From e5950c68cd6b799b46882561e771c000bacb7289 Mon Sep 17 00:00:00 2001 From: q-logic <52290913+q-logic@users.noreply.github.com> Date: Thu, 14 Jan 2021 18:42:18 +0300 Subject: [PATCH 001/582] Initial commit --- packages/sqlalchemy-spanner/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/sqlalchemy-spanner/README.md diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md new file mode 100644 index 000000000000..df1bc9b6a6dc --- /dev/null +++ b/packages/sqlalchemy-spanner/README.md @@ -0,0 +1 @@ +# python-sqlalchemy-spanner \ No newline at end of file From aa77e631471f0e1a64492dc019ecd0df2e0f9b3c Mon Sep 17 00:00:00 2001 From: Aleksandra Bogoslavetc Date: Thu, 14 Jan 2021 21:56:11 +0300 Subject: [PATCH 002/582] initial folders and files --- packages/sqlalchemy-spanner/.gitignore | 1 + .../sqlalchemy-spanner/code-of-conduct.md | 63 +++++++++++++++++++ packages/sqlalchemy-spanner/noxfile.py | 0 .../sqlalchemy-spanner/pyspanner/__init__.py | 0 .../pyspanner/sqlalchemy_spanner.py | 0 packages/sqlalchemy-spanner/setup.py | 22 +++++++ 6 files changed, 86 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.gitignore create mode 100644 packages/sqlalchemy-spanner/code-of-conduct.md create mode 100644 packages/sqlalchemy-spanner/noxfile.py create mode 100644 packages/sqlalchemy-spanner/pyspanner/__init__.py create mode 100644 packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py create mode 100644 packages/sqlalchemy-spanner/setup.py diff --git a/packages/sqlalchemy-spanner/.gitignore b/packages/sqlalchemy-spanner/.gitignore new file mode 100644 index 000000000000..600d2d33badf --- /dev/null +++ b/packages/sqlalchemy-spanner/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/code-of-conduct.md b/packages/sqlalchemy-spanner/code-of-conduct.md new file mode 100644 index 000000000000..f8b12cb550a3 --- /dev/null +++ b/packages/sqlalchemy-spanner/code-of-conduct.md @@ -0,0 +1,63 @@ +# Google Open Source Community Guidelines + +At Google, we recognize and celebrate the creativity and collaboration of open +source contributors and the diversity of skills, experiences, cultures, and +opinions they bring to the projects and communities they participate in. + +Every one of Google's open source projects and communities are inclusive +environments, based on treating all individuals respectfully, regardless of +gender identity and expression, sexual orientation, disabilities, +neurodiversity, physical appearance, body size, ethnicity, nationality, race, +age, religion, or similar personal characteristic. + +We value diverse opinions, but we value respectful behavior more. + +Respectful behavior includes: + +* Being considerate, kind, constructive, and helpful. +* Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or + physically threatening behavior, speech, and imagery. +* Not engaging in unwanted physical contact. + +Some Google open source projects [may adopt][] an explicit project code of +conduct, which may have additional detailed expectations for participants. Most +of those projects will use our [modified Contributor Covenant][]. + +[may adopt]: https://opensource.google/docs/releasing/preparing/#conduct +[modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ + +## Resolve peacefully + +We do not believe that all conflict is necessarily bad; healthy debate and +disagreement often yields positive results. However, it is never okay to be +disrespectful. + +If you see someone behaving disrespectfully, you are encouraged to address the +behavior directly with those involved. Many issues can be resolved quickly and +easily, and this gives people more control over the outcome of their dispute. +If you are unable to resolve the matter for any reason, or if the behavior is +threatening or harassing, report it. We are dedicated to providing an +environment where participants feel welcome and safe. + +## Reporting problems + +Some Google open source projects may adopt a project-specific code of conduct. +In those cases, a Google employee will be identified as the Project Steward, +who will receive and handle reports of code of conduct violations. In the event +that a project hasn’t identified a Project Steward, you can report problems by +emailing opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is +taken. The identity of the reporter will be omitted from the details of the +report supplied to the accused. In potentially harmful situations, such as +ongoing harassment or threats to anyone's safety, we may take action without +notice. + +*This document was adapted from the [IndieWeb Code of Conduct][] and can also +be found at .* + +[IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/pyspanner/__init__.py b/packages/sqlalchemy-spanner/pyspanner/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py new file mode 100644 index 000000000000..bd47cc96c6b9 --- /dev/null +++ b/packages/sqlalchemy-spanner/setup.py @@ -0,0 +1,22 @@ +from setuptools import setup + +setup( + name="sqlalchemy-spanner", + version='0.1', + description="SQLAlchemy dialect integrated into Spanner database", + author='Google LLC', + author_email='cloud-spanner-developers@googlegroups.com', + packages=['spanner'], + classifiers=[ + "Intended Audience :: Developers", + ], + install_requires=[ + 'sqlalchemy>=1.1.13', + 'google-cloud==0.25.0' + ], + entry_points={ + 'sqlalchemy.dialects': [ + 'spanner = spanner.sqlalchemy_spanner:SpannerDialect' + ] + } +) From 88102729a98111e2059aec81a8594757fc8c3737 Mon Sep 17 00:00:00 2001 From: Aleksandra Bogoslavetc Date: Fri, 15 Jan 2021 15:04:15 +0300 Subject: [PATCH 003/582] new license, update version --- packages/sqlalchemy-spanner/LICENSE | 201 ++++++++++++++++++ packages/sqlalchemy-spanner/noxfile.py | 13 ++ .../sqlalchemy-spanner/pyspanner/__init__.py | 0 .../pyspanner/sqlalchemy_spanner.py | 0 packages/sqlalchemy-spanner/setup.py | 4 +- .../sqlalchemy-spanner/spanner/__init__.py | 13 ++ .../spanner/sqlalchemy_spanner.py | 13 ++ 7 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 packages/sqlalchemy-spanner/LICENSE delete mode 100644 packages/sqlalchemy-spanner/pyspanner/__init__.py delete mode 100644 packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py create mode 100644 packages/sqlalchemy-spanner/spanner/__init__.py create mode 100644 packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py diff --git a/packages/sqlalchemy-spanner/LICENSE b/packages/sqlalchemy-spanner/LICENSE new file mode 100644 index 000000000000..08eea89fa5ef --- /dev/null +++ b/packages/sqlalchemy-spanner/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index e69de29bb2d1..ec072f2e6d6a 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/packages/sqlalchemy-spanner/pyspanner/__init__.py b/packages/sqlalchemy-spanner/pyspanner/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/pyspanner/sqlalchemy_spanner.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index bd47cc96c6b9..6aba3ad66b05 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -4,7 +4,7 @@ name="sqlalchemy-spanner", version='0.1', description="SQLAlchemy dialect integrated into Spanner database", - author='Google LLC', + author='QLogic LLC', author_email='cloud-spanner-developers@googlegroups.com', packages=['spanner'], classifiers=[ @@ -12,7 +12,7 @@ ], install_requires=[ 'sqlalchemy>=1.1.13', - 'google-cloud==0.25.0' + 'google-cloud-spanner==3.0.0' ], entry_points={ 'sqlalchemy.dialects': [ diff --git a/packages/sqlalchemy-spanner/spanner/__init__.py b/packages/sqlalchemy-spanner/spanner/__init__.py new file mode 100644 index 000000000000..ec072f2e6d6a --- /dev/null +++ b/packages/sqlalchemy-spanner/spanner/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py new file mode 100644 index 000000000000..ec072f2e6d6a --- /dev/null +++ b/packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. From a313cd783b861cc48ac92858a7a1c8d3fec0001f Mon Sep 17 00:00:00 2001 From: Aleksandra Bogoslavetc Date: Fri, 15 Jan 2021 15:13:51 +0300 Subject: [PATCH 004/582] setup.py license --- packages/sqlalchemy-spanner/setup.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 6aba3ad66b05..9ed02fe1fde4 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -1,3 +1,17 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from setuptools import setup setup( From d37d9aab303a8ea104577012bc8a3bb983d4be18 Mon Sep 17 00:00:00 2001 From: Aleksandra Bogoslavetc Date: Mon, 18 Jan 2021 13:15:45 +0300 Subject: [PATCH 005/582] rename files to be consistent with other cloud libs --- .../{spanner => google/cloud/spanner_sqlalchemy}/__init__.py | 0 .../cloud/spanner_sqlalchemy/spanner_sqlalchemy.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/sqlalchemy-spanner/{spanner => google/cloud/spanner_sqlalchemy}/__init__.py (100%) rename packages/sqlalchemy-spanner/{spanner/sqlalchemy_spanner.py => google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py} (100%) diff --git a/packages/sqlalchemy-spanner/spanner/__init__.py b/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/__init__.py similarity index 100% rename from packages/sqlalchemy-spanner/spanner/__init__.py rename to packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/__init__.py diff --git a/packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py similarity index 100% rename from packages/sqlalchemy-spanner/spanner/sqlalchemy_spanner.py rename to packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py From 5cf9065e00ef7da7cdb6214a452965af593c512f Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 28 Jan 2021 11:30:32 +0300 Subject: [PATCH 006/582] feat(sqlalchemy): implement dialect's minimal functionality (#2) --- packages/sqlalchemy-spanner/.gitignore | 61 ++++- packages/sqlalchemy-spanner/README.md | 16 +- .../spanner_sqlalchemy/spanner_sqlalchemy.py | 13 - .../__init__.py | 4 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 240 ++++++++++++++++++ packages/sqlalchemy-spanner/noxfile.py | 53 +++- packages/sqlalchemy-spanner/setup.py | 28 +- 7 files changed, 383 insertions(+), 32 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py rename packages/sqlalchemy-spanner/google/cloud/{spanner_sqlalchemy => sqlalchemy_spanner}/__init__.py (88%) create mode 100644 packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py diff --git a/packages/sqlalchemy-spanner/.gitignore b/packages/sqlalchemy-spanner/.gitignore index 600d2d33badf..ff157fe97a8b 100644 --- a/packages/sqlalchemy-spanner/.gitignore +++ b/packages/sqlalchemy-spanner/.gitignore @@ -1 +1,60 @@ -.vscode \ No newline at end of file +*.py[cod] +*.sw[op] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +dist +build +eggs +.eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +__pycache__ + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.nox +.cache +.pytest_cache + + +# Mac +.DS_Store + +# JetBrains +.idea + +# VS Code +.vscode + +# emacs +*~ + +# Built documentation +docs/_build +docs.metadata + +# Virtual environment +env/ +coverage.xml +sponge_log.xml + +# System test environment variables. +system_tests/local_test_setup + +# Make sure a generated file isn't accidentally committed. +pylintrc +pylintrc.test \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index df1bc9b6a6dc..9d82e9cd1e2e 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -1 +1,15 @@ -# python-sqlalchemy-spanner \ No newline at end of file +# python-sqlalchemy-spanner + +Usage example: + +```python +from sqlalchemy import create_engine, select, MetaData, Table + +engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" +) + +table = Table("table-id", MetaData(bind=engine), autoload=True) +for row in select(["*"], from_obj=table).execute().fetchall(): + print(row) +``` \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py b/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py deleted file mode 100644 index ec072f2e6d6a..000000000000 --- a/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/spanner_sqlalchemy.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/__init__.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py similarity index 88% rename from packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/__init__.py rename to packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py index ec072f2e6d6a..58c4b68b4953 100644 --- a/packages/sqlalchemy-spanner/google/cloud/spanner_sqlalchemy/__init__.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py @@ -11,3 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +from sqlalchemy_spanner import SpannerDialect + +__all__ = (SpannerDialect,) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py new file mode 100644 index 000000000000..1172ea96c178 --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -0,0 +1,240 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +from sqlalchemy import types +from sqlalchemy.engine.default import DefaultDialect +from google.cloud import spanner_dbapi + +# Spanner-to-SQLAlchemy types map +_type_map = { + "BOOL": types.Boolean, + "BYTES": types.BINARY, + "DATE": types.DATE, + "DATETIME": types.DATETIME, + "FLOAT": types.Float, + "INT64": types.BIGINT, + "INTEGER": types.Integer, + "NUMERIC": types.DECIMAL, + "STRING": types.String, + "TIME": types.TIME, + "TIMESTAMP": types.TIMESTAMP, +} + + +class SpannerDialect(DefaultDialect): + """Cloud Spanner dialect. + + Represents an API layer to control Cloud Spanner database with SQLAlchemy API. + """ + + name = "spanner" + driver = "spanner" + positional = False + paramstyle = "format" + encoding = "utf-8" + + execute_sequence_format = list + + supports_alter = True + supports_sane_rowcount = True + supports_sane_multi_rowcount = False + supports_default_values = False + supports_sequences = True + supports_native_enum = True + supports_native_boolean = True + + @classmethod + def dbapi(cls): + """A pointer to the Cloud Spanner DB API package. + + Used to initiate connections to the Cloud Spanner databases. + """ + return spanner_dbapi + + def _check_unicode_returns(self, connection, additional_tests=None): + """Ensure requests are returning Unicode responses.""" + return True + + def create_connect_args(self, url): + """Parse connection args from the given URL. + + The method prepares args suitable to send to the DB API `connect()` function. + + The given URL follows the style: + `spanner:///projects/{project-id}/instances/{instance-id}/databases/{database-id}` + """ + match = re.match( + ( + r"^projects/(?P.+?)/instances/" + "(?P.+?)/databases/(?P.+?)$" + ), + url.database, + ) + return ( + [match.group("instance"), match.group("database"), match.group("project")], + {}, + ) + + def get_columns(self, connection, table_name, schema=None, **kw): + """Get the table columns description. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + list: The table every column dict-like description. + """ + sql = """ +SELECT COLUMN_NAME, SPANNER_TYPE, IS_NULLABLE +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_NAME="{table_name}" +""".format( + table_name=table_name + ) + + with connection.connection.database.snapshot() as snap: + columns = snap.execute_sql(sql) + + cols_desc = [] + for col in columns: + type_ = "STRING" if col[1].startswith("STRING") else col[1] + + cols_desc.append( + { + "name": col[0], + "type": _type_map[type_], + "nullable": col[2], + "default": None, + } + ) + return cols_desc + + def get_indexes(self, connection, table_name, schema=None, **kw): + """Get the table indexes. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + list: List with indexes description. + """ + sql = """ +SELECT i.INDEX_NAME, ic.COLUMN_NAME, i.IS_UNIQUE, ic.COLUMN_ORDERING +FROM INFORMATION_SCHEMA.INDEXES as i +JOIN INFORMATION_SCHEMA.INDEX_COLUMNS AS ic + ON ic.INDEX_NAME = i.INDEX_NAME AND ic.TABLE_NAME = i.TABLE_NAME +WHERE i.TABLE_NAME="{table_name}" +""".format( + table_name=table_name + ) + + with connection.connection.database.snapshot() as snap: + inds = snap.execute_sql(sql) + + ind_descs = [] + for ind in inds: + ind_descs.append( + { + "name": ind[0], + "column_names": [ind[1]], + "unique": ind[2], + "column_sorting": {ind[0]: ind[3]}, + } + ) + return ind_descs + + def get_pk_constraint(self, connection, table_name, schema=None, **kw): + """Get the table primary key constraint. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + dict: Dict with the primary key constraint description. + """ + sql = """ +SELECT ccu.COLUMN_NAME +FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc +JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu + ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME +WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "PRIMARY KEY" +""".format( + table_name=table_name + ) + + with connection.connection.database.snapshot() as snap: + pks = snap.execute_sql(sql) + + cols = [] + for key in pks: + cols.append(key[0]) + + return {"constrained_columns": cols} + + def get_foreign_keys(self, connection, table_name, schema=None, **kw): + """Get the table foreign key constraints. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + list: Dicts, each of which describes a foreign key constraint. + """ + sql = """ +SELECT ccu.COLUMN_NAME, ccu.TABLE_SCHEMA, ccu.TABLE_NAME, ccu.CONSTRAINT_NAME +FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc +JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu + ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME +WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "FOREIGN KEY" +""".format( + table_name=table_name + ) + + with connection.connection.database.snapshot() as snap: + fks = snap.execute_sql(sql) + + keys = [] + for key in fks: + keys.append( + { + "constrained_columns": [key[0]], + "referred_schema": key[1], + "referred_table": key[2], + "referred_columns": [key[0]], + "name": key[3], + } + ) + return keys diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index ec072f2e6d6a..1d722589446c 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -1,13 +1,64 @@ +# -*- coding: utf-8 -*- +# # Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import absolute_import + +import nox + + +BLACK_VERSION = "black==19.10b0" +BLACK_PATHS = ["google", "tests", "noxfile.py", "setup.py"] + +DEFAULT_PYTHON_VERSION = "3.7" + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def lint(session): + """Run linters. + + Returns a failure if the linters find linting errors or sufficiently + serious code quality issues. + """ + session.install("flake8", BLACK_VERSION) + session.run( + "black", "--check", *BLACK_PATHS, + ) + session.run( + "flake8", "google", "tests", "--max-line-length=88", + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def blacken(session): + """Run black. + + Format code to uniform standard. + + This currently uses Python 3.6 due to the automated Kokoro run of synthtool. + That run uses an image that doesn't have 3.6 installed. Before updating this + check the state of the `gcp_ubuntu_config` we use for that Kokoro run. + """ + session.install(BLACK_VERSION) + session.run( + "black", *BLACK_PATHS, + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def lint_setup_py(session): + """Verify that setup.py is valid (including RST check).""" + session.install("docutils", "pygments") + session.run("python", "setup.py", "check", "--restructuredtext", "--strict") diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 9ed02fe1fde4..0b23a462f4bd 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -15,22 +15,18 @@ from setuptools import setup setup( - name="sqlalchemy-spanner", - version='0.1', - description="SQLAlchemy dialect integrated into Spanner database", - author='QLogic LLC', - author_email='cloud-spanner-developers@googlegroups.com', - packages=['spanner'], - classifiers=[ - "Intended Audience :: Developers", - ], - install_requires=[ - 'sqlalchemy>=1.1.13', - 'google-cloud-spanner==3.0.0' - ], + author="QLogic LLC", + author_email="cloud-spanner-developers@googlegroups.com", + classifiers=["Intended Audience :: Developers"], + description="SQLAlchemy dialect integrated into Cloud Spanner database", entry_points={ - 'sqlalchemy.dialects': [ - 'spanner = spanner.sqlalchemy_spanner:SpannerDialect' + "sqlalchemy.dialects": [ + "spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" ] - } + }, + install_requires=["sqlalchemy>=1.1.13", "google-cloud-spanner>=3.0.0"], + name="sqlalchemy-spanner", + packages=["google.cloud.sqlalchemy_spanner"], + url="https://github.com/q-logic/python-sqlalchemy-spanner/", + version="0.1", ) From 6b7057a0e5fd670a6bcd9b7c2dbd92692bad6376 Mon Sep 17 00:00:00 2001 From: IlyaFaer Date: Mon, 1 Feb 2021 10:33:09 +0300 Subject: [PATCH 007/582] fix: import error --- .../google/cloud/sqlalchemy_spanner/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py index 58c4b68b4953..d231f1e86439 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy_spanner import SpannerDialect +from .sqlalchemy_spanner import SpannerDialect __all__ = (SpannerDialect,) From 7bfbd604f33200856d0e03a85658ecc88165ecb7 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 16 Feb 2021 10:21:52 +0300 Subject: [PATCH 008/582] test: prepare the package for SQLAlchemy dialect compliance testing (#1) --- .../cloud/sqlalchemy_spanner/__init__.py | 2 +- .../cloud/sqlalchemy_spanner/requirements.py | 20 +++++++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- packages/sqlalchemy-spanner/noxfile.py | 12 ++++++-- packages/sqlalchemy-spanner/setup.cfg | 29 +++++++++++++++++++ packages/sqlalchemy-spanner/setup.py | 2 +- packages/sqlalchemy-spanner/test/conftest.py | 24 +++++++++++++++ .../sqlalchemy-spanner/test/test_suite.py | 17 +++++++++++ 8 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py create mode 100644 packages/sqlalchemy-spanner/setup.cfg create mode 100644 packages/sqlalchemy-spanner/test/conftest.py create mode 100644 packages/sqlalchemy-spanner/test/test_suite.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py index d231f1e86439..6cfd02bb7288 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py new file mode 100644 index 000000000000..1a8d3145784e --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -0,0 +1,20 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy.testing.requirements import SuiteRequirements + + +class Requirements(SuiteRequirements): + + pass diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 1172ea96c178..15b400865a86 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 1d722589446c..902fa813a710 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright 2018 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ BLACK_VERSION = "black==19.10b0" -BLACK_PATHS = ["google", "tests", "noxfile.py", "setup.py"] +BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py"] DEFAULT_PYTHON_VERSION = "3.7" @@ -37,7 +37,7 @@ def lint(session): "black", "--check", *BLACK_PATHS, ) session.run( - "flake8", "google", "tests", "--max-line-length=88", + "flake8", "google", "test", "--max-line-length=88", ) @@ -62,3 +62,9 @@ def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" session.install("docutils", "pygments") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def compliance_test(session): + """Run SQLAlchemy dialect compliance test suite.""" + session.run("pytest", "-v") diff --git a/packages/sqlalchemy-spanner/setup.cfg b/packages/sqlalchemy-spanner/setup.cfg new file mode 100644 index 000000000000..7050a471883c --- /dev/null +++ b/packages/sqlalchemy-spanner/setup.cfg @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[egg_info] +tag_build = dev + +[tool:pytest] +addopts= --tb native -v -r fxX --maxfail=25 -p no:warnings +python_files=test/*test_*.py + +[sqla_testing] +requirement_cls=google.cloud.sqlalchemy_spanner.requirements:Requirements +profile_file=test/profiles.txt + +[db] +default=spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 0b23a462f4bd..cc28cf57d86f 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -1,4 +1,4 @@ -# Copyright 2018 Google LLC +# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/packages/sqlalchemy-spanner/test/conftest.py b/packages/sqlalchemy-spanner/test/conftest.py new file mode 100644 index 000000000000..35767cf2c673 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/conftest.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from sqlalchemy.dialects import registry + +registry.register("spanner", "google.cloud.sqlalchemy_spanner", "SpannerDialect") + +pytest.register_assert_rewrite("sqlalchemy.testing.assertions") + +from sqlalchemy.testing.plugin.pytestplugin import * # noqa: E402, F401, F403 diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py new file mode 100644 index 000000000000..9551e4fcadc9 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy.testing.suite import * # noqa: F401, F403 From 56dbb2c0c5495c503b8515e3761e6f8cd13df245 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 16 Feb 2021 14:28:25 -0500 Subject: [PATCH 009/582] refactor: refactor setup file (#3) --- .../sqlalchemy-spanner/google/__init__.py | 22 ++++++++++ .../google/cloud/__init__.py | 22 ++++++++++ packages/sqlalchemy-spanner/setup.py | 42 +++++++++++++++---- 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 packages/sqlalchemy-spanner/google/__init__.py create mode 100644 packages/sqlalchemy-spanner/google/cloud/__init__.py diff --git a/packages/sqlalchemy-spanner/google/__init__.py b/packages/sqlalchemy-spanner/google/__init__.py new file mode 100644 index 000000000000..0f7918773786 --- /dev/null +++ b/packages/sqlalchemy-spanner/google/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/google/cloud/__init__.py b/packages/sqlalchemy-spanner/google/cloud/__init__.py new file mode 100644 index 000000000000..0f7918773786 --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index cc28cf57d86f..ce73e8c82ec0 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -12,21 +12,47 @@ # See the License for the specific language governing permissions and # limitations under the License. -from setuptools import setup +import setuptools -setup( - author="QLogic LLC", + +# Package metadata. + +name = "sqlalchemy-spanner" +description = "SQLAlchemy dialect integrated into Cloud Spanner database" +dependencies = [ + "sqlalchemy>=1.1.13", + "google-cloud-spanner>=3.0.0" +] + +# Only include packages under the 'google' namespace. Do not include tests, +# benchmarks, etc. +packages = [ + package + for package in setuptools.PEP420PackageFinder.find() + if package.startswith("google") +] + +# Determine which namespaces are needed. +namespaces = ["google"] +if "google.cloud" in packages: + namespaces.append("google.cloud") + +setuptools.setup( + author="Google LLC", author_email="cloud-spanner-developers@googlegroups.com", classifiers=["Intended Audience :: Developers"], - description="SQLAlchemy dialect integrated into Cloud Spanner database", + description=description, entry_points={ "sqlalchemy.dialects": [ "spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" ] }, - install_requires=["sqlalchemy>=1.1.13", "google-cloud-spanner>=3.0.0"], - name="sqlalchemy-spanner", - packages=["google.cloud.sqlalchemy_spanner"], - url="https://github.com/q-logic/python-sqlalchemy-spanner/", + install_requires=dependencies, + name=name, + namespace_packages=namespaces, + packages=packages, + url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", version="0.1", + include_package_data=True, + zip_safe=False, ) From f14221f8af1145bb3eb5bcbddd596ba77c9e4043 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 16 Feb 2021 14:29:00 -0500 Subject: [PATCH 010/582] fix: install pytest and library to run tests (#5) --- packages/sqlalchemy-spanner/noxfile.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 902fa813a710..c4976097e5dc 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -67,4 +67,6 @@ def lint_setup_py(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def compliance_test(session): """Run SQLAlchemy dialect compliance test suite.""" + session.install("pytest") + session.install(".") session.run("pytest", "-v") From 6b6e039cda4e4ad55a632d1cfcd3fd4fa4d26d27 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 18 Feb 2021 14:38:47 +0300 Subject: [PATCH 011/582] feat: add types compiler and introspection methods (#2) --- .../cloud/sqlalchemy_spanner/provision.py | 20 ++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 287 ++++++++++++++---- 2 files changed, 254 insertions(+), 53 deletions(-) create mode 100644 packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py new file mode 100644 index 000000000000..91ff8e924bf2 --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py @@ -0,0 +1,20 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy.testing.provision import temp_table_keyword_args + + +@temp_table_keyword_args.for_db("spanner") +def _spanner_temp_table_keyword_args(cfg, eng): + return {} diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 15b400865a86..800768b6913e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -16,6 +16,7 @@ from sqlalchemy import types from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.sql.compiler import GenericTypeCompiler from google.cloud import spanner_dbapi # Spanner-to-SQLAlchemy types map @@ -34,6 +35,40 @@ } +class SpannerTypeCompiler(GenericTypeCompiler): + """Spanner types compiler. + + Maps SQLAlchemy types to Spanner data types. + """ + + def visit_INTEGER(self, type_, **kw): + return "INT64" + + def visit_FLOAT(self, type_, **kw): + return "FLOAT64" + + def visit_TEXT(self, type_, **kw): + return "STRING({})".format(type_.length) + + def visit_ARRAY(self, type_, **kw): + return "ARRAY<{}>".format(self.process(type_.item_type, **kw)) + + def visit_BINARY(self, type_, **kw): + return "BYTES" + + def visit_DECIMAL(self, type_, **kw): + return "NUMERIC" + + def visit_VARCHAR(self, type_, **kw): + return "STRING({})".format(type_.length) + + def visit_CHAR(self, type_, **kw): + return "STRING({})".format(type_.length) + + def visit_BOOLEAN(self, type_, **kw): + return "BOOL" + + class SpannerDialect(DefaultDialect): """Cloud Spanner dialect. @@ -56,6 +91,8 @@ class SpannerDialect(DefaultDialect): supports_native_enum = True supports_native_boolean = True + type_compiler = SpannerTypeCompiler + @classmethod def dbapi(cls): """A pointer to the Cloud Spanner DB API package. @@ -94,37 +131,51 @@ def get_columns(self, connection, table_name, schema=None, **kw): The method is used by SQLAlchemy introspection systems. Args: - connection (sqlalchemy.engine.base.Connection): - SQLAlchemy connection object. + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name Returns: list: The table every column dict-like description. """ + if isinstance(connection, Engine): + connection = connection.connect() + sql = """ -SELECT COLUMN_NAME, SPANNER_TYPE, IS_NULLABLE -FROM INFORMATION_SCHEMA.COLUMNS -WHERE TABLE_NAME="{table_name}" +SELECT column_name, spanner_type, is_nullable +FROM information_schema.columns +WHERE + table_catalog = '' + AND table_schema = '' + AND table_name = '{}' +ORDER BY + table_catalog, + table_schema, + table_name, + ordinal_position """.format( - table_name=table_name + table_name ) + cols_desc = [] with connection.connection.database.snapshot() as snap: columns = snap.execute_sql(sql) - cols_desc = [] - for col in columns: - type_ = "STRING" if col[1].startswith("STRING") else col[1] - - cols_desc.append( - { - "name": col[0], - "type": _type_map[type_], - "nullable": col[2], - "default": None, - } - ) + for col in columns: + type_ = "STRING" if col[1].startswith("STRING") else col[1] + + cols_desc.append( + { + "name": col[0], + "type": _type_map[type_], + "nullable": col[2] == "YES", + "default": None, + } + ) return cols_desc def get_indexes(self, connection, table_name, schema=None, **kw): @@ -133,14 +184,20 @@ def get_indexes(self, connection, table_name, schema=None, **kw): The method is used by SQLAlchemy introspection systems. Args: - connection (sqlalchemy.engine.base.Connection): - SQLAlchemy connection object. + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name Returns: list: List with indexes description. """ + if isinstance(connection, Engine): + connection = connection.connect() + sql = """ SELECT i.INDEX_NAME, ic.COLUMN_NAME, i.IS_UNIQUE, ic.COLUMN_ORDERING FROM INFORMATION_SCHEMA.INDEXES as i @@ -151,20 +208,20 @@ def get_indexes(self, connection, table_name, schema=None, **kw): table_name=table_name ) + ind_desc = [] with connection.connection.database.snapshot() as snap: - inds = snap.execute_sql(sql) - - ind_descs = [] - for ind in inds: - ind_descs.append( - { - "name": ind[0], - "column_names": [ind[1]], - "unique": ind[2], - "column_sorting": {ind[0]: ind[3]}, - } - ) - return ind_descs + rows = snap.execute_sql(sql) + + for row in rows: + ind_desc.append( + { + "name": row[0], + "column_names": [row[1]], + "unique": row[2], + "column_sorting": {row[0]: row[3]}, + } + ) + return ind_desc def get_pk_constraint(self, connection, table_name, schema=None, **kw): """Get the table primary key constraint. @@ -172,14 +229,20 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): The method is used by SQLAlchemy introspection systems. Args: - connection (sqlalchemy.engine.base.Connection): - SQLAlchemy connection object. + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name Returns: dict: Dict with the primary key constraint description. """ + if isinstance(connection, Engine): + connection = connection.connect() + sql = """ SELECT ccu.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc @@ -190,12 +253,12 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): table_name=table_name ) + cols = [] with connection.connection.database.snapshot() as snap: - pks = snap.execute_sql(sql) + rows = snap.execute_sql(sql) - cols = [] - for key in pks: - cols.append(key[0]) + for row in rows: + cols.append(row[0]) return {"constrained_columns": cols} @@ -205,14 +268,20 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): The method is used by SQLAlchemy introspection systems. Args: - connection (sqlalchemy.engine.base.Connection): - SQLAlchemy connection object. + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name Returns: list: Dicts, each of which describes a foreign key constraint. """ + if isinstance(connection, Engine): + connection = connection.connect() + sql = """ SELECT ccu.COLUMN_NAME, ccu.TABLE_SCHEMA, ccu.TABLE_NAME, ccu.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc @@ -223,18 +292,130 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): table_name=table_name ) + keys = [] with connection.connection.database.snapshot() as snap: - fks = snap.execute_sql(sql) + rows = snap.execute_sql(sql) + + for row in rows: + keys.append( + { + "constrained_columns": [row[0]], + "referred_schema": row[1], + "referred_table": row[2], + "referred_columns": [row[0]], + "name": row[3], + } + ) + return keys - keys = [] - for key in fks: - keys.append( - { - "constrained_columns": [key[0]], - "referred_schema": key[1], - "referred_table": key[2], - "referred_columns": [key[0]], - "name": key[3], - } + def get_table_names(self, connection, schema=None, **kw): + """Get all the tables from the given schema. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name. + + Returns: + list: Names of the tables within the given schema. + """ + if isinstance(connection, Engine): + connection = connection.connect() + + sql = """ +SELECT table_name +FROM information_schema.tables +WHERE table_schema = '{}' +""".format( + schema + ) + + table_names = [] + with connection.connection.database.snapshot() as snap: + rows = snap.execute_sql(sql) + + for row in rows: + table_names.append(row[0]) + + return table_names + + def get_unique_constraints(self, connection, table_name, schema=None, **kw): + """Get the table unique constraints. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + dict: Dict with the unique constraints' descriptions. + """ + if isinstance(connection, Engine): + connection = connection.connect() + + sql = """ +SELECT ccu.CONSTRAINT_NAME, ccu.COLUMN_NAME +FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc +JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu + ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME +WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "UNIQUE" +""".format( + table_name=table_name + ) + + cols = [] + with connection.connection.database.snapshot() as snap: + rows = snap.execute_sql(sql) + + for row in rows: + cols.append({"name": row[0], "column_names": [row[1]]}) + + return cols + + def has_table(self, connection, table_name, schema=None): + """Check if the given table exists. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name. + + Returns: + bool: True, if the given table exists, False otherwise. + """ + if isinstance(connection, Engine): + connection = connection.connect() + + with connection.connection.database.snapshot() as snap: + rows = snap.execute_sql( + """ +SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_NAME="{table_name}" +LIMIT 1 +""".format( + table_name=table_name + ) ) - return keys + + for _ in rows: + return True + + return False From 569ed08b6d854a2f70769fdd5926090fe904f3ca Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 18 Feb 2021 18:20:51 +0300 Subject: [PATCH 012/582] feat: improve indexes reflection (#7) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 800768b6913e..255b1b25cbd8 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -199,11 +199,16 @@ def get_indexes(self, connection, table_name, schema=None, **kw): connection = connection.connect() sql = """ -SELECT i.INDEX_NAME, ic.COLUMN_NAME, i.IS_UNIQUE, ic.COLUMN_ORDERING -FROM INFORMATION_SCHEMA.INDEXES as i -JOIN INFORMATION_SCHEMA.INDEX_COLUMNS AS ic - ON ic.INDEX_NAME = i.INDEX_NAME AND ic.TABLE_NAME = i.TABLE_NAME -WHERE i.TABLE_NAME="{table_name}" +SELECT + i.index_name, + ARRAY_AGG(ic.column_name), + i.is_unique, + ARRAY_AGG(ic.column_ordering) +FROM information_schema.indexes as i +JOIN information_schema.index_columns AS ic + ON ic.index_name = i.index_name AND ic.table_name = i.table_name +WHERE i.table_name="{table_name}" +GROUP BY i.index_name, i.is_unique """.format( table_name=table_name ) @@ -216,9 +221,11 @@ def get_indexes(self, connection, table_name, schema=None, **kw): ind_desc.append( { "name": row[0], - "column_names": [row[1]], + "column_names": row[1], "unique": row[2], - "column_sorting": {row[0]: row[3]}, + "column_sorting": { + col: order for col, order in zip(row[1], row[3]) + }, } ) return ind_desc From ffefc855fac2dba69e163c145d39b071e6a39f74 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 22 Feb 2021 12:33:44 +0300 Subject: [PATCH 013/582] feat: override primary key definition mechanism (#4) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 255b1b25cbd8..b47d3e17ea91 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -15,19 +15,19 @@ import re from sqlalchemy import types +from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect -from sqlalchemy.sql.compiler import GenericTypeCompiler +from sqlalchemy.sql.compiler import DDLCompiler, GenericTypeCompiler from google.cloud import spanner_dbapi # Spanner-to-SQLAlchemy types map _type_map = { "BOOL": types.Boolean, - "BYTES": types.BINARY, + "BYTES(MAX)": types.BINARY, "DATE": types.DATE, "DATETIME": types.DATETIME, - "FLOAT": types.Float, + "FLOAT64": types.Float, "INT64": types.BIGINT, - "INTEGER": types.Integer, "NUMERIC": types.DECIMAL, "STRING": types.String, "TIME": types.TIME, @@ -35,6 +35,34 @@ } +class SpannerDDLCompiler(DDLCompiler): + """Spanner DDL statements compiler.""" + + def visit_primary_key_constraint(self, constraint): + """Build primary key definition. + + Primary key in Spanner is defined outside of a table columns definition, see: + https://cloud.google.com/spanner/docs/getting-started/python#create_a_database + + The method returns None to omit primary key in a table columns definition. + """ + return None + + def post_create_table(self, table): + """Build statements to be executed after CREATE TABLE. + + Args: + table (sqlalchemy.schema.Table): Table to create. + + Returns: + str: primary key difinition to add to the table CREATE request. + """ + cols = [col.name for col in table.primary_key.columns] + + return " PRIMARY KEY ({})".format(", ".join(cols)) + + + class SpannerTypeCompiler(GenericTypeCompiler): """Spanner types compiler. @@ -68,6 +96,9 @@ def visit_CHAR(self, type_, **kw): def visit_BOOLEAN(self, type_, **kw): return "BOOL" + def visit_DATETIME(self, type_, **kw): + return "TIMESTAMP" + class SpannerDialect(DefaultDialect): """Cloud Spanner dialect. @@ -91,6 +122,7 @@ class SpannerDialect(DefaultDialect): supports_native_enum = True supports_native_boolean = True + ddl_compiler = SpannerDDLCompiler type_compiler = SpannerTypeCompiler @classmethod From 98074b614b487be930dcc21146416bfa9a7357f1 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 24 Feb 2021 19:46:09 +0300 Subject: [PATCH 014/582] feat: support UNION/INTERSECT/EXCEPT operators (#9) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index b47d3e17ea91..53792c387d00 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -17,7 +17,12 @@ from sqlalchemy import types from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect -from sqlalchemy.sql.compiler import DDLCompiler, GenericTypeCompiler +from sqlalchemy.sql.compiler import ( + selectable, + DDLCompiler, + GenericTypeCompiler, + SQLCompiler, +) from google.cloud import spanner_dbapi # Spanner-to-SQLAlchemy types map @@ -34,6 +39,21 @@ "TIMESTAMP": types.TIMESTAMP, } +_compound_keywords = { + selectable.CompoundSelect.UNION: "UNION DISTINCT", + selectable.CompoundSelect.UNION_ALL: "UNION ALL", + selectable.CompoundSelect.EXCEPT: "EXCEPT DISTINCT", + selectable.CompoundSelect.EXCEPT_ALL: "EXCEPT ALL", + selectable.CompoundSelect.INTERSECT: "INTERSECT DISTINCT", + selectable.CompoundSelect.INTERSECT_ALL: "INTERSECT ALL", +} + + +class SpannerSQLCompiler(SQLCompiler): + """Spanner SQL statements compiler.""" + + compound_keywords = _compound_keywords + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" @@ -62,7 +82,6 @@ def post_create_table(self, table): return " PRIMARY KEY ({})".format(", ".join(cols)) - class SpannerTypeCompiler(GenericTypeCompiler): """Spanner types compiler. @@ -123,6 +142,7 @@ class SpannerDialect(DefaultDialect): supports_native_boolean = True ddl_compiler = SpannerDDLCompiler + statement_compiler = SpannerSQLCompiler type_compiler = SpannerTypeCompiler @classmethod From 6c38a9231b19c7d0aa4a7decf7b8df6d5351dd22 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 24 Feb 2021 20:03:01 +0300 Subject: [PATCH 015/582] test: build testing workflow (#10) --- .../.github/workflows/test_suite.yml | 30 ++++++++++++++++ .../create_test_database.py | 35 +++++++++++++++++++ .../sqlalchemy-spanner/google/__init__.py | 2 +- .../google/cloud/__init__.py | 2 +- packages/sqlalchemy-spanner/noxfile.py | 9 +++-- packages/sqlalchemy-spanner/setup.py | 5 +-- .../sqlalchemy-spanner/test/test_suite.py | 2 +- 7 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 packages/sqlalchemy-spanner/.github/workflows/test_suite.yml create mode 100644 packages/sqlalchemy-spanner/create_test_database.py diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml new file mode 100644 index 000000000000..46514181a962 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -0,0 +1,30 @@ +on: + push: + branches: + - master + pull_request: +name: SQLAlchemy Spanner dialect +jobs: + tests: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run SQLAlchemy tests + run: nox + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py new file mode 100644 index 000000000000..98ad2f64f36e --- /dev/null +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud.spanner_v1 import Client + +project = os.getenv( + "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), +) + +client = Client(project=project) + +config = f"{client.project_name}/instanceConfigs/regional-us-central1" + +instance = client.instance("sqlalchemy-dialect-test", config) +created_op = instance.create() +created_op.result(120) # block until completion + +database = instance.database("compliance-test") +created_op = database.create() +created_op.result(120) diff --git a/packages/sqlalchemy-spanner/google/__init__.py b/packages/sqlalchemy-spanner/google/__init__.py index 0f7918773786..e0bdef06ac5f 100644 --- a/packages/sqlalchemy-spanner/google/__init__.py +++ b/packages/sqlalchemy-spanner/google/__init__.py @@ -19,4 +19,4 @@ except ImportError: import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/sqlalchemy-spanner/google/cloud/__init__.py b/packages/sqlalchemy-spanner/google/cloud/__init__.py index 0f7918773786..e0bdef06ac5f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/__init__.py +++ b/packages/sqlalchemy-spanner/google/cloud/__init__.py @@ -19,4 +19,4 @@ except ImportError: import pkgutil - __path__ = pkgutil.extend_path(__path__, __name__) \ No newline at end of file + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index c4976097e5dc..bb2ed3d1bd13 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -22,7 +22,7 @@ BLACK_VERSION = "black==19.10b0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py"] -DEFAULT_PYTHON_VERSION = "3.7" +DEFAULT_PYTHON_VERSION = "3.8" @nox.session(python=DEFAULT_PYTHON_VERSION) @@ -68,5 +68,10 @@ def lint_setup_py(session): def compliance_test(session): """Run SQLAlchemy dialect compliance test suite.""" session.install("pytest") - session.install(".") + session.install("sqlalchemy") + session.install( + "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" + ) + session.install("-e", ".") + session.run("python", "create_test_database.py") session.run("pytest", "-v") diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index ce73e8c82ec0..6a820d0255b8 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -19,10 +19,7 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" -dependencies = [ - "sqlalchemy>=1.1.13", - "google-cloud-spanner>=3.0.0" -] +dependencies = ["sqlalchemy>=1.1.13", "google-cloud-spanner>=3.0.0"] # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 9551e4fcadc9..13059b28c41f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,4 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy.testing.suite import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 From a9ad946137215de71cfa73496c293b32b073f644 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 1 Mar 2021 11:07:02 +0300 Subject: [PATCH 016/582] feat: improve foreign keys reflection (#6) --- .../cloud/sqlalchemy_spanner/requirements.py | 6 ++-- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 31 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 1a8d3145784e..a98d07e9373a 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -12,9 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from sqlalchemy.testing import exclusions from sqlalchemy.testing.requirements import SuiteRequirements class Requirements(SuiteRequirements): - - pass + @property + def implicitly_named_constraints(self): + return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 53792c387d00..e620f5487260 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -342,11 +342,22 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): connection = connection.connect() sql = """ -SELECT ccu.COLUMN_NAME, ccu.TABLE_SCHEMA, ccu.TABLE_NAME, ccu.CONSTRAINT_NAME -FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc -JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu - ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME -WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "FOREIGN KEY" +SELECT + tc.constraint_name, + ctu.table_name, + ctu.table_schema, + ccu.column_name, + kcu.column_name +FROM information_schema.table_constraints AS tc +JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name +JOIN information_schema.constraint_table_usage AS ctu + ON ctu.constraint_name = tc.constraint_name +JOIN information_schema.key_column_usage AS kcu + ON kcu.constraint_name = tc.constraint_name +WHERE + tc.table_name="{table_name}" + AND tc.constraint_type = "FOREIGN KEY" """.format( table_name=table_name ) @@ -358,11 +369,11 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): for row in rows: keys.append( { - "constrained_columns": [row[0]], - "referred_schema": row[1], - "referred_table": row[2], - "referred_columns": [row[0]], - "name": row[3], + "name": row[0], + "referred_table": row[1], + "referred_schema": row[2] or None, + "referred_columns": [row[3]], + "constrained_columns": [row[4]], } ) return keys From 34bb1cad699279fb9a0b95c46f8f0fa45a7aa909 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 1 Mar 2021 12:49:24 +0300 Subject: [PATCH 017/582] feat: implement dialect basic methods (#8) --- .../cloud/sqlalchemy_spanner/requirements.py | 32 +++++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 56 +++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite.py | 53 ++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index a98d07e9373a..d0a6ac1d4a9c 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -20,3 +20,35 @@ class Requirements(SuiteRequirements): @property def implicitly_named_constraints(self): return exclusions.open() + + @property + def autocommit(self): + return exclusions.open() + + @property + def order_by_collation(self): + return exclusions.open() + + @property + def ctes(self): + return exclusions.open() + + @property + def isolation_level(self): + return exclusions.open() + + def get_order_by_collation(self, _): + """Get the default collation name. + + Returns: + str: Collation name. + """ + return '"unicode"' + + def get_isolation_levels(self, _): + """Get isolation levels supported by the dialect. + + Returns: + dict: isolation levels description. + """ + return {"default": "SERIALIZABLE", "supported": ["SERIALIZABLE", "AUTOCOMMIT"]} diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e620f5487260..f41978e276bf 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -153,6 +153,20 @@ def dbapi(cls): """ return spanner_dbapi + @property + def default_isolation_level(self): + """Default isolation level name. + + Returns: + str: default isolation level. + """ + return "SERIALIZABLE" + + @default_isolation_level.setter + def default_isolation_level(self, value): + """Default isolation level should not be changed.""" + pass + def _check_unicode_returns(self, connection, additional_tests=None): """Ensure requests are returning Unicode responses.""" return True @@ -489,3 +503,45 @@ def has_table(self, connection, table_name, schema=None): return True return False + + def set_isolation_level(self, conn_proxy, level): + """Set the connection isolation level. + + Args: + conn_proxy ( + Union[ + sqlalchemy.pool._ConnectionFairy, + spanner_dbapi.connection.Connection, + ] + ): + Database connection proxy object or the connection iself. + level (string): Isolation level. + """ + if isinstance(conn_proxy, spanner_dbapi.Connection): + conn = conn_proxy + else: + conn = conn_proxy.connection + + conn.autocommit = level == "AUTOCOMMIT" + + def get_isolation_level(self, conn_proxy): + """Get the connection isolation level. + + Args: + conn_proxy ( + Union[ + sqlalchemy.pool._ConnectionFairy, + spanner_dbapi.connection.Connection, + ] + ): + Database connection proxy object or the connection iself. + + Returns: + str: the connection isolation level. + """ + if isinstance(conn_proxy, spanner_dbapi.Connection): + conn = conn_proxy + else: + conn = conn_proxy.connection + + return "AUTOCOMMIT" if conn.autocommit else "SERIALIZABLE" diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 13059b28c41f..490d2d36cb61 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,4 +14,57 @@ # See the License for the specific language governing permissions and # limitations under the License. +from sqlalchemy.testing import config +from sqlalchemy.testing import eq_ +from sqlalchemy.testing import provide_metadata +from sqlalchemy.testing.schema import Column +from sqlalchemy.testing.schema import Table +from sqlalchemy import literal_column +from sqlalchemy import select +from sqlalchemy import String + from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 + +from sqlalchemy.testing.suite.test_dialect import ( # noqa: F401, F403 + EscapingTest as _EscapingTest, +) + + +class EscapingTest(_EscapingTest): + @provide_metadata + def test_percent_sign_round_trip(self): + """Test that the DBAPI accommodates for escaped / nonescaped + percent signs in a way that matches the compiler + + SPANNER OVERRIDE + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + m = self.metadata + t = Table("t", m, Column("data", String(50))) + t.create(config.db) + with config.db.begin() as conn: + conn.execute(t.insert(), dict(data="some % value")) + + eq_( + conn.scalar( + select([t.c.data]).where( + t.c.data == literal_column("'some % value'") + ) + ), + "some % value", + ) + + conn.execute(t.delete()) + conn.execute(t.insert(), dict(data="some %% other value")) + eq_( + conn.scalar( + select([t.c.data]).where( + t.c.data == literal_column("'some %% other value'") + ) + ), + "some %% other value", + ) From 692173bcd4eb2359ece1ca82c9c313d9fb6e3993 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 3 Mar 2021 03:58:46 +0300 Subject: [PATCH 018/582] docs: add "under development" disclaimer (#12) --- packages/sqlalchemy-spanner/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 9d82e9cd1e2e..9a296baa3e8a 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -1,6 +1,8 @@ # python-sqlalchemy-spanner -Usage example: +**NOTE: This project is still in DEVELOPMENT. It may make breaking changes without prior notice and should not yet be used for production purposes.** + +**Usage example**: ```python from sqlalchemy import create_engine, select, MetaData, Table @@ -12,4 +14,4 @@ engine = create_engine( table = Table("table-id", MetaData(bind=engine), autoload=True) for row in select(["*"], from_obj=table).execute().fetchall(): print(row) -``` \ No newline at end of file +``` From 8e98af13203880ec88518dac6ad7a7e1c8e95ef6 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 3 Mar 2021 20:57:08 +1100 Subject: [PATCH 019/582] chore: setting up contributing guidelines (#14) and GitHub issue templates. --- .../.github/ISSUE_TEMPLATE.md | 16 +++++++++++ .../.github/PULL_REQUEST_TEMPLATE.md | 6 ++++ packages/sqlalchemy-spanner/contributing.md | 28 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md create mode 100644 packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 packages/sqlalchemy-spanner/contributing.md diff --git a/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md b/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000000..3c52212facc1 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,16 @@ +## Expected Behavior + + +## Actual Behavior + + +## Steps to Reproduce the Problem + +1. +1. +1. + +## Specifications + +- Version: +- Platform: \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md b/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..0787bd9431fa --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,6 @@ +Fixes # + +> It's a good idea to open an issue first for discussion. + +- [ ] Tests pass +- [ ] Appropriate changes to README are included in PR \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/contributing.md b/packages/sqlalchemy-spanner/contributing.md new file mode 100644 index 000000000000..6272489dae31 --- /dev/null +++ b/packages/sqlalchemy-spanner/contributing.md @@ -0,0 +1,28 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows [Google's Open Source Community +Guidelines](https://opensource.google/conduct/). From c0c98003b23fcda3a6ba01ec1b5a2f3c3d675a12 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 9 Mar 2021 18:27:01 +0300 Subject: [PATCH 020/582] feat: add default schema name (#15) --- .../google/cloud/sqlalchemy_spanner/requirements.py | 4 ++++ .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index d0a6ac1d4a9c..418764b49b72 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -17,6 +17,10 @@ class Requirements(SuiteRequirements): + @property + def schema_reflection(self): + return exclusions.open() + @property def implicitly_named_constraints(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index f41978e276bf..c7ff9a00f38d 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -171,6 +171,14 @@ def _check_unicode_returns(self, connection, additional_tests=None): """Ensure requests are returning Unicode responses.""" return True + def _get_default_schema_name(self, _): + """Get default Cloud Spanner schema name. + + Returns: + str: Schema name. + """ + return "" + def create_connect_args(self, url): """Parse connection args from the given URL. From fa4230925133109d422236ec20ca8b4d31bf1dcd Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 10 Mar 2021 10:35:02 +0300 Subject: [PATCH 021/582] test: skip INSERT/DELETE/UPDATE from cte tests (#11) --- .../sqlalchemy-spanner/test/test_suite.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 490d2d36cb61..bfa39ae0da50 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytest + from sqlalchemy.testing import config from sqlalchemy.testing import eq_ from sqlalchemy.testing import provide_metadata @@ -23,12 +25,14 @@ from sqlalchemy import select from sqlalchemy import String +from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import ( # noqa: F401, F403 EscapingTest as _EscapingTest, ) +from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest # noqa: F401, F403 class EscapingTest(_EscapingTest): @@ -68,3 +72,58 @@ def test_percent_sign_round_trip(self): ), "some %% other value", ) + + +class CTETest(_CTETest): + @pytest.mark.skip("INSERT from WITH subquery is not supported") + def test_insert_from_select_round_trip(self): + """ + The test checks if an INSERT can be done from a cte, like: + + WITH some_cte AS (...) + INSERT INTO some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_scalar_subq_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_from_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("UPDATE from WITH subquery is not supported") + def test_update_from_round_trip(self): + """ + The test checks if an UPDATE can be done from a cte, like: + + WITH some_cte AS (...) + UPDATE some_other_table + SET (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("WITH RECURSIVE subqueries are not supported") + def test_select_recursive_round_trip(self): + pass From ebffcb94ff5caaa4c0a03ad5aa537bd1c28d3784 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 10 Mar 2021 10:39:49 +0300 Subject: [PATCH 022/582] test: fix the boolean literal test (#16) --- packages/sqlalchemy-spanner/test/test_suite.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index bfa39ae0da50..c1d089bcec31 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -23,6 +23,7 @@ from sqlalchemy.testing.schema import Table from sqlalchemy import literal_column from sqlalchemy import select +from sqlalchemy import Boolean from sqlalchemy import String from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 @@ -33,6 +34,7 @@ EscapingTest as _EscapingTest, ) from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest # noqa: F401, F403 +from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest class EscapingTest(_EscapingTest): @@ -127,3 +129,17 @@ def test_update_from_round_trip(self): @pytest.mark.skip("WITH RECURSIVE subqueries are not supported") def test_select_recursive_round_trip(self): pass + + +class BooleanTest(_BooleanTest): + def test_render_literal_bool(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._literal_round_trip(Boolean(), [True], [True]) + self._literal_round_trip(Boolean(), [False], [False]) From b5bcdc13497c5e0702a21f4ddfc2293180c5ccdb Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 10 Mar 2021 12:25:25 +0300 Subject: [PATCH 023/582] feat: add empty sets support (#18) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index c7ff9a00f38d..4cf3ef2504e1 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -39,6 +39,20 @@ "TIMESTAMP": types.TIMESTAMP, } +_type_map_inv = { + types.Boolean: "BOOL", + types.BINARY: "BYTES(MAX)", + types.DATE: "DATE", + types.DATETIME: "DATETIME", + types.Float: "FLOAT64", + types.BIGINT: "INT64", + types.DECIMAL: "NUMERIC", + types.String: "STRING", + types.TIME: "TIME", + types.TIMESTAMP: "TIMESTAMP", + types.Integer: "INT64", +} + _compound_keywords = { selectable.CompoundSelect.UNION: "UNION DISTINCT", selectable.CompoundSelect.UNION_ALL: "UNION ALL", @@ -54,6 +68,20 @@ class SpannerSQLCompiler(SQLCompiler): compound_keywords = _compound_keywords + def visit_empty_set_expr(self, type_): + """Return an empty set expression of the given type. + + Args: + type_ (sqlalchemy.sql.sqltypes.SchemaType): + A SQLAlchemy data type. + + Returns: + str: A query to select an empty set of the given type. + """ + return "SELECT CAST(1 AS {}) FROM (SELECT 1) WHERE 1 != 1".format( + _type_map_inv[type(type_[0])] + ) + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" From 39e4c9ce74b1e1dce0b6be178a3e59b57cca8d6d Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 10 Mar 2021 14:46:08 +0300 Subject: [PATCH 024/582] test: override syntax-inappropriate EXISTS tests (#17) --- .../sqlalchemy-spanner/test/test_suite.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index c1d089bcec31..d20b250ffc66 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -22,6 +22,7 @@ from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy import literal_column +from sqlalchemy import exists from sqlalchemy import select from sqlalchemy import Boolean from sqlalchemy import String @@ -34,6 +35,7 @@ EscapingTest as _EscapingTest, ) from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest # noqa: F401, F403 +from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest @@ -143,3 +145,49 @@ def test_render_literal_bool(self): """ self._literal_round_trip(Boolean(), [True], [True]) self._literal_round_trip(Boolean(), [False], [False]) + + +class ExistsTest(_ExistsTest): + def test_select_exists(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select((exists().where(stuff.c.data == "some data"),)) + ).fetchall(), + [(True,)], + ) + + def test_select_exists_false(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select((exists().where(stuff.c.data == "no data"),)) + ).fetchall(), + [(False,)], + ) From 37fdc2510cf56ef45a8012407d56da875bd88669 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 11 Mar 2021 10:23:53 +0300 Subject: [PATCH 025/582] test: skip underscore-names tests (#21) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 1 + packages/sqlalchemy-spanner/test/test_suite.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 4cf3ef2504e1..4ecf6e9a9ebe 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -158,6 +158,7 @@ class SpannerDialect(DefaultDialect): positional = False paramstyle = "format" encoding = "utf-8" + max_identifier_length = 128 execute_sequence_format = list diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index d20b250ffc66..7a795cb3e0d7 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -28,13 +28,12 @@ from sqlalchemy import String from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_dialect import ( # noqa: F401, F403 - EscapingTest as _EscapingTest, -) -from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest # noqa: F401, F403 +from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest +from sqlalchemy.testing.suite.test_ddl import TableDDLTest as _TableDDLTest +from sqlalchemy.testing.suite.test_dialect import EscapingTest as _EscapingTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest @@ -191,3 +190,11 @@ def test_select_exists_false(self, connection): ).fetchall(), [(False,)], ) + + +class TableDDLTest(_TableDDLTest): + @pytest.mark.skip( + "Spanner table name must start with an uppercase or lowercase letter" + ) + def test_underscore_names(self): + pass From 8b44d35c5a6f96c13ebdc9395802b8129868f011 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 11 Mar 2021 18:54:27 +0300 Subject: [PATCH 026/582] test: add DDL tests group into the test suite (#22) --- .../google/cloud/sqlalchemy_spanner/requirements.py | 4 ++++ packages/sqlalchemy-spanner/test/test_suite.py | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 418764b49b72..24e458b10e6c 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -17,6 +17,10 @@ class Requirements(SuiteRequirements): + @property + def foreign_key_constraint_name_reflection(self): + return exclusions.open() + @property def schema_reflection(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 7a795cb3e0d7..4f565c65e7f4 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -27,12 +27,17 @@ from sqlalchemy import Boolean from sqlalchemy import String +from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest from sqlalchemy.testing.suite.test_ddl import TableDDLTest as _TableDDLTest +from sqlalchemy.testing.suite.test_ddl import ( + LongNameBlowoutTest as _LongNameBlowoutTest, +) + from sqlalchemy.testing.suite.test_dialect import EscapingTest as _EscapingTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest @@ -198,3 +203,8 @@ class TableDDLTest(_TableDDLTest): ) def test_underscore_names(self): pass + + +@pytest.mark.skip("Max identifier length in Spanner is 128") +class LongNameBlowoutTest(_LongNameBlowoutTest): + pass From 1579c72bc6ace3447c43fe336b36cf4e31a49c8d Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 16 Mar 2021 16:25:00 +0530 Subject: [PATCH 027/582] test: fix datetime compliance tests (#13) * fix: datetime compliance test * fix: time related compliance test * fix: add pytest skip, doc string and remove empty classes * fix: change docstring to be consistent * fix: nit * tests: fix nit Co-authored-by: Alex <7764119+AVaksman@users.noreply.github.com> --- .../sqlalchemy-spanner/test/test_suite.py | 214 +++++++++++++++++- 1 file changed, 213 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 4f565c65e7f4..fec3c61eb483 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -22,10 +22,13 @@ from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy import literal_column +from sqlalchemy import select, case, bindparam from sqlalchemy import exists -from sqlalchemy import select from sqlalchemy import Boolean from sqlalchemy import String +from sqlalchemy.testing import requires +from sqlalchemy.types import Integer +from google.api_core.datetime_helpers import DatetimeWithNanoseconds from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 @@ -43,6 +46,18 @@ from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest +from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 + DateTest as _DateTest, + DateTimeHistoricTest, + DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, + DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, + DateTimeTest as _DateTimeTest, + TimeTest as _TimeTest, + TimeMicrosecondsTest as _TimeMicrosecondsTest, + TimestampMicrosecondsTest, +) + + class EscapingTest(_EscapingTest): @provide_metadata def test_percent_sign_round_trip(self): @@ -208,3 +223,200 @@ def test_underscore_names(self): @pytest.mark.skip("Max identifier length in Spanner is 128") class LongNameBlowoutTest(_LongNameBlowoutTest): pass + + +class DateTest(_DateTest): + def test_round_trip(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table date_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + """ + date_table = self.tables.date_table + + config.db.execute(date_table.insert(), {"id": 1, "date_data": self.data}) + + row = config.db.execute(select([date_table.c.date_data])).first() + + compare = self.compare or self.data + eq_(row, (compare,)) + assert isinstance(row[0], type(compare)) + + def test_null(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table date_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + """ + date_table = self.tables.date_table + + config.db.execute(date_table.insert(), {"id": 1, "date_data": None}) + + row = config.db.execute(select([date_table.c.date_data])).first() + eq_(row, (None,)) + + @requires.standalone_null_binds_whereclause + def test_null_bound_comparison(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table date_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + """ + + # this test is based on an Oracle issue observed in #4886. + # passing NULL for an expression that needs to be interpreted as + # a certain type, does the DBAPI have the info it needs to do this. + date_table = self.tables.date_table + with config.db.connect() as conn: + result = conn.execute( + date_table.insert(), {"id": 1, "date_data": self.data} + ) + id_ = result.inserted_primary_key[0] + stmt = select([date_table.c.id]).where( + case( + [ + ( + bindparam("foo", type_=self.datatype) + != None, # noqa: E711, + bindparam("foo", type_=self.datatype), + ) + ], + else_=date_table.c.date_data, + ) + == date_table.c.date_data + ) + + row = conn.execute(stmt, {"foo": None}).first() + eq_(row[0], id_) + + +class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest): + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Spanner is not able cleanup data and drop the table correctly, + table already exists after related tests finished, so it doesn't + create a new table and insertions for tests for other data types + will fail with `400 Invalid value for column date_data in + table date_table: Expected DATE`. + Overriding the tests to create a new table for tests to avoid the same + failures. + """ + Table( + "datetime_table", + metadata, + Column("id", Integer, primary_key=True, test_needs_autoincrement=True), + Column("date_data", cls.datatype), + ) + + def test_null(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table datetime_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + """ + date_table = self.tables.datetime_table + + config.db.execute(date_table.insert(), {"id": 1, "date_data": None}) + + row = config.db.execute(select([date_table.c.date_data])).first() + eq_(row, (None,)) + + def test_round_trip(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table datetime_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + + Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid + assert failures convert datetime input to the desire timestamp format. + """ + date_table = self.tables.datetime_table + config.db.execute(date_table.insert(), {"id": 1, "date_data": self.data}) + + row = config.db.execute(select([date_table.c.date_data])).first() + compare = self.compare or self.data + compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + eq_(row[0].rfc3339(), compare) + assert isinstance(row[0], DatetimeWithNanoseconds) + + @requires.standalone_null_binds_whereclause + def test_null_bound_comparison(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail + with `400 id must not be NULL in table datetime_table`. + Overriding the tests to add a manual primary key value to avoid the same + failures. + """ + # this test is based on an Oracle issue observed in #4886. + # passing NULL for an expression that needs to be interpreted as + # a certain type, does the DBAPI have the info it needs to do this. + date_table = self.tables.datetime_table + with config.db.connect() as conn: + result = conn.execute( + date_table.insert(), {"id": 1, "date_data": self.data} + ) + id_ = result.inserted_primary_key[0] + stmt = select([date_table.c.id]).where( + case( + [ + ( + bindparam("foo", type_=self.datatype) + != None, # noqa: E711, + bindparam("foo", type_=self.datatype), + ) + ], + else_=date_table.c.date_data, + ) + == date_table.c.date_data + ) + + row = conn.execute(stmt, {"foo": None}).first() + eq_(row[0], id_) + + +class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): + """ + SPANNER OVERRIDE: + + DateTimeTest tests have the same failures same as DateTimeMicrosecondsTest tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +@pytest.mark.skip("Spanner doesn't support Time data type.") +class TimeTests(_TimeMicrosecondsTest, _TimeTest): + pass + + +@pytest.mark.skip("Spanner doesn't coerce dates from datetime.") +class DateTimeCoercedToDateTimeTest(_DateTimeCoercedToDateTimeTest): + pass From d097b4828244bd4aadaaa71948bddb528d0b2733 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 17 Mar 2021 15:13:48 +0530 Subject: [PATCH 028/582] chore: restrict sqlalchemy version to 1.3.23 (#31) --- packages/sqlalchemy-spanner/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 6a820d0255b8..ff5f97a5ce20 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -19,7 +19,7 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" -dependencies = ["sqlalchemy>=1.1.13", "google-cloud-spanner>=3.0.0"] +dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.0.0"] # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. From 8b5e6a4792df5376ea543f6e86497692e3f4934b Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 18 Mar 2021 11:07:42 +0300 Subject: [PATCH 029/582] feat: implement schemas reflection method (#27) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 31 ++++++++++++++++++- .../sqlalchemy-spanner/test/test_suite.py | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 4ecf6e9a9ebe..db40e14782bc 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -310,7 +310,9 @@ def get_indexes(self, connection, table_name, schema=None, **kw): FROM information_schema.indexes as i JOIN information_schema.index_columns AS ic ON ic.index_name = i.index_name AND ic.table_name = i.table_name -WHERE i.table_name="{table_name}" +WHERE + i.table_name="{table_name}" + AND i.index_type != 'PRIMARY_KEY' GROUP BY i.index_name, i.is_unique """.format( table_name=table_name @@ -372,6 +374,33 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): return {"constrained_columns": cols} + def get_schema_names(self, connection, **kw): + """Get all the schemas in the database. + + Args: + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. + + Returns: + list: Schema names. + """ + if isinstance(connection, Engine): + connection = connection.connect() + + schemas = [] + with connection.connection.database.snapshot() as snap: + rows = snap.execute_sql( + "SELECT schema_name FROM information_schema.schemata" + ) + + for row in rows: + schemas.append(row[0]) + + return schemas + def get_foreign_keys(self, connection, table_name, schema=None, **kw): """Get the table foreign key constraints. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index fec3c61eb483..d0c5313c39ac 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -45,6 +45,8 @@ from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest +config.test_schema = "" + from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 DateTest as _DateTest, From c53950ed1a91e03e4e2d6d18646e727e46c1f0b8 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 18 Mar 2021 11:37:37 +0300 Subject: [PATCH 030/582] feat: tweak table dropping mechanism (#28) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index db40e14782bc..f7a6558a9d2f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -14,7 +14,7 @@ import re -from sqlalchemy import types +from sqlalchemy import types, ForeignKeyConstraint from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect from sqlalchemy.sql.compiler import ( @@ -86,6 +86,36 @@ def visit_empty_set_expr(self, type_): class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" + def visit_drop_table(self, drop_table): + """ + Cloud Spanner doesn't drop tables which have indexes + or foreign key constraints. This method builds several DDL + statements separated by semicolons to drop the indexes and + foreign keys constraints of the table before the DROP TABLE + statement. + + Args: + (sqlalchemy.schema.DropTable): DROP TABLE statement object. + + Returns: + str: + DDL statements separated by semicolons, which will + sequentially drop indexes, foreign keys constraints + and then the table itself. + """ + constrs = "" + for cons in drop_table.element.constraints: + if isinstance(cons, ForeignKeyConstraint) and cons.name: + constrs += "ALTER TABLE {table} DROP CONSTRAINT {constr};".format( + table=drop_table.element.name, constr=cons.name + ) + + indexes = "" + for index in drop_table.element.indexes: + indexes += "DROP INDEX {};".format(index.name) + + return indexes + constrs + str(drop_table) + def visit_primary_key_constraint(self, constraint): """Build primary key definition. From 09bcb7352bd454c4d0af59d378e921e04c7cba98 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Fri, 19 Mar 2021 08:07:42 +0530 Subject: [PATCH 031/582] test: fix integer compliance tests (#20) * fix: integer complaince tests * fix: add docstring for tests * fix: change docstring to be consistent * test: add todo note to remove override method * test: nit --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 3 + .../sqlalchemy-spanner/test/test_suite.py | 99 +++++++++++++++++-- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index f7a6558a9d2f..520b06912779 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -176,6 +176,9 @@ def visit_BOOLEAN(self, type_, **kw): def visit_DATETIME(self, type_, **kw): return "TIMESTAMP" + def visit_BIGINT(self, type_, **kw): + return "INT64" + class SpannerDialect(DefaultDialect): """Cloud Spanner dialect. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index d0c5313c39ac..bebfd01bb7dd 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -16,18 +16,20 @@ import pytest -from sqlalchemy.testing import config +from sqlalchemy.testing import config, db from sqlalchemy.testing import eq_ from sqlalchemy.testing import provide_metadata from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy import literal_column -from sqlalchemy import select, case, bindparam + +from sqlalchemy import bindparam, case, literal, select, util from sqlalchemy import exists from sqlalchemy import Boolean from sqlalchemy import String -from sqlalchemy.testing import requires from sqlalchemy.types import Integer +from sqlalchemy.testing import requires + from google.api_core.datetime_helpers import DatetimeWithNanoseconds from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 @@ -44,9 +46,7 @@ from sqlalchemy.testing.suite.test_dialect import EscapingTest as _EscapingTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest - -config.test_schema = "" - +from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 DateTest as _DateTest, @@ -59,6 +59,8 @@ TimestampMicrosecondsTest, ) +config.test_schema = "" + class EscapingTest(_EscapingTest): @provide_metadata @@ -422,3 +424,88 @@ class TimeTests(_TimeMicrosecondsTest, _TimeTest): @pytest.mark.skip("Spanner doesn't coerce dates from datetime.") class DateTimeCoercedToDateTimeTest(_DateTimeCoercedToDateTimeTest): pass + + +class IntegerTest(_IntegerTest): + @provide_metadata + def _round_trip(self, datatype, data): + """ + SPANNER OVERRIDE: + + This is the helper method for integer class tests which creates a table and + performs an insert operation. + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures and deleting the table at the end. + """ + metadata = self.metadata + int_table = Table( + "integer_table", + metadata, + Column("id", Integer, primary_key=True, test_needs_autoincrement=True), + Column("integer_data", datatype), + ) + + metadata.create_all(config.db) + + config.db.execute(int_table.insert(), {"id": 1, "integer_data": data}) + + row = config.db.execute(select([int_table.c.integer_data])).first() + + eq_(row, (data,)) + + if util.py3k: + assert isinstance(row[0], int) + else: + assert isinstance(row[0], (long, int)) # noqa + + config.db.execute(int_table.delete()) + + @provide_metadata + def _literal_round_trip(self, type_, input_, output, filter_=None): + """ + SPANNER OVERRIDE: + + Spanner DBAPI does not execute DDL statements unless followed by a + non DDL statement, which is preventing correct table clean up. + The table already exists after related tests finish, so it doesn't + create a new table and when running tests for other data types + insertions will fail with `400 Duplicate name in schema: t`. + Overriding the tests to create and drop a new table to prevent + database existence errors. + """ + + # for literal, we test the literal render in an INSERT + # into a typed column. we can then SELECT it back as its + # official type; ideally we'd be able to use CAST here + # but MySQL in particular can't CAST fully + t = Table("int_t", self.metadata, Column("x", type_)) + t.create() + + with db.connect() as conn: + for value in input_: + ins = ( + t.insert() + .values(x=literal(value)) + .compile( + dialect=db.dialect, compile_kwargs=dict(literal_binds=True), + ) + ) + conn.execute(ins) + conn.execute("SELECT 1") + + if self.supports_whereclause: + stmt = t.select().where(t.c.x == literal(value)) + else: + stmt = t.select() + + stmt = stmt.compile( + dialect=db.dialect, compile_kwargs=dict(literal_binds=True), + ) + for row in conn.execute(stmt): + value = row[0] + if filter_ is not None: + value = filter_(value) + assert value in output From 1b58d96a638c1d5ef0c51cf659a1190c0e4a2165 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 31 Mar 2021 06:48:13 +0300 Subject: [PATCH 032/582] Update README.md (#35) Co-authored-by: skuruppu Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- packages/sqlalchemy-spanner/README.md | 133 +++++++++++++++++++- packages/sqlalchemy-spanner/contributing.md | 26 ++++ 2 files changed, 156 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 9a296baa3e8a..267d42c9cd89 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -1,11 +1,40 @@ -# python-sqlalchemy-spanner +# Spanner dialect for SQLAlchemy + +Spanner dialect for SQLAlchemy represents an interface API designed to make it possible to control Cloud Spanner databases with SQLAlchemy API. The dialect is built on top of [the Spanner DB API](https://github.com/googleapis/python-spanner/tree/master/google/cloud/spanner_dbapi), which is designed in accordance with [PEP-249](https://www.python.org/dev/peps/pep-0249/). **NOTE: This project is still in DEVELOPMENT. It may make breaking changes without prior notice and should not yet be used for production purposes.** -**Usage example**: +- [Cloud Spanner product documentation](https://cloud.google.com/spanner/docs) +- [SQLAlchemy product documentation](https://www.sqlalchemy.org/) + +Quick Start +----------- + +In order to use this package, you first need to go through the following steps: + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) +2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project) +3. [Enable the Google Cloud Spanner API.](https://cloud.google.com/spanner) +4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html) + +Installation +----------- + +To install an in-development version of the package, clone its Git-repository: +``` +git clone https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy.git +``` +Next install the package from the package `setup.py` file: +``` +python setup.py install +``` +During setup the dialect will be registered with entry points. +Example Usage +----------- +**Simple SELECT** ```python -from sqlalchemy import create_engine, select, MetaData, Table +from sqlalchemy import MetaData, Table, create_engine, select engine = create_engine( "spanner:///projects/project-id/instances/instance-id/databases/database-id" @@ -15,3 +44,101 @@ table = Table("table-id", MetaData(bind=engine), autoload=True) for row in select(["*"], from_obj=table).execute().fetchall(): print(row) ``` + +**Create a table** +```python +from sqlalchemy import ( + Column, + Integer, + MetaData, + String, + Table, + create_engine, +) + +engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test" +) +metadata = MetaData() + +user = Table( + "users", + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), +) + +metadata.create_all(engine) +``` +Migration +----------- +SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. + +Features and limitations +----------- +**Unique constraints** +Cloud Spanner doesn't support direct UNIQUE constraints creation. In order to achieve column values uniqueness UNIQUE indexes should be used. + +Instead of direct UNIQUE constraint creation: +```python +Table( + 'table', + metadata, + Column('col1', Integer), + UniqueConstraint('col1', name='uix_1') +) +``` +Create a UNIQUE index: +```python +Table( + 'table', + metadata, + Column('col1', Integer), + Index("uix_1", "col1", unique=True), +) +``` +**Autocommit mode** +Spanner dialect supports both "autocommit" and "manual commit" modes. To set/change the current mode isolation levels can be used: `SERIALIZABLE` and `AUTOCOMMIT`. + +**DDL and transactions** +DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. + +**Dropping a table** +Cloud Spanner, by default, doesn't drop tables, which have secondary indexes and/or foreign key constraints. In Spanner dialect for SQLAlchemy, however, this restriction is omitted - if a table you are trying to delete has indexes/foreign keys, they will be dropped automatically right before dropping the table. + +**Data types** +Data types table mapping SQLAlchemy types to Cloud Spanner types: + +| SQLAlchemy | Spanner | +| ------------- | ------------- | +| INTEGER | INT64 | +| BIGINT | INT64 | +| DECIMAL | NUMERIC | +| FLOAT | FLOAT64 | +| TEXT | STRING | +| ARRAY | ARRAY | +| BINARY | BYTES | +| VARCHAR | STRING | +| CHAR | STRING | +| BOOLEAN | BOOL | +| DATETIME | TIMESTAMP | +| NUMERIC | NUMERIC | + + +**Other limitations** +- WITH RECURSIVE statement is not supported. +- Named schemas are not supported. +- Temporary tables are not supported, real tables are used instead. +- Numeric type dimensions (scale and precision) are constant. See the [docs](https://cloud.google.com/spanner/docs/data-types#numeric_types). + +Contributing +------------ + +Contributions to this library are welcome and encouraged. + +See [CONTRIBUTING](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get +started. + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. See the [Code +of Conduct](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/code-of-conduct.md) for more information. diff --git a/packages/sqlalchemy-spanner/contributing.md b/packages/sqlalchemy-spanner/contributing.md index 6272489dae31..6294c4529e49 100644 --- a/packages/sqlalchemy-spanner/contributing.md +++ b/packages/sqlalchemy-spanner/contributing.md @@ -26,3 +26,29 @@ information on using pull requests. This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/). + +## Running tests + +SQLAlchemy Spanner dialect includes a test suite, which can be executed both on a live service and Spanner emulator. + +**Using pytest** +To execute the test suite with standard `pytest` package you only need to checkout to the package folder and run: +``` +pytest -v +``` + +**Using nox** +The package includes a configuration file for `nox` package, which allows to execute the dialect test suite in an isolated virtual environment. To execute all the `nox` sessions checkout to the dialect folder and then run command: +``` +nox +``` +To execute only the dialect compliance test suite execute command: +``` +nox -s compliance_test +``` + +**Live service** +To run the test suite on a live service use [setup.cfg](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/setup.cfg) `db.default` attribute to set URI of the project, instance and database, where the tests should be executed. + +**Emulator** +As the dialect is built on top of the Spanner DB API, it also supports running on Spanner emulator. To make it happen you need to set an environment variable, pointing to the emulator service, for example `SPANNER_EMULATOR_HOST=localhost:9010` \ No newline at end of file From d80ad62b968632befb6c552a17fcc456c256efe2 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 31 Mar 2021 15:18:19 +1100 Subject: [PATCH 033/582] test: add basic circleci config (#39) --- .../sqlalchemy-spanner/.circleci/config.yml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.circleci/config.yml diff --git a/packages/sqlalchemy-spanner/.circleci/config.yml b/packages/sqlalchemy-spanner/.circleci/config.yml new file mode 100644 index 000000000000..23c416210178 --- /dev/null +++ b/packages/sqlalchemy-spanner/.circleci/config.yml @@ -0,0 +1,21 @@ +version: 2.1 + +orbs: + python: circleci/python@3.8.0 + +jobs: + build-and-test: + executor: python/default + steps: + - checkout + - python/load-cache + - python/install-deps + - python/save-cache + - run: + command: ./manage.py test + name: Test + +workflows: + main: + jobs: + - build-and-test From 3e107673dc3c87614307f90e64bb1a7047d8cc40 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 2 Apr 2021 15:33:12 +0300 Subject: [PATCH 034/582] feat: set higher python-spanner requirements (#38) --- packages/sqlalchemy-spanner/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index ff5f97a5ce20..17fd6162e3b4 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -19,7 +19,7 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" -dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.0.0"] +dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.3.0"] # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. From 66f4cfe604c392fc07346645f0746910afb10c4b Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 2 Apr 2021 19:18:06 +0300 Subject: [PATCH 035/582] feat: implement UNIQUE constraints creation mechanism (#24) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 12 ++ .../sqlalchemy-spanner/test/test_suite.py | 183 +++++++++++++++++- 2 files changed, 190 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 520b06912779..5e93d8177f5e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -126,6 +126,18 @@ def visit_primary_key_constraint(self, constraint): """ return None + def visit_unique_constraint(self, constraint): + """Unique contraints in Spanner are defined with indexes: + https://cloud.google.com/spanner/docs/secondary-indexes#unique-indexes + + The method throws an exception to notify user that in + Spanner unique constraints are done with unique indexes. + """ + raise spanner_dbapi.exceptions.ProgrammingError( + "Spanner doesn't support direct UNIQUE constraints creation. " + "Create UNIQUE indexes instead." + ) + def post_create_table(self, table): """Build statements to be executed after CREATE TABLE. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index bebfd01bb7dd..17c57bae870f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,16 +14,29 @@ # See the License for the specific language governing permissions and # limitations under the License. +import operator import pytest -from sqlalchemy.testing import config, db +import sqlalchemy +from sqlalchemy import inspect +from sqlalchemy import testing +from sqlalchemy import ForeignKey +from sqlalchemy import MetaData +from sqlalchemy.schema import DDL +from sqlalchemy.testing import config +from sqlalchemy.testing import db from sqlalchemy.testing import eq_ from sqlalchemy.testing import provide_metadata +from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table +from sqlalchemy import bindparam +from sqlalchemy import case +from sqlalchemy import literal from sqlalchemy import literal_column - -from sqlalchemy import bindparam, case, literal, select, util +from sqlalchemy import select +from sqlalchemy import util +from sqlalchemy import event from sqlalchemy import exists from sqlalchemy import Boolean from sqlalchemy import String @@ -32,8 +45,10 @@ from google.api_core.datetime_helpers import DatetimeWithNanoseconds -from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 +from google.cloud import spanner_dbapi + from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 @@ -42,8 +57,10 @@ from sqlalchemy.testing.suite.test_ddl import ( LongNameBlowoutTest as _LongNameBlowoutTest, ) - from sqlalchemy.testing.suite.test_dialect import EscapingTest as _EscapingTest +from sqlalchemy.testing.suite.test_reflection import ( + ComponentReflectionTest as _ComponentReflectionTest, +) from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest @@ -102,6 +119,29 @@ def test_percent_sign_round_trip(self): class CTETest(_CTETest): + @classmethod + def define_tables(cls, metadata): + """ + The original method creates a foreign key without a name, + which causes troubles on test cleanup. Overriding the + method to explicitly set a foreign key name. + """ + Table( + "some_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", ForeignKey("some_table.id", name="fk_some_table")), + ) + + Table( + "some_other_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", Integer), + ) + @pytest.mark.skip("INSERT from WITH subquery is not supported") def test_insert_from_select_round_trip(self): """ @@ -509,3 +549,136 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): if filter_ is not None: value = filter_(value) assert value in output + + +class ComponentReflectionTest(_ComponentReflectionTest): + @classmethod + def define_temp_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + In Cloud Spanner unique indexes are used instead of directly + creating unique constraints. Overriding the test to replace + constraints with indexes in testing data. + """ + kw = temp_table_keyword_args(config, config.db) + user_tmp = Table( + "user_tmp", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + Column("foo", sqlalchemy.INT), + sqlalchemy.Index("user_tmp_uq", "name", unique=True), + sqlalchemy.Index("user_tmp_ix", "foo"), + **kw + ) + if ( + testing.requires.view_reflection.enabled + and testing.requires.temporary_views.enabled + ): + event.listen( + user_tmp, + "after_create", + DDL("create temporary view user_tmp_v as " "select * from user_tmp"), + ) + event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v")) + + @testing.provide_metadata + def _test_get_unique_constraints(self, schema=None): + """ + SPANNER OVERRIDE: + + In Cloud Spanner unique indexes are used instead of directly + creating unique constraints. Overriding the test to replace + constraints with indexes in testing data. + """ + # SQLite dialect needs to parse the names of the constraints + # separately from what it gets from PRAGMA index_list(), and + # then matches them up. so same set of column_names in two + # constraints will confuse it. Perhaps we should no longer + # bother with index_list() here since we have the whole + # CREATE TABLE? + uniques = sorted( + [ + {"name": "unique_a", "column_names": ["a"]}, + {"name": "unique_a_b_c", "column_names": ["a", "b", "c"]}, + {"name": "unique_c_a_b", "column_names": ["c", "a", "b"]}, + {"name": "unique_asc_key", "column_names": ["asc", "key"]}, + {"name": "i.have.dots", "column_names": ["b"]}, + {"name": "i have spaces", "column_names": ["c"]}, + ], + key=operator.itemgetter("name"), + ) + orig_meta = self.metadata + table = Table( + "testtbl", + orig_meta, + Column("a", sqlalchemy.String(20)), + Column("b", sqlalchemy.String(30)), + Column("c", sqlalchemy.Integer), + # reserved identifiers + Column("asc", sqlalchemy.String(30)), + Column("key", sqlalchemy.String(30)), + schema=schema, + ) + for uc in uniques: + table.append_constraint( + sqlalchemy.Index(uc["name"], *uc["column_names"], unique=True) + ) + orig_meta.create_all() + + inspector = inspect(orig_meta.bind) + reflected = sorted( + inspector.get_unique_constraints("testtbl", schema=schema), + key=operator.itemgetter("name"), + ) + + names_that_duplicate_index = set() + + for orig, refl in zip(uniques, reflected): + # Different dialects handle duplicate index and constraints + # differently, so ignore this flag + dupe = refl.pop("duplicates_index", None) + if dupe: + names_that_duplicate_index.add(dupe) + eq_(orig, refl) + + reflected_metadata = MetaData() + reflected = Table( + "testtbl", reflected_metadata, autoload_with=orig_meta.bind, schema=schema, + ) + + # test "deduplicates for index" logic. MySQL and Oracle + # "unique constraints" are actually unique indexes (with possible + # exception of a unique that is a dupe of another one in the case + # of Oracle). make sure # they aren't duplicated. + idx_names = set([idx.name for idx in reflected.indexes]) + uq_names = set( + [ + uq.name + for uq in reflected.constraints + if isinstance(uq, sqlalchemy.UniqueConstraint) + ] + ).difference(["unique_c_a_b"]) + + assert not idx_names.intersection(uq_names) + if names_that_duplicate_index: + eq_(names_that_duplicate_index, idx_names) + eq_(uq_names, set()) + + @testing.provide_metadata + def test_unique_constraint_raises(self): + """ + Checking that unique constraint creation + fails due to a ProgrammingError. + """ + Table( + "user_tmp_failure", + self.metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + sqlalchemy.UniqueConstraint("name", name="user_tmp_uq"), + ) + + with pytest.raises(spanner_dbapi.exceptions.ProgrammingError): + self.metadata.create_all() From a8b582894abb929f8b20f3a3446661aaf96f4f58 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 6 Apr 2021 13:35:09 +0300 Subject: [PATCH 036/582] fix: use empty schema name by default (#32) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- .../sqlalchemy-spanner/test/test_suite.py | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 5e93d8177f5e..b672f46dd1ca 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -527,7 +527,7 @@ def get_table_names(self, connection, schema=None, **kw): FROM information_schema.tables WHERE table_schema = '{}' """.format( - schema + schema or "" ) table_names = [] diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 17c57bae870f..36ef6a4dddad 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -682,3 +682,48 @@ def test_unique_constraint_raises(self): with pytest.raises(spanner_dbapi.exceptions.ProgrammingError): self.metadata.create_all() + + @testing.provide_metadata + def _test_get_table_names(self, schema=None, table_type="table", order_by=None): + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + _ignore_tables = [ + "comment_test", + "noncol_idx_test_pk", + "noncol_idx_test_nopk", + "local_table", + "remote_table", + "remote_table_2", + ] + meta = self.metadata + + insp = inspect(meta.bind) + + if table_type == "view": + table_names = insp.get_view_names(schema) + table_names.sort() + answer = ["email_addresses_v", "users_v"] + eq_(sorted(table_names), answer) + else: + if order_by: + tables = [ + rec[0] + for rec in insp.get_sorted_table_and_fkc_names(schema) + if rec[0] + ] + else: + tables = insp.get_table_names(schema) + table_names = [t for t in tables if t not in _ignore_tables] + + if order_by == "foreign_key": + answer = ["users", "user_tmp", "email_addresses", "dingalings"] + eq_(table_names, answer) + else: + answer = ["dingalings", "email_addresses", "user_tmp", "users"] + eq_(sorted(table_names), answer) From d3952c6faffa98805f53cccf8b944aebcd58bd83 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 7 Apr 2021 05:17:30 +0300 Subject: [PATCH 037/582] test: skip unsupported features tests (#46) --- .../cloud/sqlalchemy_spanner/requirements.py | 4 ++++ packages/sqlalchemy-spanner/test/test_suite.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 24e458b10e6c..1ef7af9b2686 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -37,6 +37,10 @@ def autocommit(self): def order_by_collation(self): return exclusions.open() + @property + def implements_get_lastrowid(self): + return exclusions.closed() + @property def ctes(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 36ef6a4dddad..da5f3cfa504a 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -58,6 +58,9 @@ LongNameBlowoutTest as _LongNameBlowoutTest, ) from sqlalchemy.testing.suite.test_dialect import EscapingTest as _EscapingTest +from sqlalchemy.testing.suite.test_insert import ( + InsertBehaviorTest as _InsertBehaviorTest, +) from sqlalchemy.testing.suite.test_reflection import ( ComponentReflectionTest as _ComponentReflectionTest, ) @@ -727,3 +730,17 @@ def _test_get_table_names(self, schema=None, table_type="table", order_by=None): else: answer = ["dingalings", "email_addresses", "user_tmp", "users"] eq_(sorted(table_names), answer) + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_indexes(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_unique_constraints(self): + pass + + +class InsertBehaviorTest(_InsertBehaviorTest): + @pytest.mark.skip("Spanner doesn't support empty inserts") + def test_empty_insert(self): + pass From 373675492d9c1ab2a123b0ff568b15953e20c8b7 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 7 Apr 2021 10:56:59 +0300 Subject: [PATCH 038/582] Update README.md (#44) --- packages/sqlalchemy-spanner/README.md | 51 ++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 267d42c9cd89..0eafe70a3845 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -30,21 +30,8 @@ python setup.py install ``` During setup the dialect will be registered with entry points. -Example Usage +A Minimal App ----------- -**Simple SELECT** -```python -from sqlalchemy import MetaData, Table, create_engine, select - -engine = create_engine( - "spanner:///projects/project-id/instances/instance-id/databases/database-id" -) - -table = Table("table-id", MetaData(bind=engine), autoload=True) -for row in select(["*"], from_obj=table).execute().fetchall(): - print(row) -``` - **Create a table** ```python from sqlalchemy import ( @@ -57,9 +44,9 @@ from sqlalchemy import ( ) engine = create_engine( - "spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test" + "spanner:///projects/project-id/instances/instance-id/databases/database-id" ) -metadata = MetaData() +metadata = MetaData(bind=engine) user = Table( "users", @@ -70,6 +57,38 @@ user = Table( metadata.create_all(engine) ``` +**Insert a row** +```python +from sqlalchemy import ( + MetaData, + Table, + create_engine, + insert, +) + +engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" +) +metadata = MetaData(bind=engine) + +user = Table("users", metadata, autoload=True) + +insert(user).values(user_id=1, user_name="Full Name").execute() +``` + +**Read** +```python +from sqlalchemy import MetaData, Table, create_engine, select + +engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" +) + +table = Table("users", MetaData(bind=engine), autoload=True) +for row in select(["*"], from_obj=table).execute().fetchall(): + print(row) +``` + Migration ----------- SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. From 3465b69d52a3e7a3799649310025cc362898dc0b Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 7 Apr 2021 19:36:13 +0300 Subject: [PATCH 039/582] fix: types reflection (#33) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 14 ++++-- .../sqlalchemy-spanner/test/test_suite.py | 46 +++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index b672f46dd1ca..92f225b74f23 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -33,7 +33,7 @@ "DATETIME": types.DATETIME, "FLOAT64": types.Float, "INT64": types.BIGINT, - "NUMERIC": types.DECIMAL, + "NUMERIC": types.NUMERIC(precision=38, scale=9), "STRING": types.String, "TIME": types.TIME, "TIMESTAMP": types.TIMESTAMP, @@ -176,6 +176,9 @@ def visit_BINARY(self, type_, **kw): def visit_DECIMAL(self, type_, **kw): return "NUMERIC" + def visit_NUMERIC(self, type_, **kw): + return "NUMERIC" + def visit_VARCHAR(self, type_, **kw): return "STRING({})".format(type_.length) @@ -314,12 +317,17 @@ def get_columns(self, connection, table_name, schema=None, **kw): columns = snap.execute_sql(sql) for col in columns: - type_ = "STRING" if col[1].startswith("STRING") else col[1] + if col[1].startswith("STRING"): + end = col[1].index(")") + size = int(col[1][7:end]) + type_ = _type_map["STRING"](length=size) + else: + type_ = _type_map[col[1]] cols_desc.append( { "name": col[0], - "type": _type_map[type_], + "type": type_, "nullable": col[2] == "YES", "default": None, } diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index da5f3cfa504a..7d50af1d5d17 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -16,6 +16,7 @@ import operator import pytest +import pytz import sqlalchemy from sqlalchemy import inspect @@ -41,6 +42,7 @@ from sqlalchemy import Boolean from sqlalchemy import String from sqlalchemy.types import Integer +from sqlalchemy.types import Numeric from sqlalchemy.testing import requires from google.api_core.datetime_helpers import DatetimeWithNanoseconds @@ -50,6 +52,7 @@ from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest @@ -64,6 +67,7 @@ from sqlalchemy.testing.suite.test_reflection import ( ComponentReflectionTest as _ComponentReflectionTest, ) +from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest @@ -739,6 +743,48 @@ def test_get_temp_table_indexes(self): def test_get_temp_table_unique_constraints(self): pass + @testing.requires.table_reflection + def test_numeric_reflection(self): + """ + SPANNER OVERRIDE: + + Spanner defines NUMERIC type with the constant precision=38 + and scale=9. Overriding the test to check if the NUMERIC + column is successfully created and has dimensions + correct for Cloud Spanner. + """ + for typ in self._type_round_trip(Numeric(18, 5)): + assert isinstance(typ, Numeric) + eq_(typ.precision, 38) + eq_(typ.scale, 9) + + +class RowFetchTest(_RowFetchTest): + def test_row_w_scalar_select(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner returns a DatetimeWithNanoseconds() for date + data types. Overriding the test to use a DatetimeWithNanoseconds + type value as an expected result. + -------------- + + test that a scalar select as a column is returned as such + and that type conversion works OK. + + (this is half a SQLAlchemy Core test and half to catch database + backends that may have unusual behavior with scalar selects.) + """ + datetable = self.tables.has_dates + s = select([datetable.alias("x").c.today]).as_scalar() + s2 = select([datetable.c.id, s.label("somelabel")]) + row = config.db.execute(s2).first() + + eq_( + row["somelabel"], + DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=pytz.UTC), + ) + class InsertBehaviorTest(_InsertBehaviorTest): @pytest.mark.skip("Spanner doesn't support empty inserts") From b2a120bc1a754c4bb8617c551db0f2b5bf319418 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Thu, 8 Apr 2021 20:01:12 +0530 Subject: [PATCH 040/582] refactor: remove unnecessary override functions (#37) --- .../sqlalchemy-spanner/test/test_suite.py | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 7d50af1d5d17..9a6b1159a920 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -354,26 +354,6 @@ def test_null_bound_comparison(self): class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest): - @classmethod - def define_tables(cls, metadata): - """ - SPANNER OVERRIDE: - - Spanner is not able cleanup data and drop the table correctly, - table already exists after related tests finished, so it doesn't - create a new table and insertions for tests for other data types - will fail with `400 Invalid value for column date_data in - table date_table: Expected DATE`. - Overriding the tests to create a new table for tests to avoid the same - failures. - """ - Table( - "datetime_table", - metadata, - Column("id", Integer, primary_key=True, test_needs_autoincrement=True), - Column("date_data", cls.datatype), - ) - def test_null(self): """ SPANNER OVERRIDE: @@ -384,7 +364,7 @@ def test_null(self): Overriding the tests to add a manual primary key value to avoid the same failures. """ - date_table = self.tables.datetime_table + date_table = self.tables.date_table config.db.execute(date_table.insert(), {"id": 1, "date_data": None}) @@ -404,7 +384,7 @@ def test_round_trip(self): Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid assert failures convert datetime input to the desire timestamp format. """ - date_table = self.tables.datetime_table + date_table = self.tables.date_table config.db.execute(date_table.insert(), {"id": 1, "date_data": self.data}) row = config.db.execute(select([date_table.c.date_data])).first() @@ -427,7 +407,7 @@ def test_null_bound_comparison(self): # this test is based on an Oracle issue observed in #4886. # passing NULL for an expression that needs to be interpreted as # a certain type, does the DBAPI have the info it needs to do this. - date_table = self.tables.datetime_table + date_table = self.tables.date_table with config.db.connect() as conn: result = conn.execute( date_table.insert(), {"id": 1, "date_data": self.data} @@ -485,7 +465,7 @@ def _round_trip(self, datatype, data): row can be inserted into such a table - following insertions will fail with `400 id must not be NULL in table date_table`. Overriding the tests and adding a manual primary key value to avoid the same - failures and deleting the table at the end. + failures. """ metadata = self.metadata int_table = Table( @@ -508,8 +488,6 @@ def _round_trip(self, datatype, data): else: assert isinstance(row[0], (long, int)) # noqa - config.db.execute(int_table.delete()) - @provide_metadata def _literal_round_trip(self, type_, input_, output, filter_=None): """ From 845280e10e9a32c0dc914daf1aba4770a858f27b Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 14 Apr 2021 18:33:32 +0300 Subject: [PATCH 041/582] test: skip unsupported features (#49) --- .../sqlalchemy-spanner/test/test_suite.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 9a6b1159a920..681458f87c69 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -52,6 +52,7 @@ from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 @@ -69,6 +70,9 @@ ) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest +from sqlalchemy.testing.suite.test_select import ( + IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, +) from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest @@ -768,3 +772,20 @@ class InsertBehaviorTest(_InsertBehaviorTest): @pytest.mark.skip("Spanner doesn't support empty inserts") def test_empty_insert(self): pass + + @pytest.mark.skip("Spanner doesn't support auto increment") + def test_insert_from_select_autoinc(self): + pass + + @pytest.mark.skip("Spanner doesn't support auto increment") + def test_insert_from_select_autoinc_no_rows(self): + pass + + @pytest.mark.skip("Spanner doesn't support default column values") + def test_insert_from_select_with_defaults(self): + pass + + +@pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") +class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): + pass From 46893a251db8ea36734bd87c886bac7f43a8ddaa Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 14 Apr 2021 18:36:44 +0300 Subject: [PATCH 042/582] refactor: use a decorator for connection initiation (#52) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 95 ++++++++----------- 1 file changed, 39 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 92f225b74f23..fe0041b4c917 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -63,6 +63,29 @@ } +def engine_to_connection(function): + """ + Decorator to initiate a connection to a + database in case of an engine-related use. + """ + + def wrapper(self, connection, *args, **kwargs): + """ + Args: + connection (Union[ + sqlalchemy.engine.base.Connection, + sqlalchemy.engine.Engine + ]): + SQLAlchemy connection or engine object. + """ + if isinstance(connection, Engine): + connection = connection.connect() + + return function(self, connection, *args, **kwargs) + + return wrapper + + class SpannerSQLCompiler(SQLCompiler): """Spanner SQL statements compiler.""" @@ -276,16 +299,14 @@ def create_connect_args(self, url): {}, ) + @engine_to_connection def get_columns(self, connection, table_name, schema=None, **kw): """Get the table columns description. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name @@ -293,9 +314,6 @@ def get_columns(self, connection, table_name, schema=None, **kw): Returns: list: The table every column dict-like description. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT column_name, spanner_type, is_nullable FROM information_schema.columns @@ -334,16 +352,14 @@ def get_columns(self, connection, table_name, schema=None, **kw): ) return cols_desc + @engine_to_connection def get_indexes(self, connection, table_name, schema=None, **kw): """Get the table indexes. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name @@ -351,9 +367,6 @@ def get_indexes(self, connection, table_name, schema=None, **kw): Returns: list: List with indexes description. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT i.index_name, @@ -388,16 +401,14 @@ def get_indexes(self, connection, table_name, schema=None, **kw): ) return ind_desc + @engine_to_connection def get_pk_constraint(self, connection, table_name, schema=None, **kw): """Get the table primary key constraint. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name @@ -405,9 +416,6 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): Returns: dict: Dict with the primary key constraint description. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT ccu.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc @@ -427,22 +435,17 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): return {"constrained_columns": cols} + @engine_to_connection def get_schema_names(self, connection, **kw): """Get all the schemas in the database. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. Returns: list: Schema names. """ - if isinstance(connection, Engine): - connection = connection.connect() - schemas = [] with connection.connection.database.snapshot() as snap: rows = snap.execute_sql( @@ -454,16 +457,14 @@ def get_schema_names(self, connection, **kw): return schemas + @engine_to_connection def get_foreign_keys(self, connection, table_name, schema=None, **kw): """Get the table foreign key constraints. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name @@ -471,9 +472,6 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): Returns: list: Dicts, each of which describes a foreign key constraint. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT tc.constraint_name, @@ -511,25 +509,20 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): ) return keys + @engine_to_connection def get_table_names(self, connection, schema=None, **kw): """Get all the tables from the given schema. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. schema (str): Optional. Schema name. Returns: list: Names of the tables within the given schema. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT table_name FROM information_schema.tables @@ -547,16 +540,14 @@ def get_table_names(self, connection, schema=None, **kw): return table_names + @engine_to_connection def get_unique_constraints(self, connection, table_name, schema=None, **kw): """Get the table unique constraints. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name @@ -564,9 +555,6 @@ def get_unique_constraints(self, connection, table_name, schema=None, **kw): Returns: dict: Dict with the unique constraints' descriptions. """ - if isinstance(connection, Engine): - connection = connection.connect() - sql = """ SELECT ccu.CONSTRAINT_NAME, ccu.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc @@ -586,16 +574,14 @@ def get_unique_constraints(self, connection, table_name, schema=None, **kw): return cols + @engine_to_connection def has_table(self, connection, table_name, schema=None): """Check if the given table exists. The method is used by SQLAlchemy introspection systems. Args: - connection (Union[ - sqlalchemy.engine.base.Connection, - sqlalchemy.engine.Engine - ]): + connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. table_name (str): Name of the table to introspect. schema (str): Optional. Schema name. @@ -603,9 +589,6 @@ def has_table(self, connection, table_name, schema=None): Returns: bool: True, if the given table exists, False otherwise. """ - if isinstance(connection, Engine): - connection = connection.connect() - with connection.connection.database.snapshot() as snap: rows = snap.execute_sql( """ From 7b26b4d7c6052d096b14cf5e1a750a28a91bf8ed Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 14 Apr 2021 18:39:02 +0300 Subject: [PATCH 043/582] fix: use INT64 type for empty sets with no type (#50) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index fe0041b4c917..3ca6544d638e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -51,6 +51,7 @@ types.TIME: "TIME", types.TIMESTAMP: "TIMESTAMP", types.Integer: "INT64", + types.NullType: "INT64", } _compound_keywords = { From cb6e0150b912b5728f9530cb5afb6e3c2dac7692 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 14 Apr 2021 18:45:21 +0300 Subject: [PATCH 044/582] fix: support types with length (#48) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 11 +++++++---- packages/sqlalchemy-spanner/test/test_suite.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 3ca6544d638e..d69a2d21e08e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -189,13 +189,16 @@ def visit_FLOAT(self, type_, **kw): return "FLOAT64" def visit_TEXT(self, type_, **kw): - return "STRING({})".format(type_.length) + return "STRING({})".format(type_.length or "MAX") def visit_ARRAY(self, type_, **kw): return "ARRAY<{}>".format(self.process(type_.item_type, **kw)) def visit_BINARY(self, type_, **kw): - return "BYTES" + return "BYTES({})".format(type_.length or "MAX") + + def visit_large_binary(self, type_, **kw): + return "BYTES({})".format(type_.length or "MAX") def visit_DECIMAL(self, type_, **kw): return "NUMERIC" @@ -204,10 +207,10 @@ def visit_NUMERIC(self, type_, **kw): return "NUMERIC" def visit_VARCHAR(self, type_, **kw): - return "STRING({})".format(type_.length) + return "STRING({})".format(type_.length or "MAX") def visit_CHAR(self, type_, **kw): - return "STRING({})".format(type_.length) + return "STRING({})".format(type_.length or "MAX") def visit_BOOLEAN(self, type_, **kw): return "BOOL" diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 681458f87c69..791f50e95a05 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -27,6 +27,7 @@ from sqlalchemy.testing import config from sqlalchemy.testing import db from sqlalchemy.testing import eq_ +from sqlalchemy.testing import fixtures from sqlalchemy.testing import provide_metadata from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column @@ -39,6 +40,7 @@ from sqlalchemy import util from sqlalchemy import event from sqlalchemy import exists +from sqlalchemy import LargeBinary from sqlalchemy import Boolean from sqlalchemy import String from sqlalchemy.types import Integer @@ -75,6 +77,7 @@ ) from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest +from sqlalchemy.testing.suite.test_types import _LiteralRoundTripFixture from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 DateTest as _DateTest, @@ -789,3 +792,14 @@ def test_insert_from_select_with_defaults(self): @pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): pass + + +class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): + __backend__ = True + + def test_nolength_binary(self): + metadata = MetaData() + foo = Table("foo", metadata, Column("one", LargeBinary)) + + foo.create(config.db) + foo.drop(config.db) From 623be3e0f4710ba385cbcd0033a3d292db1fb957 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 14 Apr 2021 21:24:23 +0530 Subject: [PATCH 045/582] test: skip sequence tests (#45) --- .../sqlalchemy-spanner/test/test_suite.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 791f50e95a05..3c27243e26f4 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -90,6 +90,12 @@ TimestampMicrosecondsTest, ) +from sqlalchemy.testing.suite.test_sequence import ( + SequenceCompilerTest as _SequenceCompilerTest, + HasSequenceTest as _HasSequenceTest, + SequenceTest as _SequenceTest, +) + config.test_schema = "" @@ -543,6 +549,21 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): assert value in output +@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") +class SequenceCompilerTest(_SequenceCompilerTest): + pass + + +@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") +class HasSequenceTest(_HasSequenceTest): + pass + + +@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") +class SequenceTest(_SequenceTest): + pass + + class ComponentReflectionTest(_ComponentReflectionTest): @classmethod def define_temp_tables(cls, metadata): From 7b8d555f78dff9c52ab0aef3c28addc5e0dc78a8 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 21 Apr 2021 18:46:15 +0300 Subject: [PATCH 046/582] test: skip test, which check use of quotes in table names (#54) --- packages/sqlalchemy-spanner/test/test_suite.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 3c27243e26f4..a1ca96dc4f65 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -70,6 +70,9 @@ from sqlalchemy.testing.suite.test_reflection import ( ComponentReflectionTest as _ComponentReflectionTest, ) +from sqlalchemy.testing.suite.test_reflection import ( + QuotedNameArgumentTest as _QuotedNameArgumentTest, +) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_select import ( @@ -564,6 +567,11 @@ class SequenceTest(_SequenceTest): pass +@pytest.mark.skip("Spanner doesn't support quotes in table names.") +class QuotedNameArgumentTest(_QuotedNameArgumentTest): + pass + + class ComponentReflectionTest(_ComponentReflectionTest): @classmethod def define_temp_tables(cls, metadata): From 2a4b9dd408c9534504cf2734b71a6e172c6f3832 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 21 Apr 2021 18:51:19 +0300 Subject: [PATCH 047/582] fix: composite keys reflection (#56) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 9 ++++--- .../sqlalchemy-spanner/test/test_suite.py | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index d69a2d21e08e..3c9d649637cd 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -481,8 +481,8 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): tc.constraint_name, ctu.table_name, ctu.table_schema, - ccu.column_name, - kcu.column_name + ARRAY_AGG(DISTINCT ccu.column_name), + ARRAY_AGG(kcu.column_name) FROM information_schema.table_constraints AS tc JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name @@ -493,6 +493,7 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): WHERE tc.table_name="{table_name}" AND tc.constraint_type = "FOREIGN KEY" +GROUP BY tc.constraint_name, ctu.table_name, ctu.table_schema """.format( table_name=table_name ) @@ -507,8 +508,8 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): "name": row[0], "referred_table": row[1], "referred_schema": row[2] or None, - "referred_columns": [row[3]], - "constrained_columns": [row[4]], + "referred_columns": row[3], + "constrained_columns": row[4], } ) return keys diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index a1ca96dc4f65..509fbef699c9 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -55,6 +55,7 @@ from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 @@ -73,6 +74,9 @@ from sqlalchemy.testing.suite.test_reflection import ( QuotedNameArgumentTest as _QuotedNameArgumentTest, ) +from sqlalchemy.testing.suite.test_reflection import ( + CompositeKeyReflectionTest as _CompositeKeyReflectionTest, +) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest from sqlalchemy.testing.suite.test_select import ( @@ -773,6 +777,27 @@ def test_numeric_reflection(self): eq_(typ.scale, 9) +class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): + @testing.requires.foreign_key_constraint_reflection + @testing.provide_metadata + def test_fk_column_order(self): + """ + SPANNER OVERRIDE: + + Spanner column usage reflection doesn't support determenistic + ordering. Overriding the test to check that columns are + reflected correctly, without considering their order. + """ + # test for issue #5661 + meta = self.metadata + insp = inspect(meta.bind) + foreign_keys = insp.get_foreign_keys(self.tables.tb2.name) + eq_(len(foreign_keys), 1) + fkey1 = foreign_keys[0] + eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) + eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) + + class RowFetchTest(_RowFetchTest): def test_row_w_scalar_select(self): """ From 847121ac32c0caa2b1862e8828a5b0d8efa21c6c Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 21 Apr 2021 18:54:03 +0300 Subject: [PATCH 048/582] feat: set sequence as an unsupported feature (#57) --- .../cloud/sqlalchemy_spanner/requirements.py | 4 +++ .../sqlalchemy-spanner/test/test_suite.py | 32 ++++--------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 1ef7af9b2686..3ec9f7a00a00 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -49,6 +49,10 @@ def ctes(self): def isolation_level(self): return exclusions.open() + @property + def sequences(self): + return exclusions.closed() + def get_order_by_collation(self, _): """Get the default collation name. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 509fbef699c9..016ffd1584c3 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -57,6 +57,7 @@ from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest @@ -97,12 +98,6 @@ TimestampMicrosecondsTest, ) -from sqlalchemy.testing.suite.test_sequence import ( - SequenceCompilerTest as _SequenceCompilerTest, - HasSequenceTest as _HasSequenceTest, - SequenceTest as _SequenceTest, -) - config.test_schema = "" @@ -556,26 +551,6 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): assert value in output -@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") -class SequenceCompilerTest(_SequenceCompilerTest): - pass - - -@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") -class HasSequenceTest(_HasSequenceTest): - pass - - -@pytest.mark.skip("Spanner doesn't support CREATE SEQUENCE.") -class SequenceTest(_SequenceTest): - pass - - -@pytest.mark.skip("Spanner doesn't support quotes in table names.") -class QuotedNameArgumentTest(_QuotedNameArgumentTest): - pass - - class ComponentReflectionTest(_ComponentReflectionTest): @classmethod def define_temp_tables(cls, metadata): @@ -857,3 +832,8 @@ def test_nolength_binary(self): foo.create(config.db) foo.drop(config.db) + + +@pytest.mark.skip("Spanner doesn't support quotes in table names.") +class QuotedNameArgumentTest(_QuotedNameArgumentTest): + pass From bea98b76a974687dc954bc4c5865b28d50ae4422 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 21 Apr 2021 18:58:46 +0300 Subject: [PATCH 049/582] feat: add identifiers compiler (#53) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 23 +++++++++++++++++-- .../sqlalchemy-spanner/test/test_suite.py | 10 ++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 3c9d649637cd..dc9c24b7ae76 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -21,7 +21,9 @@ selectable, DDLCompiler, GenericTypeCompiler, + IdentifierPreparer, SQLCompiler, + RESERVED_WORDS, ) from google.cloud import spanner_dbapi @@ -87,6 +89,21 @@ def wrapper(self, connection, *args, **kwargs): return wrapper +class SpannerIdentifierPreparer(IdentifierPreparer): + """Identifiers compiler. + + In Cloud Spanner backticks "`" are used for keywords escaping. + """ + + reserved_words = RESERVED_WORDS.copy() + reserved_words.update(spanner_dbapi.parse_utils.SPANNER_RESERVED_KEYWORDS) + + def __init__(self, dialect): + super(SpannerIdentifierPreparer, self).__init__( + dialect, initial_quote="`", final_quote="`" + ) + + class SpannerSQLCompiler(SQLCompiler): """Spanner SQL statements compiler.""" @@ -131,12 +148,13 @@ def visit_drop_table(self, drop_table): for cons in drop_table.element.constraints: if isinstance(cons, ForeignKeyConstraint) and cons.name: constrs += "ALTER TABLE {table} DROP CONSTRAINT {constr};".format( - table=drop_table.element.name, constr=cons.name + table=drop_table.element.name, + constr=self.preparer.quote(cons.name), ) indexes = "" for index in drop_table.element.indexes: - indexes += "DROP INDEX {};".format(index.name) + indexes += "DROP INDEX {};".format(self.preparer.quote(index.name)) return indexes + constrs + str(drop_table) @@ -246,6 +264,7 @@ class SpannerDialect(DefaultDialect): supports_native_boolean = True ddl_compiler = SpannerDDLCompiler + preparer = SpannerIdentifierPreparer statement_compiler = SpannerSQLCompiler type_compiler = SpannerTypeCompiler diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 016ffd1584c3..4fd6ca7ef9d9 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -610,7 +610,7 @@ def _test_get_unique_constraints(self, schema=None): key=operator.itemgetter("name"), ) orig_meta = self.metadata - table = Table( + Table( "testtbl", orig_meta, Column("a", sqlalchemy.String(20)), @@ -619,12 +619,12 @@ def _test_get_unique_constraints(self, schema=None): # reserved identifiers Column("asc", sqlalchemy.String(30)), Column("key", sqlalchemy.String(30)), + sqlalchemy.Index("unique_a", "a", unique=True), + sqlalchemy.Index("unique_a_b_c", "a", "b", "c", unique=True), + sqlalchemy.Index("unique_c_a_b", "c", "a", "b", unique=True), + sqlalchemy.Index("unique_asc_key", "asc", "key", unique=True), schema=schema, ) - for uc in uniques: - table.append_constraint( - sqlalchemy.Index(uc["name"], *uc["column_names"], unique=True) - ) orig_meta.create_all() inspector = inspect(orig_meta.bind) From 8048afc3e9b245d338700a760f18b17fcb7811bc Mon Sep 17 00:00:00 2001 From: skuruppu Date: Fri, 23 Apr 2021 09:21:16 +1000 Subject: [PATCH 050/582] fix: update circleci config to run tests (#43) Co-authored-by: Ilya Gurov Co-authored-by: Alex <7764119+AVaksman@users.noreply.github.com> --- packages/sqlalchemy-spanner/.circleci/config.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/.circleci/config.yml b/packages/sqlalchemy-spanner/.circleci/config.yml index 23c416210178..eabed9f35111 100644 --- a/packages/sqlalchemy-spanner/.circleci/config.yml +++ b/packages/sqlalchemy-spanner/.circleci/config.yml @@ -1,19 +1,17 @@ version: 2.1 orbs: - python: circleci/python@3.8.0 + python: circleci/python@1.3.3 jobs: build-and-test: executor: python/default steps: - checkout - - python/load-cache - - python/install-deps - - python/save-cache - - run: - command: ./manage.py test - name: Test + - run: sudo apt install python3.8 + - run: echo $GCLOUD_SERVICE_KEY > "$GOOGLE_APPLICATION_CREDENTIALS" + - run: python3 -m pip install nox + - run: python3 -m nox workflows: main: From 5f7c8b8242ce3e260a7bf5465e40880a346b34aa Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 27 Apr 2021 10:03:38 +0300 Subject: [PATCH 051/582] test: check if a test instance exists before creating it (#59) --- .../.github/workflows/test_suite.yml | 30 ------------------- .../create_test_database.py | 13 ++++---- 2 files changed, 7 insertions(+), 36 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.github/workflows/test_suite.yml diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml deleted file mode 100644 index 46514181a962..000000000000 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ /dev/null @@ -1,30 +0,0 @@ -on: - push: - branches: - - master - pull_request: -name: SQLAlchemy Spanner dialect -jobs: - tests: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Install nox - run: python -m pip install nox - - name: Run SQLAlchemy tests - run: nox - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 98ad2f64f36e..5cf6e9ebf22c 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -25,11 +25,12 @@ client = Client(project=project) config = f"{client.project_name}/instanceConfigs/regional-us-central1" - instance = client.instance("sqlalchemy-dialect-test", config) -created_op = instance.create() -created_op.result(120) # block until completion -database = instance.database("compliance-test") -created_op = database.create() -created_op.result(120) +if not instance.exists(): + created_op = instance.create() + created_op.result(120) # block until completion + + database = instance.database("compliance-test") + created_op = database.create() + created_op.result(120) From 8d86b3a8f2d554aef595113cdc21b61b468eb0fe Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 29 Apr 2021 12:39:30 +0300 Subject: [PATCH 052/582] fix: don't escape collation name (#60) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index dc9c24b7ae76..7086e4369b58 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -17,6 +17,7 @@ from sqlalchemy import types, ForeignKeyConstraint from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy import util from sqlalchemy.sql.compiler import ( selectable, DDLCompiler, @@ -103,6 +104,19 @@ def __init__(self, dialect): dialect, initial_quote="`", final_quote="`" ) + def _requires_quotes(self, value): + """Return True if the given identifier requires quoting.""" + lc_value = value.lower() + if lc_value == '"unicode"': # don't escape default Spanner colation + return False + + return ( + lc_value in self.reserved_words + or value[0] in self.illegal_initial_characters + or not self.legal_characters.match(util.text_type(value)) + or (lc_value != value) + ) + class SpannerSQLCompiler(SQLCompiler): """Spanner SQL statements compiler.""" From 55816ea42c1147d4adb8f5b65578e895a37c97fa Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 29 Apr 2021 12:41:09 +0300 Subject: [PATCH 053/582] test: skip composite grouping tests (#61) --- packages/sqlalchemy-spanner/test/test_suite.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 4fd6ca7ef9d9..3e2d533007ee 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -83,6 +83,7 @@ from sqlalchemy.testing.suite.test_select import ( IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, ) +from sqlalchemy.testing.suite.test_select import OrderByLabelTest as _OrderByLabelTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest from sqlalchemy.testing.suite.test_types import _LiteralRoundTripFixture @@ -823,6 +824,11 @@ class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): pass +@pytest.mark.skip("Spanner doesn't support composed GROUP BY") +class OrderByLabelTest(_OrderByLabelTest): + pass + + class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): __backend__ = True From e298da0e759e457c6d3de07a5eaa58c5622e35c4 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 11 May 2021 10:17:12 +0530 Subject: [PATCH 054/582] fix: prevent transaction rollback error at teardown (#68) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 7086e4369b58..54282876ddde 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -685,3 +685,15 @@ def get_isolation_level(self, conn_proxy): conn = conn_proxy.connection return "AUTOCOMMIT" if conn.autocommit else "SERIALIZABLE" + + def do_rollback(self, dbapi_connection): + """To prevent transaction rollback error, rollback is ignored if + DBAPI rollback is already executed.""" + if ( + not isinstance(dbapi_connection, spanner_dbapi.Connection) + and dbapi_connection.connection._transaction + and dbapi_connection.connection._transaction.rolled_back + ): + pass + else: + dbapi_connection.rollback() From cb839de3e8dd9f5832eaae1fbd38284e3619af53 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 11 May 2021 11:53:40 +0530 Subject: [PATCH 055/582] test: fix string compliance tests (#23) * test: fix string compliance tests * test: nit * fix: nit * fix: remove override methods and add default value * fix: add default value MAX * test: fix nit * test: add logic for additional escape ti fox the test * test: add condition check for other data type * test: remove override tests Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> Co-authored-by: Alex <7764119+AVaksman@users.noreply.github.com> --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 28 ++++++++++++++++++- .../sqlalchemy-spanner/test/test_suite.py | 9 +++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 54282876ddde..3454c95fc132 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -137,6 +137,32 @@ def visit_empty_set_expr(self, type_): _type_map_inv[type(type_[0])] ) + def render_literal_value(self, value, type_): + """Render the value of a bind parameter as a quoted literal. + + This is used for statement sections that do not accept bind parameters + on the target driver/database. + + This should be implemented by subclasses using the quoting services + of the DBAPI. + + Cloud spanner supports prefixed backslash to escape non-alphanumeric characters + in string. Override the method to add additional escape before using it to + generate a SQL statement. + """ + raw = ["\\", "'", '"', "\n", "\t", "\r"] + if type(value) == str and any(single in value for single in raw): + value = 'r"""{}"""'.format(value) + return value + else: + processor = type_._cached_literal_processor(self.dialect) + if processor: + return processor(value) + else: + raise NotImplementedError( + "Don't know how to literal-quote value %r" % value + ) + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" @@ -183,7 +209,7 @@ def visit_primary_key_constraint(self, constraint): return None def visit_unique_constraint(self, constraint): - """Unique contraints in Spanner are defined with indexes: + """Unique constraints in Spanner are defined with indexes: https://cloud.google.com/spanner/docs/secondary-indexes#unique-indexes The method throws an exception to notify user that in diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 3e2d533007ee..b0d48f111e34 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -86,6 +86,8 @@ from sqlalchemy.testing.suite.test_select import OrderByLabelTest as _OrderByLabelTest from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest +from sqlalchemy.testing.suite.test_types import StringTest as _StringTest + from sqlalchemy.testing.suite.test_types import _LiteralRoundTripFixture from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 @@ -535,7 +537,6 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): ) ) conn.execute(ins) - conn.execute("SELECT 1") if self.supports_whereclause: stmt = t.select().where(t.c.x == literal(value)) @@ -843,3 +844,9 @@ def test_nolength_binary(self): @pytest.mark.skip("Spanner doesn't support quotes in table names.") class QuotedNameArgumentTest(_QuotedNameArgumentTest): pass + + +class StringTest(_StringTest): + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass From 76a1d4a22af9de83e7a2bfba8579729d5c374de4 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 12 May 2021 07:28:52 +0530 Subject: [PATCH 056/582] test: fix get table name test for foreign keys (#63) * fix: get table name fks test * fix: nit --- packages/sqlalchemy-spanner/test/test_suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index b0d48f111e34..861f09926432 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -724,8 +724,8 @@ def _test_get_table_names(self, schema=None, table_type="table", order_by=None): table_names = [t for t in tables if t not in _ignore_tables] if order_by == "foreign_key": - answer = ["users", "user_tmp", "email_addresses", "dingalings"] - eq_(table_names, answer) + answer = {"dingalings", "email_addresses", "user_tmp", "users"} + eq_(set(table_names), answer) else: answer = ["dingalings", "email_addresses", "user_tmp", "users"] eq_(sorted(table_names), answer) From b7f7acf8b96d80ae6e632c59e84537be2e359b77 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 12 May 2021 08:08:08 +0530 Subject: [PATCH 057/582] test: fix insert test (#62) * test: skip autoincrement test * test: enable advance tests * test: remove advance tests Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../sqlalchemy-spanner/test/test_suite.py | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 861f09926432..5b856cd2d45e 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -25,6 +25,7 @@ from sqlalchemy import MetaData from sqlalchemy.schema import DDL from sqlalchemy.testing import config +from sqlalchemy.testing import engines from sqlalchemy.testing import db from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures @@ -811,14 +812,36 @@ def test_empty_insert(self): def test_insert_from_select_autoinc(self): pass - @pytest.mark.skip("Spanner doesn't support auto increment") - def test_insert_from_select_autoinc_no_rows(self): - pass - @pytest.mark.skip("Spanner doesn't support default column values") def test_insert_from_select_with_defaults(self): pass + def test_autoclose_on_insert(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support tables with an auto increment primary key, + following insertions will fail with `400 id must not be NULL in table + autoinc_pk`. + + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + if config.requirements.returning.enabled: + engine = engines.testing_engine(options={"implicit_returning": False}) + else: + engine = config.db + + with engine.begin() as conn: + r = conn.execute( + self.tables.autoinc_pk.insert(), dict(id=1, data="some data") + ) + + assert r._soft_closed + assert not r.closed + assert r.is_insert + assert not r.returns_rows + @pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): From a57bb8c5dac3e52bad90b35c0ca75f7703329cc3 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 12 May 2021 08:33:44 +0530 Subject: [PATCH 058/582] test: add text compliance tests (#36) * test: add text compliance tests * test: enable skipped test * test: nit Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../sqlalchemy-spanner/test/test_suite.py | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 5b856cd2d45e..9c703ed44436 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -88,7 +88,7 @@ from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest from sqlalchemy.testing.suite.test_types import StringTest as _StringTest - +from sqlalchemy.testing.suite.test_types import TextTest as _TextTest from sqlalchemy.testing.suite.test_types import _LiteralRoundTripFixture from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 @@ -873,3 +873,57 @@ class StringTest(_StringTest): @pytest.mark.skip("Spanner doesn't support non-ascii characters") def test_literal_non_ascii(self): pass + + +class TextTest(_TextTest): + def test_text_empty_strings(self, connection): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support the tables with an empty primary key + when column has defined NOT NULL - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + text_table = self.tables.text_table + + connection.execute(text_table.insert(), {"id": 1, "text_data": ""}) + row = connection.execute(select([text_table.c.text_data])).first() + eq_(row, ("",)) + + def test_text_null_strings(self, connection): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support the tables with an empty primary key + when column has defined NOT NULL - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + text_table = self.tables.text_table + + connection.execute(text_table.insert(), {"id": 1, "text_data": None}) + row = connection.execute(select([text_table.c.text_data])).first() + eq_(row, (None,)) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + def test_text_roundtrip(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support the tables with an empty primary key + when column has defined NOT NULL - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + text_table = self.tables.text_table + + config.db.execute(text_table.insert(), {"id": 1, "text_data": "some text"}) + row = config.db.execute(select([text_table.c.text_data])).first() + eq_(row, ("some text",)) From 9591811a41832b80cf30d704696217154a6b9252 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Wed, 12 May 2021 16:03:51 +0530 Subject: [PATCH 059/582] test: unicode compliance tests (#41) * test: unicode compliance tests * test: enable skipped test --- .../sqlalchemy-spanner/test/test_suite.py | 105 +++++++++++++++++- 1 file changed, 99 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 9c703ed44436..49f789d99932 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -85,21 +85,23 @@ IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, ) from sqlalchemy.testing.suite.test_select import OrderByLabelTest as _OrderByLabelTest -from sqlalchemy.testing.suite.test_types import BooleanTest as _BooleanTest -from sqlalchemy.testing.suite.test_types import IntegerTest as _IntegerTest -from sqlalchemy.testing.suite.test_types import StringTest as _StringTest -from sqlalchemy.testing.suite.test_types import TextTest as _TextTest -from sqlalchemy.testing.suite.test_types import _LiteralRoundTripFixture - from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 + BooleanTest as _BooleanTest, DateTest as _DateTest, DateTimeHistoricTest, DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, DateTimeTest as _DateTimeTest, + IntegerTest as _IntegerTest, + _LiteralRoundTripFixture, + StringTest as _StringTest, + TextTest as _TextTest, TimeTest as _TimeTest, TimeMicrosecondsTest as _TimeMicrosecondsTest, TimestampMicrosecondsTest, + UnicodeVarcharTest as _UnicodeVarcharTest, + UnicodeTextTest as _UnicodeTextTest, + _UnicodeFixture as _UnicodeFixtureTest, ) config.test_schema = "" @@ -554,6 +556,97 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): assert value in output +class UnicodeFixtureTest(_UnicodeFixtureTest): + def test_round_trip(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support the tables with an empty primary key + when column has defined NOT NULL - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures and deleting the table at the end. + """ + unicode_table = self.tables.unicode_table + + config.db.execute(unicode_table.insert(), {"id": 1, "unicode_data": self.data}) + + row = config.db.execute(select([unicode_table.c.unicode_data])).first() + + eq_(row, (self.data,)) + assert isinstance(row[0], util.text_type) + + def test_round_trip_executemany(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support the tables with an empty primary key + when column has defined NOT NULL - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures and deleting the table at the end. + """ + unicode_table = self.tables.unicode_table + + config.db.execute( + unicode_table.insert(), + [{"id": i, "unicode_data": self.data} for i in range(3)], + ) + + rows = config.db.execute(select([unicode_table.c.unicode_data])).fetchall() + eq_(rows, [(self.data,) for i in range(3)]) + for row in rows: + assert isinstance(row[0], util.text_type) + + def _test_null_strings(self, connection): + unicode_table = self.tables.unicode_table + + connection.execute(unicode_table.insert(), {"id": 1, "unicode_data": None}) + row = connection.execute(select([unicode_table.c.unicode_data])).first() + eq_(row, (None,)) + + def _test_empty_strings(self, connection): + unicode_table = self.tables.unicode_table + + connection.execute( + unicode_table.insert(), {"id": 1, "unicode_data": util.u("")} + ) + row = connection.execute(select([unicode_table.c.unicode_data])).first() + eq_(row, (util.u(""),)) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal(self): + pass + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + +class UnicodeVarcharTest(UnicodeFixtureTest, _UnicodeVarcharTest): + """ + SPANNER OVERRIDE: + + UnicodeVarcharTest class inherits the _UnicodeFixtureTest class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +class UnicodeTextTest(UnicodeFixtureTest, _UnicodeTextTest): + """ + SPANNER OVERRIDE: + + UnicodeTextTest class inherits the _UnicodeFixtureTest class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + class ComponentReflectionTest(_ComponentReflectionTest): @classmethod def define_temp_tables(cls, metadata): From 7e6d621317c1b8c5599a1cc011cfb91055a1ce17 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 12 May 2021 14:54:06 +0300 Subject: [PATCH 060/582] feat: support OFFSET without explicit LIMIT clause (#40) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 3454c95fc132..42d66a8afd49 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -163,6 +163,33 @@ def render_literal_value(self, value, type_): "Don't know how to literal-quote value %r" % value ) + def limit_clause(self, select, **kw): + """Build LIMIT-OFFSET clause. + + Spanner doesn't support using OFFSET without a LIMIT + clause. It also doesn't support negative LIMITs, while + SQLAlchemy support both. + + The method builds LIMIT-OFFSET clauses as usual, with + only difference: when OFFSET is used without an explicit + LIMIT, the dialect compiles a statement with a LIMIT + set to the biggest integer value. + + Args: + (sqlalchemy.sql.selectable.Select): Select clause object. + + Returns: + str: LIMIT-OFFSET clause. + """ + text = "" + if select._limit_clause is not None: + text += "\n LIMIT " + self.process(select._limit_clause, **kw) + if select._offset_clause is not None: + if select._limit_clause is None: + text += "\n LIMIT 9223372036854775805" + text += " OFFSET " + self.process(select._offset_clause, **kw) + return text + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" From 3c91fc0b71153dc958321c834ecef1891572c6ae Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Thu, 13 May 2021 08:36:27 +0530 Subject: [PATCH 061/582] test: fix numeric compliance test (#29) * test: fix numeric compliance test * fix: skip tests * fix: remove override methods * test: add override reason * test: close the property Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../cloud/sqlalchemy_spanner/requirements.py | 6 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 7 +- .../sqlalchemy-spanner/test/test_suite.py | 339 +++++++++++++++++- 3 files changed, 339 insertions(+), 13 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 3ec9f7a00a00..1b9298478151 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -68,3 +68,9 @@ def get_isolation_levels(self, _): dict: isolation levels description. """ return {"default": "SERIALIZABLE", "supported": ["SERIALIZABLE", "AUTOCOMMIT"]} + + @property + def precision_numerics_enotation_large(self): + """target backend supports Decimal() objects using E notation + to represent very large values.""" + return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 42d66a8afd49..cd4a1572d3e2 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -288,9 +288,6 @@ def visit_large_binary(self, type_, **kw): def visit_DECIMAL(self, type_, **kw): return "NUMERIC" - def visit_NUMERIC(self, type_, **kw): - return "NUMERIC" - def visit_VARCHAR(self, type_, **kw): return "STRING({})".format(type_.length or "MAX") @@ -303,6 +300,9 @@ def visit_BOOLEAN(self, type_, **kw): def visit_DATETIME(self, type_, **kw): return "TIMESTAMP" + def visit_NUMERIC(self, type_, **kw): + return "NUMERIC" + def visit_BIGINT(self, type_, **kw): return "INT64" @@ -329,6 +329,7 @@ class SpannerDialect(DefaultDialect): supports_sequences = True supports_native_enum = True supports_native_boolean = True + supports_native_decimal = True ddl_compiler = SpannerDDLCompiler preparer = SpannerIdentifierPreparer diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 49f789d99932..3904f1593a59 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -16,6 +16,7 @@ import operator import pytest +import decimal import pytz import sqlalchemy @@ -28,8 +29,8 @@ from sqlalchemy.testing import engines from sqlalchemy.testing import db from sqlalchemy.testing import eq_ +from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures -from sqlalchemy.testing import provide_metadata from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -41,8 +42,9 @@ from sqlalchemy import util from sqlalchemy import event from sqlalchemy import exists -from sqlalchemy import LargeBinary from sqlalchemy import Boolean +from sqlalchemy import Float +from sqlalchemy import LargeBinary from sqlalchemy import String from sqlalchemy.types import Integer from sqlalchemy.types import Numeric @@ -94,6 +96,7 @@ DateTimeTest as _DateTimeTest, IntegerTest as _IntegerTest, _LiteralRoundTripFixture, + NumericTest as _NumericTest, StringTest as _StringTest, TextTest as _TextTest, TimeTest as _TimeTest, @@ -514,19 +517,18 @@ def _literal_round_trip(self, type_, input_, output, filter_=None): """ SPANNER OVERRIDE: - Spanner DBAPI does not execute DDL statements unless followed by a - non DDL statement, which is preventing correct table clean up. - The table already exists after related tests finish, so it doesn't - create a new table and when running tests for other data types - insertions will fail with `400 Duplicate name in schema: t`. - Overriding the tests to create and drop a new table to prevent - database existence errors. - """ + Spanner is not able cleanup data and drop the table correctly, + table was already exists after related tests finished, so it doesn't + create a new table and when started tests for other data type following + insertions will fail with `400 Duplicate name in schema: t. + Overriding the tests to create a new table for test and drop table manually + before it creates a new table to avoid the same failures.""" # for literal, we test the literal render in an INSERT # into a typed column. we can then SELECT it back as its # official type; ideally we'd be able to use CAST here # but MySQL in particular can't CAST fully + t = Table("int_t", self.metadata, Column("x", type_)) t.create() @@ -1020,3 +1022,320 @@ def test_text_roundtrip(self): config.db.execute(text_table.insert(), {"id": 1, "text_data": "some text"}) row = config.db.execute(select([text_table.c.text_data])).first() eq_(row, ("some text",)) + + +class NumericTest(_NumericTest): + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._literal_round_trip( + Numeric(precision=8, scale=4), [15.7563], [decimal.Decimal("15.7563")], + ) + self._literal_round_trip( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric_asfloat(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._literal_round_trip( + Numeric(precision=8, scale=4, asdecimal=False), [15.7563], [15.7563], + ) + self._literal_round_trip( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563")], + [15.7563], + ) + + def test_render_literal_float(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._literal_round_trip( + Float(4), + [decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + self._literal_round_trip( + Float(4), + [decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_generic_float_type + def test_float_custom_scale(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._do_test( + Float(None, decimal_return_scale=7, asdecimal=True), + [15.7563827], + [decimal.Decimal("15.7563827")], + check_scale=True, + ) + + self._do_test( + Float(None, decimal_return_scale=7, asdecimal=True), + [15.7563827], + [decimal.Decimal("15.7563827")], + check_scale=True, + ) + + def test_numeric_as_decimal(self): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + self._do_test( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + def test_numeric_as_float(self): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + + self._do_test( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563")], + [15.7563], + ) + + @requires.floats_to_four_decimals + def test_float_as_decimal(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._do_test( + Float(precision=8, asdecimal=True), [15.7563], [decimal.Decimal("15.7563")], + ) + + self._do_test( + Float(precision=8, asdecimal=True), + [decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + def test_float_as_float(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + self._do_test( + Float(precision=8), + [15.7563], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + self._do_test( + Float(precision=8), + [decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_numerics_general + def test_precision_decimal(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + + Remove an extra digits after decimal point as cloud spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("54.234246451")], + [decimal.Decimal("54.234246451")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("0.004354")], + [decimal.Decimal("0.004354")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("900.0")], + [decimal.Decimal("900.0")], + ) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal_large(self): + """test exceedingly large decimals. + + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + + self._do_test( + Numeric(precision=25, scale=2), + [decimal.Decimal("4E+8")], + [decimal.Decimal("4E+8")], + ) + + self._do_test( + Numeric(precision=25, scale=2), + [decimal.Decimal("5748E+15")], + [decimal.Decimal("5748E+15")], + ) + + self._do_test( + Numeric(precision=25, scale=2), + [decimal.Decimal("1.521E+15")], + [decimal.Decimal("1.521E+15")], + ) + + self._do_test( + Numeric(precision=25, scale=2), + [decimal.Decimal("00000000000000.1E+12")], + [decimal.Decimal("00000000000000.1E+12")], + ) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal(self): + """test exceedingly small decimals. + + Decimal reports values with E notation when the exponent + is greater than 6. + + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + + Remove extra digits after decimal point as cloud spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-2")], + [decimal.Decimal("1E-2")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-3")], + [decimal.Decimal("1E-3")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-4")], + [decimal.Decimal("1E-4")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-5")], + [decimal.Decimal("1E-5")], + ) + + self._do_test( + Numeric(precision=18, scale=14), + [decimal.Decimal("1E-6")], + [decimal.Decimal("1E-6")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-7")], + [decimal.Decimal("1E-7")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("1E-8")], + [decimal.Decimal("1E-8")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("0.010000059")], + [decimal.Decimal("0.010000059")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("0.000000059")], + [decimal.Decimal("0.000000059")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("0.000000696")], + [decimal.Decimal("0.000000696")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("0.700000696")], + [decimal.Decimal("0.700000696")], + ) + + self._do_test( + Numeric(precision=18, scale=9), + [decimal.Decimal("696E-9")], + [decimal.Decimal("696E-9")], + ) From df9ab9bd1df2ad884b665c28e986cba76a295510 Mon Sep 17 00:00:00 2001 From: Alex <7764119+AVaksman@users.noreply.github.com> Date: Thu, 13 May 2021 01:27:47 -0400 Subject: [PATCH 062/582] ci: delete old instances (#65) * feat: delete old instances * fix: capitalize constants Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../create_test_database.py | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 5cf6e9ebf22c..d4a523de2b79 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -15,22 +15,62 @@ # limitations under the License. import os +import time from google.cloud.spanner_v1 import Client +from google.cloud.spanner_v1.instance import Instance -project = os.getenv( + +USE_EMULATOR = os.getenv("SPANNER_EMULATOR_HOST") is not None + +PROJECT = os.getenv( "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), ) +CLIENT = None + +if USE_EMULATOR: + from google.auth.credentials import AnonymousCredentials + CLIENT = Client( + project=PROJECT, credentials=AnonymousCredentials() + ) +else: + CLIENT = Client(project=PROJECT) + -client = Client(project=project) +def reap_old_instances(): + # Delete test instances that are older than four hours. + cutoff = int(time.time()) - 4 * 60 * 60 + instances_pbs = CLIENT.list_instances("labels.python-spanner-sqlalchemy-systest:true") + for instance_pb in instances_pbs: + instance = Instance.from_pb(instance_pb, CLIENT) + if "created" not in instance.labels: + continue + create_time = int(instance.labels["created"]) + if create_time > cutoff: + continue + # Backups are not used in sqlalchemy dialect test, therefore instance can just be deleted. + instance.delete() -config = f"{client.project_name}/instanceConfigs/regional-us-central1" -instance = client.instance("sqlalchemy-dialect-test", config) -if not instance.exists(): +def prep_instance(): + configs = list(CLIENT.list_instance_configs()) + # Filter out non "us" locations + configs = [config for config in configs if "-us-" in config.name] + + instance_config = configs[0].name + create_time = str(int(time.time())) + unique_resource_id = '%s%d' % ('-', 1000 * time.time()) + instance_id = "sqlalchemy-test" + unique_resource_id + labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} + + instance = CLIENT.instance(instance_id, instance_config, labels=labels) + created_op = instance.create() created_op.result(120) # block until completion database = instance.database("compliance-test") created_op = database.create() created_op.result(120) + +reap_old_instances() +prep_instance() From 9a23ab4199c532df394ec85a29525eed49313fa4 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 18 May 2021 10:48:22 +0300 Subject: [PATCH 063/582] test: add a migration nox testing session (#69) --- packages/sqlalchemy-spanner/noxfile.py | 84 ++++++++++++++++++- .../sqlalchemy-spanner/test_migration_env.py | 80 ++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/test_migration_env.py diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index bb2ed3d1bd13..7e0eef6209d7 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -18,10 +18,51 @@ import nox +ALEMBIC_CONF = """ +[alembic] +script_location = test_migration +prepend_sys_path = . +sqlalchemy.url = spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test +[post_write_hooks] +[loggers] +keys = root,sqlalchemy,alembic +[handlers] +keys = console +[formatters] +keys = generic +[logger_root] +level = WARN +handlers = console +qualname = +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine +[logger_alembic] +level = INFO +handlers = +qualname = alembic +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S +""" + +UPGRADE_CODE = """def upgrade(): + op.create_table( + 'account', + sa.Column('id', sa.Integer, primary_key=True), + sa.Column('name', sa.String(50), nullable=False), + sa.Column('description', sa.Unicode(200)), + )""" + BLACK_VERSION = "black==19.10b0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py"] - DEFAULT_PYTHON_VERSION = "3.8" @@ -75,3 +116,44 @@ def compliance_test(session): session.install("-e", ".") session.run("python", "create_test_database.py") session.run("pytest", "-v") + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def migration_test(session): + """Migrate with SQLAlchemy and Alembic and check the result.""" + import glob + import os + import shutil + + session.install("pytest") + session.install("sqlalchemy") + session.install("google-cloud-spanner") + session.install("-e", ".") + session.install("alembic") + session.run("alembic", "init", "test_migration") + + # setting testing configurations + os.remove("alembic.ini") + with open("alembic.ini", "w") as f: + f.write(ALEMBIC_CONF) + + session.run("alembic", "revision", "-m", "migration_for_test") + files = glob.glob("test_migration/versions/*.py") + + # updating the upgrade-script code + with open(files[0], "r") as f: + script_code = f.read() + + script_code = script_code.replace("""def upgrade():\n pass""", UPGRADE_CODE) + with open(files[0], "w") as f: + f.write(script_code) + + os.remove("test_migration/env.py") + shutil.copyfile("test_migration_env.py", "test_migration/env.py") + + # running the test migration + session.run("alembic", "upgrade", "head") + + # clearing the migration data + os.remove("alembic.ini") + shutil.rmtree("test_migration") diff --git a/packages/sqlalchemy-spanner/test_migration_env.py b/packages/sqlalchemy-spanner/test_migration_env.py new file mode 100644 index 000000000000..883ebc1e0145 --- /dev/null +++ b/packages/sqlalchemy-spanner/test_migration_env.py @@ -0,0 +1,80 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context +from alembic.ddl.impl import DefaultImpl + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = None + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +class SpannerImpl(DefaultImpl): + __dialect__ = "spanner" + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure(connection=connection, target_metadata=target_metadata) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() From 4da88484e921b1e7b85faf5af3142276276dbdc7 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 18 May 2021 13:44:45 +0300 Subject: [PATCH 064/582] test: drop alembic tables after migration test is over (#70) --- .../migration_test_cleanup.py | 24 +++++++++++++++++++ packages/sqlalchemy-spanner/noxfile.py | 1 + 2 files changed, 25 insertions(+) create mode 100644 packages/sqlalchemy-spanner/migration_test_cleanup.py diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py new file mode 100644 index 000000000000..9f4d729b369c --- /dev/null +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud import spanner + +client = spanner.Client() + +instance = client.instance("sqlalchemy-dialect-test") +database = instance.database("compliance-test") + +database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 7e0eef6209d7..0446691db059 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -157,3 +157,4 @@ def migration_test(session): # clearing the migration data os.remove("alembic.ini") shutil.rmtree("test_migration") + session.run("python", "migration_test_cleanup.py") From 9ac5cd74eee7dbe89507bf1cf21581c989ede967 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 18 May 2021 19:15:28 +0530 Subject: [PATCH 065/582] test: select compliance tests (#47) * test: select compliance tests * test: enable more tests * test: remove test skip of null datatype * test: remove redundant code * test: add issue reference Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../sqlalchemy-spanner/test/test_suite.py | 107 ++++++++++++++---- 1 file changed, 83 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 3904f1593a59..1e31e3c65b5a 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -60,6 +60,7 @@ from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 @@ -72,21 +73,19 @@ from sqlalchemy.testing.suite.test_insert import ( InsertBehaviorTest as _InsertBehaviorTest, ) -from sqlalchemy.testing.suite.test_reflection import ( - ComponentReflectionTest as _ComponentReflectionTest, +from sqlalchemy.testing.suite.test_select import ( # noqa: F401, F403 + CompoundSelectTest as _CompoundSelectTest, + ExistsTest as _ExistsTest, + IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, + LikeFunctionsTest as _LikeFunctionsTest, + OrderByLabelTest as _OrderByLabelTest, ) from sqlalchemy.testing.suite.test_reflection import ( QuotedNameArgumentTest as _QuotedNameArgumentTest, -) -from sqlalchemy.testing.suite.test_reflection import ( + ComponentReflectionTest as _ComponentReflectionTest, CompositeKeyReflectionTest as _CompositeKeyReflectionTest, ) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest -from sqlalchemy.testing.suite.test_select import ExistsTest as _ExistsTest -from sqlalchemy.testing.suite.test_select import ( - IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, -) -from sqlalchemy.testing.suite.test_select import OrderByLabelTest as _OrderByLabelTest from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 BooleanTest as _BooleanTest, DateTest as _DateTest, @@ -938,16 +937,6 @@ def test_autoclose_on_insert(self): assert not r.returns_rows -@pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") -class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): - pass - - -@pytest.mark.skip("Spanner doesn't support composed GROUP BY") -class OrderByLabelTest(_OrderByLabelTest): - pass - - class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): __backend__ = True @@ -959,11 +948,6 @@ def test_nolength_binary(self): foo.drop(config.db) -@pytest.mark.skip("Spanner doesn't support quotes in table names.") -class QuotedNameArgumentTest(_QuotedNameArgumentTest): - pass - - class StringTest(_StringTest): @pytest.mark.skip("Spanner doesn't support non-ascii characters") def test_literal_non_ascii(self): @@ -1339,3 +1323,78 @@ def test_enotation_decimal(self): [decimal.Decimal("696E-9")], [decimal.Decimal("696E-9")], ) + + +class LikeFunctionsTest(_LikeFunctionsTest): + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_contains_autoescape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_contains_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_contains_escape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_endswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_endswith_escape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_endswith_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_startswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_startswith_escape(self): + pass + + @pytest.mark.skip("Spanner does not support ESCAPE") + def test_startswith_autoescape_escape(self): + pass + + +@pytest.mark.skip("Spanner doesn't support quotes in table names.") +class QuotedNameArgumentTest(_QuotedNameArgumentTest): + pass + + +@pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") +class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): + pass + + +class OrderByLabelTest(_OrderByLabelTest): + @pytest.mark.skip( + "Spanner requires an alias for the GROUP BY list when specifying derived " + "columns also used in SELECT" + ) + def test_group_by_composed(self): + pass + + +class CompoundSelectTest(_CompoundSelectTest): + """ + See: https://github.com/googleapis/python-spanner/issues/347 + """ + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_limit_offset_selectable_in_unions(self): + pass + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_order_by_selectable_in_unions(self): + pass From b14cbbc64b9927d529d845233153eaf1cf0e5a56 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 19 May 2021 11:57:06 +0300 Subject: [PATCH 066/582] feat: raise exceptions for ESCAPE keyword (#64) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 11 +++++++++ .../sqlalchemy-spanner/test/test_suite.py | 24 ++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index cd4a1572d3e2..52886740dcee 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -137,6 +137,17 @@ def visit_empty_set_expr(self, type_): _type_map_inv[type(type_[0])] ) + def visit_like_op_binary(self, binary, operator, **kw): + """Build a LIKE clause.""" + if binary.modifiers.get("escape", None): + raise NotImplementedError("ESCAPE keyword is not supported by Spanner") + + # TODO: use ternary here, not "and"/ "or" + return "%s LIKE %s" % ( + binary.left._compiler_dispatch(self, **kw), + binary.right._compiler_dispatch(self, **kw), + ) + def render_literal_value(self, value, type_): """Render the value of a bind parameter as a quoted literal. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 1e31e3c65b5a..971bceeee5f0 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1326,42 +1326,48 @@ def test_enotation_decimal(self): class LikeFunctionsTest(_LikeFunctionsTest): - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_contains_autoescape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_contains_autoescape_escape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_contains_escape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_endswith_autoescape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_endswith_escape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_endswith_autoescape_escape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_startswith_autoescape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_startswith_escape(self): pass - @pytest.mark.skip("Spanner does not support ESCAPE") + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") def test_startswith_autoescape_escape(self): pass + def test_escape_keyword_raises(self): + """Check that ESCAPE keyword causes an exception when used.""" + with pytest.raises(NotImplementedError): + col = self.tables.some_table.c.data + self._test(col.contains("b##cde", escape="#"), {7}) + @pytest.mark.skip("Spanner doesn't support quotes in table names.") class QuotedNameArgumentTest(_QuotedNameArgumentTest): From fcef3959cda55f7d6742c992410cf4b50cb92816 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 21 May 2021 03:26:37 +0300 Subject: [PATCH 067/582] docs: update README.md (#73) --- packages/sqlalchemy-spanner/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 0eafe70a3845..020fb20135a8 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -93,6 +93,9 @@ Migration ----------- SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. +**Warning!** +A migration script can produce a lot of DDL statements. In case of executing every one of them separately performance and budget spending issues can occur. To avoid them it's highly recommended to use [Alembic batch context](https://cloud.google.com/spanner/docs/schema-updates) feature to pack DDL statements into more economical groups of statements. + Features and limitations ----------- **Unique constraints** @@ -117,7 +120,15 @@ Table( ) ``` **Autocommit mode** -Spanner dialect supports both "autocommit" and "manual commit" modes. To set/change the current mode isolation levels can be used: `SERIALIZABLE` and `AUTOCOMMIT`. +Spanner dialect supports both `SERIALIZABLE` and `AUTOCOMMIT` isolation levels. `SERIALIZABLE` is the default one, where transactions need to be committed manually. `AUTOCOMMIT` mode corresponds to automatically committing of a query right in its execution time. + +Isolation level change example: +```python +from sqlalchemy import create_engine + +eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id") +autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") +``` **DDL and transactions** DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. From df3e5c9f627775a5d850b4582124939f13bd3340 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 25 May 2021 08:02:01 +0530 Subject: [PATCH 068/582] refactor: remove unnecessary override methods (#75) --- .../sqlalchemy-spanner/test/test_suite.py | 254 +++--------------- 1 file changed, 40 insertions(+), 214 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 971bceeee5f0..0af96baa2117 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -27,16 +27,12 @@ from sqlalchemy.schema import DDL from sqlalchemy.testing import config from sqlalchemy.testing import engines -from sqlalchemy.testing import db from sqlalchemy.testing import eq_ from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table -from sqlalchemy import bindparam -from sqlalchemy import case -from sqlalchemy import literal from sqlalchemy import literal_column from sqlalchemy import select from sqlalchemy import util @@ -89,6 +85,7 @@ from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 BooleanTest as _BooleanTest, DateTest as _DateTest, + _DateFixture as _DateFixtureTest, DateTimeHistoricTest, DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, @@ -299,116 +296,46 @@ class LongNameBlowoutTest(_LongNameBlowoutTest): pass -class DateTest(_DateTest): - def test_round_trip(self): - """ - SPANNER OVERRIDE: - - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table date_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. - """ - date_table = self.tables.date_table - - config.db.execute(date_table.insert(), {"id": 1, "date_data": self.data}) - - row = config.db.execute(select([date_table.c.date_data])).first() - - compare = self.compare or self.data - eq_(row, (compare,)) - assert isinstance(row[0], type(compare)) - - def test_null(self): - """ - SPANNER OVERRIDE: - - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table date_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. - """ - date_table = self.tables.date_table - - config.db.execute(date_table.insert(), {"id": 1, "date_data": None}) - - row = config.db.execute(select([date_table.c.date_data])).first() - eq_(row, (None,)) - - @requires.standalone_null_binds_whereclause - def test_null_bound_comparison(self): +class DateFixtureTest(_DateFixtureTest): + @classmethod + def define_tables(cls, metadata): """ SPANNER OVERRIDE: - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table date_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. """ - - # this test is based on an Oracle issue observed in #4886. - # passing NULL for an expression that needs to be interpreted as - # a certain type, does the DBAPI have the info it needs to do this. - date_table = self.tables.date_table - with config.db.connect() as conn: - result = conn.execute( - date_table.insert(), {"id": 1, "date_data": self.data} - ) - id_ = result.inserted_primary_key[0] - stmt = select([date_table.c.id]).where( - case( - [ - ( - bindparam("foo", type_=self.datatype) - != None, # noqa: E711, - bindparam("foo", type_=self.datatype), - ) - ], - else_=date_table.c.date_data, - ) - == date_table.c.date_data - ) - - row = conn.execute(stmt, {"foo": None}).first() - eq_(row[0], id_) + Table( + "date_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("date_data", cls.datatype), + ) -class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest): - def test_null(self): - """ - SPANNER OVERRIDE: +class DateTest(DateFixtureTest, _DateTest): + """ + SPANNER OVERRIDE: - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table datetime_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. - """ - date_table = self.tables.date_table + DateTest tests used same class method to create table, so to avoid those failures + and maintain DRY concept just inherit the class to run tests successfully. + """ - config.db.execute(date_table.insert(), {"id": 1, "date_data": None}) + pass - row = config.db.execute(select([date_table.c.date_data])).first() - eq_(row, (None,)) +class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest, DateTest): def test_round_trip(self): """ SPANNER OVERRIDE: - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table datetime_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. - Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid assert failures convert datetime input to the desire timestamp format. """ date_table = self.tables.date_table - config.db.execute(date_table.insert(), {"id": 1, "date_data": self.data}) + config.db.execute(date_table.insert(), {"date_data": self.data}) row = config.db.execute(select([date_table.c.date_data])).first() compare = self.compare or self.data @@ -416,43 +343,6 @@ def test_round_trip(self): eq_(row[0].rfc3339(), compare) assert isinstance(row[0], DatetimeWithNanoseconds) - @requires.standalone_null_binds_whereclause - def test_null_bound_comparison(self): - """ - SPANNER OVERRIDE: - - Cloud Spanner supports tables with an empty primary key, but only one - row can be inserted into such a table - following insertions will fail - with `400 id must not be NULL in table datetime_table`. - Overriding the tests to add a manual primary key value to avoid the same - failures. - """ - # this test is based on an Oracle issue observed in #4886. - # passing NULL for an expression that needs to be interpreted as - # a certain type, does the DBAPI have the info it needs to do this. - date_table = self.tables.date_table - with config.db.connect() as conn: - result = conn.execute( - date_table.insert(), {"id": 1, "date_data": self.data} - ) - id_ = result.inserted_primary_key[0] - stmt = select([date_table.c.id]).where( - case( - [ - ( - bindparam("foo", type_=self.datatype) - != None, # noqa: E711, - bindparam("foo", type_=self.datatype), - ) - ], - else_=date_table.c.date_data, - ) - == date_table.c.date_data - ) - - row = conn.execute(stmt, {"foo": None}).first() - eq_(row[0], id_) - class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): """ @@ -511,81 +401,33 @@ def _round_trip(self, datatype, data): else: assert isinstance(row[0], (long, int)) # noqa - @provide_metadata - def _literal_round_trip(self, type_, input_, output, filter_=None): - """ - SPANNER OVERRIDE: - - Spanner is not able cleanup data and drop the table correctly, - table was already exists after related tests finished, so it doesn't - create a new table and when started tests for other data type following - insertions will fail with `400 Duplicate name in schema: t. - Overriding the tests to create a new table for test and drop table manually - before it creates a new table to avoid the same failures.""" - - # for literal, we test the literal render in an INSERT - # into a typed column. we can then SELECT it back as its - # official type; ideally we'd be able to use CAST here - # but MySQL in particular can't CAST fully - - t = Table("int_t", self.metadata, Column("x", type_)) - t.create() - - with db.connect() as conn: - for value in input_: - ins = ( - t.insert() - .values(x=literal(value)) - .compile( - dialect=db.dialect, compile_kwargs=dict(literal_binds=True), - ) - ) - conn.execute(ins) - - if self.supports_whereclause: - stmt = t.select().where(t.c.x == literal(value)) - else: - stmt = t.select() - - stmt = stmt.compile( - dialect=db.dialect, compile_kwargs=dict(literal_binds=True), - ) - for row in conn.execute(stmt): - value = row[0] - if filter_ is not None: - value = filter_(value) - assert value in output - class UnicodeFixtureTest(_UnicodeFixtureTest): - def test_round_trip(self): + @classmethod + def define_tables(cls, metadata): """ SPANNER OVERRIDE: - Cloud Spanner doesn't support the tables with an empty primary key - when column has defined NOT NULL - following insertions will fail with - `400 id must not be NULL in table date_table`. - Overriding the tests and adding a manual primary key value to avoid the same - failures and deleting the table at the end. + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. """ - unicode_table = self.tables.unicode_table - - config.db.execute(unicode_table.insert(), {"id": 1, "unicode_data": self.data}) - - row = config.db.execute(select([unicode_table.c.unicode_data])).first() - - eq_(row, (self.data,)) - assert isinstance(row[0], util.text_type) + Table( + "unicode_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("unicode_data", cls.datatype), + ) def test_round_trip_executemany(self): """ - SPANNER OVERRIDE: + SPANNER OVERRIDE - Cloud Spanner doesn't support the tables with an empty primary key - when column has defined NOT NULL - following insertions will fail with - `400 id must not be NULL in table date_table`. - Overriding the tests and adding a manual primary key value to avoid the same - failures and deleting the table at the end. + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. """ unicode_table = self.tables.unicode_table @@ -599,22 +441,6 @@ def test_round_trip_executemany(self): for row in rows: assert isinstance(row[0], util.text_type) - def _test_null_strings(self, connection): - unicode_table = self.tables.unicode_table - - connection.execute(unicode_table.insert(), {"id": 1, "unicode_data": None}) - row = connection.execute(select([unicode_table.c.unicode_data])).first() - eq_(row, (None,)) - - def _test_empty_strings(self, connection): - unicode_table = self.tables.unicode_table - - connection.execute( - unicode_table.insert(), {"id": 1, "unicode_data": util.u("")} - ) - row = connection.execute(select([unicode_table.c.unicode_data])).first() - eq_(row, (util.u(""),)) - @pytest.mark.skip("Spanner doesn't support non-ascii characters") def test_literal(self): pass From ab3a54abd5cd3ef5c2fd47bc4810d4041b9302a2 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 25 May 2021 10:47:54 +0300 Subject: [PATCH 069/582] test: tweak test data for the Text type (#67) --- .../sqlalchemy-spanner/test/test_suite.py | 56 +++++-------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 0af96baa2117..d2e79aee5374 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -44,6 +44,7 @@ from sqlalchemy import String from sqlalchemy.types import Integer from sqlalchemy.types import Numeric +from sqlalchemy.types import Text from sqlalchemy.testing import requires from google.api_core.datetime_helpers import DatetimeWithNanoseconds @@ -781,58 +782,27 @@ def test_literal_non_ascii(self): class TextTest(_TextTest): - def test_text_empty_strings(self, connection): - """ - SPANNER OVERRIDE: - - Cloud Spanner doesn't support the tables with an empty primary key - when column has defined NOT NULL - following insertions will fail with - `400 id must not be NULL in table date_table`. - Overriding the tests and adding a manual primary key value to avoid the same - failures. - """ - text_table = self.tables.text_table - - connection.execute(text_table.insert(), {"id": 1, "text_data": ""}) - row = connection.execute(select([text_table.c.text_data])).first() - eq_(row, ("",)) - - def test_text_null_strings(self, connection): + @classmethod + def define_tables(cls, metadata): """ SPANNER OVERRIDE: - Cloud Spanner doesn't support the tables with an empty primary key - when column has defined NOT NULL - following insertions will fail with - `400 id must not be NULL in table date_table`. - Overriding the tests and adding a manual primary key value to avoid the same - failures. + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. """ - text_table = self.tables.text_table - - connection.execute(text_table.insert(), {"id": 1, "text_data": None}) - row = connection.execute(select([text_table.c.text_data])).first() - eq_(row, (None,)) + Table( + "text_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("text_data", Text), + ) @pytest.mark.skip("Spanner doesn't support non-ascii characters") def test_literal_non_ascii(self): pass - def test_text_roundtrip(self): - """ - SPANNER OVERRIDE: - - Cloud Spanner doesn't support the tables with an empty primary key - when column has defined NOT NULL - following insertions will fail with - `400 id must not be NULL in table date_table`. - Overriding the tests and adding a manual primary key value to avoid the same - failures. - """ - text_table = self.tables.text_table - - config.db.execute(text_table.insert(), {"id": 1, "text_data": "some text"}) - row = config.db.execute(select([text_table.c.text_data])).first() - eq_(row, ("some text",)) - class NumericTest(_NumericTest): @emits_warning(r".*does \*not\* support Decimal objects natively") From a929876c0bd8b3c7140e06b1b6b89e45436d462b Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Tue, 25 May 2021 14:42:58 +0530 Subject: [PATCH 070/582] feat: add opentelemetry tracing (#51) * feat: add opentelemetry tracing * feat: call create span code in methods * feat: nit * feat: add db.instance in trace attribute * feat: nit --- .../_opentelemetry_tracing.py | 75 +++++++++++++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 41 +++++++++- packages/sqlalchemy-spanner/setup.py | 8 ++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py new file mode 100644 index 000000000000..faaae11e0d9c --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py @@ -0,0 +1,75 @@ +# Copyright 2021 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Manages OpenTelemetry trace creation and handling""" + +from contextlib import contextmanager + +from google.api_core.exceptions import GoogleAPICallError +from google.cloud.spanner_v1 import SpannerClient +from google.cloud.spanner_dbapi.exceptions import IntegrityError +from google.cloud.spanner_dbapi.exceptions import InterfaceError +from google.cloud.spanner_dbapi.exceptions import OperationalError +from google.cloud.spanner_dbapi.exceptions import ProgrammingError + +try: + from opentelemetry import trace + from opentelemetry.trace.status import Status, StatusCanonicalCode + from opentelemetry.instrumentation.utils import http_status_to_canonical_code + + HAS_OPENTELEMETRY_INSTALLED = True +except ImportError: + HAS_OPENTELEMETRY_INSTALLED = False + + +@contextmanager +def trace_call(name, extra_attributes=None): + if not HAS_OPENTELEMETRY_INSTALLED: + # Empty context manager. Users will have to check if the generated value + # is None or a span + yield None + return + + tracer = trace.get_tracer(__name__) + # Set base attributes that we know for every trace created + attributes = { + "db.type": "spanner", + "db.url": SpannerClient.DEFAULT_ENDPOINT, + "net.host.name": SpannerClient.DEFAULT_ENDPOINT, + } + + if extra_attributes: + attributes.update(extra_attributes) + + with tracer.start_as_current_span( + name, kind=trace.SpanKind.CLIENT, attributes=attributes + ) as span: + try: + yield span + except (ValueError, InterfaceError) as e: + span.set_status(Status(StatusCanonicalCode.UNKNOWN, e.args[0])) + except GoogleAPICallError as error: + if error.code is not None: + span.set_status(Status(http_status_to_canonical_code(error.code))) + elif error.grpc_status_code is not None: + span.set_status( + # OpenTelemetry's StatusCanonicalCode maps 1-1 with grpc status + # codes + Status(StatusCanonicalCode(error.grpc_status_code.value[0])) + ) + raise + except (IntegrityError, ProgrammingError, OperationalError) as e: + span.set_status( + Status(http_status_to_canonical_code(e.args[0].code), e.args[0].message) + ) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 52886740dcee..36e147c1e482 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -27,6 +27,7 @@ RESERVED_WORDS, ) from google.cloud import spanner_dbapi +from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call # Spanner-to-SQLAlchemy types map _type_map = { @@ -761,4 +762,42 @@ def do_rollback(self, dbapi_connection): ): pass else: - dbapi_connection.rollback() + trace_attributes = {"db.instance": dbapi_connection.database.name} + with trace_call("SpannerSqlAlchemy.Rollback", trace_attributes): + dbapi_connection.rollback() + + def do_commit(self, dbapi_connection): + trace_attributes = {"db.instance": dbapi_connection.database.name} + with trace_call("SpannerSqlAlchemy.Commit", trace_attributes): + dbapi_connection.commit() + + def do_close(self, dbapi_connection): + trace_attributes = {"db.instance": dbapi_connection.database.name} + with trace_call("SpannerSqlAlchemy.Close", trace_attributes): + dbapi_connection.close() + + def do_executemany(self, cursor, statement, parameters, context=None): + trace_attributes = { + "db.statement": statement, + "db.params": parameters, + "db.instance": cursor.connection.database.name, + } + with trace_call("SpannerSqlAlchemy.ExecuteMany", trace_attributes): + cursor.executemany(statement, parameters) + + def do_execute(self, cursor, statement, parameters, context=None): + trace_attributes = { + "db.statement": statement, + "db.params": parameters, + "db.instance": cursor.connection.database.name, + } + with trace_call("SpannerSqlAlchemy.Execute", trace_attributes): + cursor.execute(statement, parameters) + + def do_execute_no_params(self, cursor, statement, context=None): + trace_attributes = { + "db.statement": statement, + "db.instance": cursor.connection.database.name, + } + with trace_call("SpannerSqlAlchemy.ExecuteNoParams", trace_attributes): + cursor.execute(statement) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 17fd6162e3b4..9db3c5950665 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -20,6 +20,13 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.3.0"] +extras = { + "tracing": [ + "opentelemetry-api==0.11b0", + "opentelemetry-sdk==0.11b0", + "opentelemetry-instrumentation==0.11b0", + ] +} # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. @@ -45,6 +52,7 @@ ] }, install_requires=dependencies, + extras_require=extras, name=name, namespace_packages=namespaces, packages=packages, From 4ea9a3df92ede9877524bdd10c20eedfefe7543e Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 25 May 2021 17:28:02 +0300 Subject: [PATCH 071/582] fix: BYTES column reflection failure (#77) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 8 +++++++- packages/sqlalchemy-spanner/test/test_suite.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 36e147c1e482..4f5bafe80f6b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -32,7 +32,7 @@ # Spanner-to-SQLAlchemy types map _type_map = { "BOOL": types.Boolean, - "BYTES(MAX)": types.BINARY, + "BYTES": types.LargeBinary, "DATE": types.DATE, "DATETIME": types.DATETIME, "FLOAT64": types.Float, @@ -46,6 +46,7 @@ _type_map_inv = { types.Boolean: "BOOL", types.BINARY: "BYTES(MAX)", + types.LargeBinary: "BYTES(MAX)", types.DATE: "DATE", types.DATETIME: "DATETIME", types.Float: "FLOAT64", @@ -442,6 +443,11 @@ def get_columns(self, connection, table_name, schema=None, **kw): end = col[1].index(")") size = int(col[1][7:end]) type_ = _type_map["STRING"](length=size) + # add test creating a table with bytes + elif col[1].startswith("BYTES"): + end = col[1].index(")") + size = int(col[1][6:end]) + type_ = _type_map["BYTES"](length=size) else: type_ = _type_map[col[1]] diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index d2e79aee5374..86e1e8844891 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -675,6 +675,16 @@ def test_numeric_reflection(self): eq_(typ.precision, 38) eq_(typ.scale, 9) + @testing.requires.table_reflection + def test_binary_reflection(self): + """ + Check that a BYTES column with an explicitly + set size is correctly reflected. + """ + for typ in self._type_round_trip(LargeBinary(20)): + assert isinstance(typ, LargeBinary) + eq_(typ.length, 20) + class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): @testing.requires.foreign_key_constraint_reflection From 1a40bf718071db46e0737cf71d4b53f655a2a1c1 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 27 May 2021 10:31:52 +0300 Subject: [PATCH 072/582] Update README.md (#78) --- packages/sqlalchemy-spanner/README.md | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 020fb20135a8..317a57a70029 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -63,17 +63,15 @@ from sqlalchemy import ( MetaData, Table, create_engine, - insert, ) engine = create_engine( "spanner:///projects/project-id/instances/instance-id/databases/database-id" ) -metadata = MetaData(bind=engine) - -user = Table("users", metadata, autoload=True) +user = Table("users", MetaData(bind=engine), autoload=True) -insert(user).values(user_id=1, user_name="Full Name").execute() +with engine.begin() as connection: + connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) ``` **Read** @@ -83,10 +81,11 @@ from sqlalchemy import MetaData, Table, create_engine, select engine = create_engine( "spanner:///projects/project-id/instances/instance-id/databases/database-id" ) - table = Table("users", MetaData(bind=engine), autoload=True) -for row in select(["*"], from_obj=table).execute().fetchall(): - print(row) + +with engine.begin() as connection: + for row in connection.execute(select(["*"], from_obj=table)).fetchall(): + print(row) ``` Migration @@ -161,6 +160,23 @@ Data types table mapping SQLAlchemy types to Cloud Spanner types: - Temporary tables are not supported, real tables are used instead. - Numeric type dimensions (scale and precision) are constant. See the [docs](https://cloud.google.com/spanner/docs/data-types#numeric_types). +Best practices +----------- +When a SQLAlchemy function is called, a new connection to a database is established and a Spanner session object is fetched. In case of connectionless execution these fetches are done for every `execute()` call, which can cause a significant latency. To avoid initiating a Spanner session on every `execute()` call it's recommended to write code in connection-bounded fashion. Once a `Connection()` object is explicitly initiated, it fetches a Spanner session object and uses it for all the following calls made on this `Connection()` object. + +Non-optimal connectionless use: +```python +# execute() is called on object, which is not a Connection() object +insert(user).values(user_id=1, user_name="Full Name").execute() +``` +Optimal connection-bounded use: +```python +with engine.begin() as connection: + # execute() is called on a Connection() object + connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) +``` +Connectionless way of use is also deprecated since SQLAlchemy 2.0 and soon will be removed (see in [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/connections.html#connectionless-execution-implicit-execution)). + Contributing ------------ From 2cacfb030a42b87223ff2ce81871f1f138964024 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 2 Jun 2021 14:38:29 +1000 Subject: [PATCH 073/582] docs: update README.md migration warning text --- packages/sqlalchemy-spanner/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 317a57a70029..e21cf89e2db9 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -93,7 +93,7 @@ Migration SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. **Warning!** -A migration script can produce a lot of DDL statements. In case of executing every one of them separately performance and budget spending issues can occur. To avoid them it's highly recommended to use [Alembic batch context](https://cloud.google.com/spanner/docs/schema-updates) feature to pack DDL statements into more economical groups of statements. +A migration script can produce a lot of DDL statements. If each of the statements are executed separately, performance issues can occur. To avoid these, it's highly recommended to use the [Alembic batch context](https://alembic.sqlalchemy.org/en/latest/batch.html) feature to pack DDL statements into groups of statements. Features and limitations ----------- From d081cf7dd20bc5972c51ffaff896464766b3686c Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 2 Jun 2021 10:16:40 +0300 Subject: [PATCH 074/582] test: erase excess installation commands (#83) --- packages/sqlalchemy-spanner/noxfile.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 0446691db059..96f1c44579fd 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -109,10 +109,6 @@ def lint_setup_py(session): def compliance_test(session): """Run SQLAlchemy dialect compliance test suite.""" session.install("pytest") - session.install("sqlalchemy") - session.install( - "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" - ) session.install("-e", ".") session.run("python", "create_test_database.py") session.run("pytest", "-v") @@ -126,8 +122,6 @@ def migration_test(session): import shutil session.install("pytest") - session.install("sqlalchemy") - session.install("google-cloud-spanner") session.install("-e", ".") session.install("alembic") session.run("alembic", "init", "test_migration") From 8da15cc1185bdd1343323fe2635a5dc8cf0a56d9 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 3 Jun 2021 09:58:38 +0300 Subject: [PATCH 075/582] =?UTF-8?q?fix:=20prevent=20cleanup-rollbacking=20?= =?UTF-8?q?transactions,=20which=20are=20already=20comm=E2=80=A6=20(#80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 4f5bafe80f6b..23bb547f1b0c 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -759,12 +759,17 @@ def get_isolation_level(self, conn_proxy): return "AUTOCOMMIT" if conn.autocommit else "SERIALIZABLE" def do_rollback(self, dbapi_connection): - """To prevent transaction rollback error, rollback is ignored if - DBAPI rollback is already executed.""" + """ + To prevent rollback exception, don't rollback + committed/rolled back transactions. + """ if ( not isinstance(dbapi_connection, spanner_dbapi.Connection) and dbapi_connection.connection._transaction - and dbapi_connection.connection._transaction.rolled_back + and ( + dbapi_connection.connection._transaction.rolled_back + or dbapi_connection.connection._transaction.committed + ) ): pass else: From 749f7527e0acff43e4b2b97daf70b7ee00fa00a7 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 3 Jun 2021 10:56:24 +0300 Subject: [PATCH 076/582] feat: support table hints (#82) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 10 ++++ .../sqlalchemy-spanner/test/test_suite.py | 49 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 23bb547f1b0c..0c7078aab833 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -125,6 +125,16 @@ class SpannerSQLCompiler(SQLCompiler): compound_keywords = _compound_keywords + def get_from_hint_text(self, _, text): + """Return a hint text. + + Overriden to avoid adding square brackets to the hint text. + + Args: + text (str): The hint text. + """ + return text + def visit_empty_set_expr(self, type_): """Return an empty set expression of the given type. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 86e1e8844891..aaac0f687e33 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -20,6 +20,7 @@ import pytz import sqlalchemy +from sqlalchemy import create_engine from sqlalchemy import inspect from sqlalchemy import testing from sqlalchemy import ForeignKey @@ -42,6 +43,9 @@ from sqlalchemy import Float from sqlalchemy import LargeBinary from sqlalchemy import String +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relation +from sqlalchemy.orm import Session from sqlalchemy.types import Integer from sqlalchemy.types import Numeric from sqlalchemy.types import Text @@ -1210,3 +1214,48 @@ def test_limit_offset_selectable_in_unions(self): ) def test_order_by_selectable_in_unions(self): pass + + +class TestQueryHints(fixtures.TablesTest): + """ + Compile a complex query with JOIN and check that + the table hint was set into the right place. + """ + + __backend__ = True + + def test_complex_query_table_hints(self): + EXPECTED_QUERY = ( + "SELECT users.id, users.name \nFROM users @{FORCE_INDEX=table_1_by_int_idx}" + " JOIN addresses ON users.id = addresses.user_id " + "\nWHERE users.name IN (%s, %s)" + ) + + Base = declarative_base() + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + + class User(Base): + __tablename__ = "users" + id = Column(Integer, primary_key=True) + name = Column(String(50)) + addresses = relation("Address", backref="user") + + class Address(Base): + __tablename__ = "addresses" + id = Column(Integer, primary_key=True) + email = Column(String(50)) + user_id = Column(Integer, ForeignKey("users.id")) + + session = Session(engine) + + query = session.query(User) + query = query.with_hint( + selectable=User, text="@{FORCE_INDEX=table_1_by_int_idx}" + ) + + query = query.filter(User.name.in_(["val1", "val2"])) + query = query.join(Address) + + assert str(query.statement.compile(session.bind)) == EXPECTED_QUERY From d01b93a4429aa2da89424be3764e6acda3071a0c Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Fri, 4 Jun 2021 19:27:26 +0530 Subject: [PATCH 077/582] test: generate dynamic db url for test (#81) --- .../create_test_database.py | 23 +++++++++++++++---- .../migration_test_cleanup.py | 17 ++++++++++++-- packages/sqlalchemy-spanner/noxfile.py | 15 ++++++++++-- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index d4a523de2b79..c2982aeb4984 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import configparser import os import time @@ -30,9 +31,8 @@ if USE_EMULATOR: from google.auth.credentials import AnonymousCredentials - CLIENT = Client( - project=PROJECT, credentials=AnonymousCredentials() - ) + + CLIENT = Client(project=PROJECT, credentials=AnonymousCredentials()) else: CLIENT = Client(project=PROJECT) @@ -40,7 +40,9 @@ def reap_old_instances(): # Delete test instances that are older than four hours. cutoff = int(time.time()) - 4 * 60 * 60 - instances_pbs = CLIENT.list_instances("labels.python-spanner-sqlalchemy-systest:true") + instances_pbs = CLIENT.list_instances( + "labels.python-spanner-sqlalchemy-systest:true" + ) for instance_pb in instances_pbs: instance = Instance.from_pb(instance_pb, CLIENT) if "created" not in instance.labels: @@ -59,7 +61,7 @@ def prep_instance(): instance_config = configs[0].name create_time = str(int(time.time())) - unique_resource_id = '%s%d' % ('-', 1000 * time.time()) + unique_resource_id = "%s%d" % ("-", 1000 * time.time()) instance_id = "sqlalchemy-test" + unique_resource_id labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} @@ -72,5 +74,16 @@ def prep_instance(): created_op = database.create() created_op.result(120) + config = configparser.ConfigParser() + url = "spanner:///projects/{project}/instances/{instance_id}/databases/compliance-test".format( + project=PROJECT, instance_id=instance_id + ) + config.add_section("db") + config["db"]["default"] = url + + with open("test.cfg", "w") as configfile: + config.write(configfile) + + reap_old_instances() prep_instance() diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py index 9f4d729b369c..485f2a429eff 100644 --- a/packages/sqlalchemy-spanner/migration_test_cleanup.py +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -14,11 +14,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +import configparser +import os +import re + from google.cloud import spanner -client = spanner.Client() +config = configparser.ConfigParser() +if os.path.exists("test.cfg"): + config.read("test.cfg") +else: + config.read("setup.cfg") +db_url = config.get("db", "default") + +project = re.findall(r'projects(.*?)instances', db_url) +instance_id = re.findall(r'instances(.*?)databases', db_url) -instance = client.instance("sqlalchemy-dialect-test") +client = spanner.Client(project="".join(project).replace('/', '')) +instance = client.instance(instance_id="".join(instance_id).replace('/', '')) database = instance.database("compliance-test") database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 96f1c44579fd..458ede02776a 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -16,13 +16,14 @@ from __future__ import absolute_import +import configparser import nox ALEMBIC_CONF = """ [alembic] script_location = test_migration prepend_sys_path = . -sqlalchemy.url = spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test +sqlalchemy.url = {} [post_write_hooks] [loggers] keys = root,sqlalchemy,alembic @@ -124,12 +125,20 @@ def migration_test(session): session.install("pytest") session.install("-e", ".") session.install("alembic") + + config = configparser.ConfigParser() + if os.path.exists("test.cfg"): + config.read("test.cfg") + else: + config.read("setup.cfg") + db_url = config.get("db", "default") + session.run("alembic", "init", "test_migration") # setting testing configurations os.remove("alembic.ini") with open("alembic.ini", "w") as f: - f.write(ALEMBIC_CONF) + f.write(ALEMBIC_CONF.format(db_url)) session.run("alembic", "revision", "-m", "migration_for_test") files = glob.glob("test_migration/versions/*.py") @@ -152,3 +161,5 @@ def migration_test(session): os.remove("alembic.ini") shutil.rmtree("test_migration") session.run("python", "migration_test_cleanup.py") + if os.path.exists("test.cfg"): + os.remove("test.cfg") From c583c639d0ad2940a6cefc98ff0caa77e3646a8d Mon Sep 17 00:00:00 2001 From: Alan Derk <62039254+aderk@users.noreply.github.com> Date: Tue, 15 Jun 2021 01:22:44 -0600 Subject: [PATCH 078/582] fix: reflection of a STRING/BYTES column with MAX size fails(#87) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 17 ++++++- .../sqlalchemy-spanner/test/test_suite.py | 49 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 0c7078aab833..ff903c3b4690 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -68,6 +68,19 @@ selectable.CompoundSelect.INTERSECT_ALL: "INTERSECT ALL", } +_max_size = 2621440 + +def int_from_size(size_str): + """Convert a string column length to an integer value. + + Args: + size_str (str): The column length or the 'MAX' keyword. + + Returns: + int: The column length value. + """ + return _max_size if size_str == "MAX" else int(size_str) + def engine_to_connection(function): """ @@ -451,12 +464,12 @@ def get_columns(self, connection, table_name, schema=None, **kw): for col in columns: if col[1].startswith("STRING"): end = col[1].index(")") - size = int(col[1][7:end]) + size = int_from_size(col[1][7:end]) type_ = _type_map["STRING"](length=size) # add test creating a table with bytes elif col[1].startswith("BYTES"): end = col[1].index(")") - size = int(col[1][6:end]) + size = int_from_size(col[1][6:end]) type_ = _type_map["BYTES"](length=size) else: type_ = _type_map[col[1]] diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index aaac0f687e33..4d425738b70e 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -510,6 +510,38 @@ def define_temp_tables(cls, metadata): DDL("create temporary view user_tmp_v as " "select * from user_tmp"), ) event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v")) + + @testing.provide_metadata + def test_reflect_string_column_max_len(self): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the STRING type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + Table("text_table", self.metadata, Column("TestColumn", Text, nullable=False)) + self.metadata.create_all() + + Table("text_table", MetaData(bind=self.bind), autoload=True) + + @testing.provide_metadata + def test_reflect_bytes_column_max_len(self): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the BYTES type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + Table( + "bytes_table", + self.metadata, + Column("TestColumn", LargeBinary, nullable=False), + ) + self.metadata.create_all() + + Table("bytes_table", MetaData(bind=self.bind), autoload=True) @testing.provide_metadata def _test_get_unique_constraints(self, schema=None): @@ -573,7 +605,10 @@ def _test_get_unique_constraints(self, schema=None): reflected_metadata = MetaData() reflected = Table( - "testtbl", reflected_metadata, autoload_with=orig_meta.bind, schema=schema, + "testtbl", + reflected_metadata, + autoload_with=orig_meta.bind, + schema=schema, ) # test "deduplicates for index" logic. MySQL and Oracle @@ -830,7 +865,9 @@ def test_render_literal_numeric(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4), [15.7563], [decimal.Decimal("15.7563")], + Numeric(precision=8, scale=4), + [15.7563], + [decimal.Decimal("15.7563")], ) self._literal_round_trip( Numeric(precision=8, scale=4), @@ -849,7 +886,9 @@ def test_render_literal_numeric_asfloat(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4, asdecimal=False), [15.7563], [15.7563], + Numeric(precision=8, scale=4, asdecimal=False), + [15.7563], + [15.7563], ) self._literal_round_trip( Numeric(precision=8, scale=4, asdecimal=False), @@ -944,7 +983,9 @@ def test_float_as_decimal(self): Overriding the test to avoid the same failure. """ self._do_test( - Float(precision=8, asdecimal=True), [15.7563], [decimal.Decimal("15.7563")], + Float(precision=8, asdecimal=True), + [15.7563], + [decimal.Decimal("15.7563")], ) self._do_test( From 7c2e91bfc09003e41fa34a88c2bb70a55f140b9f Mon Sep 17 00:00:00 2001 From: Alex <7764119+AVaksman@users.noreply.github.com> Date: Wed, 16 Jun 2021 16:08:02 -0400 Subject: [PATCH 079/582] lint: fix (#90) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 5 +++-- .../sqlalchemy-spanner/test/test_suite.py | 21 ++++++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index ff903c3b4690..1c2f54a22f93 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -70,12 +70,13 @@ _max_size = 2621440 + def int_from_size(size_str): """Convert a string column length to an integer value. - + Args: size_str (str): The column length or the 'MAX' keyword. - + Returns: int: The column length value. """ diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 4d425738b70e..eb789de7f210 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -510,8 +510,8 @@ def define_temp_tables(cls, metadata): DDL("create temporary view user_tmp_v as " "select * from user_tmp"), ) event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v")) - - @testing.provide_metadata + + @testing.provide_metadata def test_reflect_string_column_max_len(self): """ SPANNER SPECIFIC TEST: @@ -605,10 +605,7 @@ def _test_get_unique_constraints(self, schema=None): reflected_metadata = MetaData() reflected = Table( - "testtbl", - reflected_metadata, - autoload_with=orig_meta.bind, - schema=schema, + "testtbl", reflected_metadata, autoload_with=orig_meta.bind, schema=schema, ) # test "deduplicates for index" logic. MySQL and Oracle @@ -865,9 +862,7 @@ def test_render_literal_numeric(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4), - [15.7563], - [decimal.Decimal("15.7563")], + Numeric(precision=8, scale=4), [15.7563], [decimal.Decimal("15.7563")], ) self._literal_round_trip( Numeric(precision=8, scale=4), @@ -886,9 +881,7 @@ def test_render_literal_numeric_asfloat(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4, asdecimal=False), - [15.7563], - [15.7563], + Numeric(precision=8, scale=4, asdecimal=False), [15.7563], [15.7563], ) self._literal_round_trip( Numeric(precision=8, scale=4, asdecimal=False), @@ -983,9 +976,7 @@ def test_float_as_decimal(self): Overriding the test to avoid the same failure. """ self._do_test( - Float(precision=8, asdecimal=True), - [15.7563], - [decimal.Decimal("15.7563")], + Float(precision=8, asdecimal=True), [15.7563], [decimal.Decimal("15.7563")], ) self._do_test( From ac34ee7087cf64fea47d6d15f074887a6fd641cb Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 17 Jun 2021 19:13:36 +1000 Subject: [PATCH 080/582] test: add back emulator test workflow (#71) --- .../.github/workflows/test_suite.yml | 31 ++++ .../create_test_database.py | 9 +- .../sqlalchemy-spanner/test/test_suite.py | 144 ++++++++++++++++++ 3 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 packages/sqlalchemy-spanner/.github/workflows/test_suite.yml diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml new file mode 100644 index 000000000000..7a6d4653d66c --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -0,0 +1,31 @@ +on: + push: + branches: + - main + pull_request: +name: SQLAlchemy Spanner dialect +jobs: + tests: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run SQLAlchemy tests + run: nox + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index c2982aeb4984..498b54489d0a 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -56,13 +56,14 @@ def reap_old_instances(): def prep_instance(): configs = list(CLIENT.list_instance_configs()) - # Filter out non "us" locations - configs = [config for config in configs if "-us-" in config.name] + if not USE_EMULATOR: + # Filter out non "us" locations + configs = [config for config in configs if "-us-" in config.name] instance_config = configs[0].name create_time = str(int(time.time())) - unique_resource_id = "%s%d" % ("-", 1000 * time.time()) - instance_id = "sqlalchemy-test" + unique_resource_id + unique_resource_id = '%s%d' % ('-', 1000 * time.time()) + instance_id = 'sqlalchemy-dialect-test' if USE_EMULATOR else "sqlalchemy-test" + unique_resource_id labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} instance = CLIENT.instance(instance_id, instance_config, labels=labels) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index eb789de7f210..524412909a08 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -480,6 +480,149 @@ class UnicodeTextTest(UnicodeFixtureTest, _UnicodeTextTest): class ComponentReflectionTest(_ComponentReflectionTest): + @classmethod + def define_reflected_tables(cls, metadata, schema): + if schema: + schema_prefix = schema + "." + else: + schema_prefix = "" + + if testing.requires.self_referential_foreign_keys.enabled: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + Column( + "parent_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey( + "%susers.user_id" % schema_prefix, name="user_id_fk" + ), + ), + schema=schema, + test_needs_fk=True, + ) + else: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + schema=schema, + test_needs_fk=True, + ) + + Table( + "dingalings", + metadata, + Column("dingaling_id", sqlalchemy.Integer, primary_key=True), + Column( + "address_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey("%semail_addresses.address_id" % schema_prefix), + ), + Column("data", sqlalchemy.String(30)), + schema=schema, + test_needs_fk=True, + ) + Table( + "email_addresses", + metadata, + Column("address_id", sqlalchemy.Integer, primary_key=True), + Column( + "remote_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey(users.c.user_id), + ), + Column("email_address", sqlalchemy.String(20)), + sqlalchemy.PrimaryKeyConstraint("address_id", name="email_ad_pk"), + schema=schema, + test_needs_fk=True, + ) + Table( + "comment_test", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True, comment="id comment"), + Column("data", sqlalchemy.String(20), comment="data % comment"), + Column( + "d2", + sqlalchemy.String(20), + comment=r"""Comment types type speedily ' " \ '' Fun!""", + ), + schema=schema, + comment=r"""the test % ' " \ table comment""", + ) + + if testing.requires.cross_schema_fk_reflection.enabled: + if schema is None: + Table( + "local_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + Column( + "remote_id", + ForeignKey("%s.remote_table_2.id" % testing.config.test_schema), + ), + test_needs_fk=True, + schema=config.db.dialect.default_schema_name, + ) + else: + Table( + "remote_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column( + "local_id", + ForeignKey( + "%s.local_table.id" % config.db.dialect.default_schema_name + ), + ), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + Table( + "remote_table_2", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + + if testing.requires.index_reflection.enabled: + cls.define_index(metadata, users) + + if not schema: + # test_needs_fk is at the moment to force MySQL InnoDB + # noncol_idx_test_nopk = Table( + # "noncol_idx_test_nopk", + # metadata, + # Column("q", sqlalchemy.String(5)), + # test_needs_fk=True, + # ) + + noncol_idx_test_pk = Table( + "noncol_idx_test_pk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + ) + + if testing.requires.indexes_with_ascdesc.enabled: + # Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) + sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) + + if testing.requires.view_column_reflection.enabled: + cls.define_views(metadata, schema) + if not schema and testing.requires.temp_table_reflection.enabled: + cls.define_temp_tables(metadata) + @classmethod def define_temp_tables(cls, metadata): """ @@ -573,6 +716,7 @@ def _test_get_unique_constraints(self, schema=None): Table( "testtbl", orig_meta, + Column("id", sqlalchemy.Integer, primary_key=True), Column("a", sqlalchemy.String(20)), Column("b", sqlalchemy.String(30)), Column("c", sqlalchemy.Integer), From 47d8dfac60779734608da363d1f24908fec77c0b Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 17 Jun 2021 12:37:51 +0300 Subject: [PATCH 081/582] test: add performance benchmark comparator (#74) --- packages/sqlalchemy-spanner/test/benchmark.py | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 packages/sqlalchemy-spanner/test/benchmark.py diff --git a/packages/sqlalchemy-spanner/test/benchmark.py b/packages/sqlalchemy-spanner/test/benchmark.py new file mode 100644 index 000000000000..be027adedd8b --- /dev/null +++ b/packages/sqlalchemy-spanner/test/benchmark.py @@ -0,0 +1,327 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +A test suite to check Spanner dialect for SQLAlchemy performance +in comparison with the original Spanner client. +""" +import datetime +import random +from scipy.stats import sem +import statistics +import time + +from google.api_core.exceptions import Aborted +from google.cloud import spanner_dbapi +from google.cloud.spanner_v1 import Client, KeySet +from sqlalchemy import ( + create_engine, + insert, + select, + text, + MetaData, + Table, +) + + +def measure_execution_time(function): + """Decorator to measure a wrapped method execution time.""" + + def wrapper(self, measures): + """Execute the wrapped method and measure its execution time. + + Args: + measures (dict): Test cases and their execution time. + """ + t_start = time.time() + try: + function(self) + measures[function.__name__] = round(time.time() - t_start, 2) + except Aborted: + measures[function.__name__] = 0 + + return wrapper + + +class BenchmarkTestBase: + """Base class for performance testing. + + Organizes testing data preparation and cleanup. + """ + + def __init__(self): + self._create_table() + + self._one_row = ( + 1, + "Pete", + "Allison", + datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d"), + b"123", + ) + + def _cleanup(self): + """Drop the test table.""" + conn = spanner_dbapi.connect("sqlalchemy-dialect-test", "compliance-test") + conn.database.update_ddl(["DROP TABLE Singers"]) + conn.close() + + def _create_table(self): + """Create a table for performace testing.""" + conn = spanner_dbapi.connect("sqlalchemy-dialect-test", "compliance-test") + conn.database.update_ddl( + [ + """ +CREATE TABLE Singers ( + id INT64, + first_name STRING(1024), + last_name STRING(1024), + birth_date DATE, + picture BYTES(1024), +) PRIMARY KEY (id) + """ + ] + ).result(120) + + conn.close() + + def run(self): + """Execute every test case.""" + measures = {} + for method in ( + self.insert_one_row_with_fetch_after, + self.read_one_row, + self.insert_many_rows, + self.select_many_rows, + self.insert_many_rows_with_mutations, + ): + method(measures) + + self._cleanup() + return measures + + +class SpannerBenchmarkTest(BenchmarkTestBase): + """The original Spanner performace testing class.""" + + def __init__(self): + super().__init__() + self._client = Client() + self._instance = self._client.instance("sqlalchemy-dialect-test") + self._database = self._instance.database("compliance-test") + + self._many_rows = [] + self._many_rows2 = [] + birth_date = datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d") + for i in range(99): + num = round(random.random() * 1000000) + self._many_rows.append((num, "Pete", "Allison", birth_date, b"123")) + num2 = round(random.random() * 1000000) + self._many_rows2.append((num2, "Pete", "Allison", birth_date, b"123")) + + # initiate a session + with self._database.snapshot(): + pass + + @measure_execution_time + def insert_one_row_with_fetch_after(self): + self._database.run_in_transaction(insert_one_row, self._one_row) + + @measure_execution_time + def insert_many_rows(self): + self._database.run_in_transaction(insert_many_rows, self._many_rows) + + @measure_execution_time + def insert_many_rows_with_mutations(self): + with self._database.batch() as batch: + batch.insert( + table="Singers", + columns=("id", "first_name", "last_name", "birth_date", "picture"), + values=self._many_rows2, + ) + + @measure_execution_time + def read_one_row(self): + with self._database.snapshot() as snapshot: + keyset = KeySet(all_=True) + snapshot.read( + table="Singers", + columns=("id", "first_name", "last_name", "birth_date", "picture"), + keyset=keyset, + ).one() + + @measure_execution_time + def select_many_rows(self): + with self._database.snapshot() as snapshot: + rows = list( + snapshot.execute_sql("SELECT * FROM Singers ORDER BY last_name") + ) + if len(rows) != 100: + raise ValueError("Wrong number of rows read") + + +class SQLAlchemyBenchmarkTest(BenchmarkTestBase): + """Spanner dialect for SQLAlchemy performance testing class.""" + + def __init__(self): + super().__init__() + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + metadata = MetaData(bind=self._engine) + self._table = Table("Singers", metadata, autoload=True) + + self._conn = self._engine.connect() + + self._many_rows = [] + self._many_rows2 = [] + birth_date = datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d") + for i in range(99): + num = round(random.random() * 1000000) + self._many_rows.append( + { + "id": num, + "first_name": "Pete", + "last_name": "Allison", + "birth_date": birth_date, + "picture": b"123", + } + ) + num2 = round(random.random() * 1000000) + self._many_rows2.append( + { + "id": num2, + "first_name": "Pete", + "last_name": "Allison", + "birth_date": birth_date, + "picture": b"123", + } + ) + + @measure_execution_time + def insert_one_row_with_fetch_after(self): + self._conn.execute(insert(self._table).values(self._one_row)) + last_name = self._conn.execute( + select([text("last_name")], from_obj=self._table) + ).fetchone()[0] + if last_name != "Allison": + raise ValueError("Received invalid last name: " + last_name) + + @measure_execution_time + def insert_many_rows(self): + self._conn.execute( + self._table.insert(), self._many_rows, + ) + + @measure_execution_time + def insert_many_rows_with_mutations(self): + self._conn.execute( + self._table.insert(), self._many_rows2, + ) + + @measure_execution_time + def read_one_row(self): + row = self._conn.execute(select(["*"], from_obj=self._table)).fetchone() + if not row: + raise ValueError("No rows read") + + @measure_execution_time + def select_many_rows(self): + rows = self._conn.execute(select(["*"], from_obj=self._table)).fetchall() + if len(rows) != 100: + raise ValueError("Wrong number of rows read") + + +def insert_one_row(transaction, one_row): + """A transaction-function for the original Spanner client. + + Inserts a single row into a database and then fetches it back. + """ + transaction.execute_update( + "INSERT Singers (id, first_name, last_name, birth_date, picture) " + " VALUES {}".format(str(one_row)) + ) + last_name = transaction.execute_sql( + "SELECT last_name FROM Singers WHERE id=1" + ).one()[0] + if last_name != "Allison": + raise ValueError("Received invalid last name: " + last_name) + + +def insert_many_rows(transaction, many_rows): + """A transaction-function for the original Spanner client. + + Insert 100 rows into a database. + """ + statements = [] + for row in many_rows: + statements.append( + "INSERT Singers (id, first_name, last_name, birth_date, picture) " + " VALUES {}".format(str(row)) + ) + _, count = transaction.batch_update(statements) + if sum(count) != 99: + raise ValueError("Wrong number of inserts: " + str(sum(count))) + + +def compare_measurements(spanner, alchemy): + """ + Compare the original Spanner client performance measures + with Spanner dialect for SQLAlchemy ones. + """ + comparison = {} + for key in spanner.keys(): + comparison[key] = { + "Spanner, sec": spanner[key], + "SQLAlchemy, sec": alchemy[key], + "SQLAlchemy deviation": round(alchemy[key] - spanner[key], 2), + "SQLAlchemy to Spanner, %": round(alchemy[key] / spanner[key] * 100), + } + return comparison + + +measures = [] +for _ in range(50): + spanner_measures = SpannerBenchmarkTest().run() + alchemy_measures = SQLAlchemyBenchmarkTest().run() + measures.append((spanner_measures, alchemy_measures)) + +agg = {"spanner": {}, "alchemy": {}} + +for span, alch in measures: + for key, value in span.items(): + agg["spanner"].setdefault(key, []).append(value) + agg["alchemy"].setdefault(key, []).append(alch[key]) + +spanner_stats = {} +for key, value in agg["spanner"].items(): + while 0 in value: + value.remove(0) + spanner_stats[key + "_aver"] = round(statistics.mean(value), 2) + spanner_stats[key + "_error"] = round(sem(value), 2) + spanner_stats[key + "_std_dev"] = round(statistics.pstdev(value), 2) + +alchemy_stats = {} +for key, value in agg["alchemy"].items(): + while 0 in value: + value.remove(0) + alchemy_stats[key + "_aver"] = round(statistics.mean(value), 2) + alchemy_stats[key + "_error"] = round(sem(value), 2) + alchemy_stats[key + "_std_dev"] = round(statistics.pstdev(value), 2) + +for key in spanner_stats: + print(key + ":") + print("spanner: ", spanner_stats[key]) + print("alchemy: ", alchemy_stats[key]) From d202516158a5bddeb119f6933c3bc3bd143a8019 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Thu, 17 Jun 2021 16:59:38 +0530 Subject: [PATCH 082/582] fix: uncomment noncol_idx_test_nopk test and fix for emulator (#91) --- packages/sqlalchemy-spanner/test/test_suite.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 524412909a08..b5c4c30a6457 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -599,12 +599,13 @@ def define_reflected_tables(cls, metadata, schema): if not schema: # test_needs_fk is at the moment to force MySQL InnoDB - # noncol_idx_test_nopk = Table( - # "noncol_idx_test_nopk", - # metadata, - # Column("q", sqlalchemy.String(5)), - # test_needs_fk=True, - # ) + noncol_idx_test_nopk = Table( + "noncol_idx_test_nopk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + ) noncol_idx_test_pk = Table( "noncol_idx_test_pk", @@ -615,7 +616,7 @@ def define_reflected_tables(cls, metadata, schema): ) if testing.requires.indexes_with_ascdesc.enabled: - # Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) + sqlalchemy.Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) if testing.requires.view_column_reflection.enabled: From 267f24706aa119b97aef406dcd62fffaf1541ce1 Mon Sep 17 00:00:00 2001 From: Vikash Singh <3116482+vi3k6i5@users.noreply.github.com> Date: Thu, 17 Jun 2021 19:28:15 +0530 Subject: [PATCH 083/582] fix: for open-telemetry status code spec change (#88) * fix: for open-telemetry status code spec change * fix: updated open telemetry version * refactor: lint fixes * refactor: removed commented and unused line * refactor: change OpenTelemetryBase to inheri unittest.TestCase * refactor: lint corrections * refactor: lint correction * refactor: lint fixes * test: add separate unit test session in noxfile * refactor: move open telemetry test inside test/unit tests --- .../_opentelemetry_tracing.py | 25 +--- packages/sqlalchemy-spanner/noxfile.py | 15 +++ packages/sqlalchemy-spanner/setup.py | 6 +- packages/sqlalchemy-spanner/test/__init__.py | 0 packages/sqlalchemy-spanner/test/_helpers.py | 80 ++++++++++++ .../test/unit/test_opentelemetry_tracing.py | 114 ++++++++++++++++++ 6 files changed, 217 insertions(+), 23 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/__init__.py create mode 100644 packages/sqlalchemy-spanner/test/_helpers.py create mode 100644 packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py index faaae11e0d9c..ed3b5b9d7751 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py @@ -18,15 +18,10 @@ from google.api_core.exceptions import GoogleAPICallError from google.cloud.spanner_v1 import SpannerClient -from google.cloud.spanner_dbapi.exceptions import IntegrityError -from google.cloud.spanner_dbapi.exceptions import InterfaceError -from google.cloud.spanner_dbapi.exceptions import OperationalError -from google.cloud.spanner_dbapi.exceptions import ProgrammingError try: from opentelemetry import trace - from opentelemetry.trace.status import Status, StatusCanonicalCode - from opentelemetry.instrumentation.utils import http_status_to_canonical_code + from opentelemetry.trace.status import Status, StatusCode HAS_OPENTELEMETRY_INSTALLED = True except ImportError: @@ -45,6 +40,7 @@ def trace_call(name, extra_attributes=None): # Set base attributes that we know for every trace created attributes = { "db.type": "spanner", + "db.engine": "sqlalchemy_spanner", "db.url": SpannerClient.DEFAULT_ENDPOINT, "net.host.name": SpannerClient.DEFAULT_ENDPOINT, } @@ -56,20 +52,9 @@ def trace_call(name, extra_attributes=None): name, kind=trace.SpanKind.CLIENT, attributes=attributes ) as span: try: + span.set_status(Status(StatusCode.OK)) yield span - except (ValueError, InterfaceError) as e: - span.set_status(Status(StatusCanonicalCode.UNKNOWN, e.args[0])) except GoogleAPICallError as error: - if error.code is not None: - span.set_status(Status(http_status_to_canonical_code(error.code))) - elif error.grpc_status_code is not None: - span.set_status( - # OpenTelemetry's StatusCanonicalCode maps 1-1 with grpc status - # codes - Status(StatusCanonicalCode(error.grpc_status_code.value[0])) - ) + span.set_status(Status(StatusCode.ERROR)) + span.record_exception(error) raise - except (IntegrityError, ProgrammingError, OperationalError) as e: - span.set_status( - Status(http_status_to_canonical_code(e.args[0].code), e.args[0].message) - ) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 458ede02776a..840998fdf7ec 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -18,6 +18,7 @@ import configparser import nox +import os ALEMBIC_CONF = """ [alembic] @@ -110,11 +111,25 @@ def lint_setup_py(session): def compliance_test(session): """Run SQLAlchemy dialect compliance test suite.""" session.install("pytest") + session.install("mock") session.install("-e", ".") session.run("python", "create_test_database.py") session.run("pytest", "-v") +@nox.session(python=DEFAULT_PYTHON_VERSION) +def unit(session): + """Run unit tests.""" + # Run SQLAlchemy dialect compliance test suite with OpenTelemetry. + session.install("pytest") + session.install("mock") + session.install("-e", ".") + session.install("opentelemetry-api==1.1.0") + session.install("opentelemetry-sdk==1.1.0") + session.install("opentelemetry-instrumentation==0.20b0") + session.run("py.test", "--quiet", os.path.join("test/unit"), *session.posargs) + + @nox.session(python=DEFAULT_PYTHON_VERSION) def migration_test(session): """Migrate with SQLAlchemy and Alembic and check the result.""" diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 9db3c5950665..3852af3d5da7 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -22,9 +22,9 @@ dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.3.0"] extras = { "tracing": [ - "opentelemetry-api==0.11b0", - "opentelemetry-sdk==0.11b0", - "opentelemetry-instrumentation==0.11b0", + "opentelemetry-api >= 1.1.0", + "opentelemetry-sdk >= 1.1.0", + "opentelemetry-instrumentation >= 0.20b0", ] } diff --git a/packages/sqlalchemy-spanner/test/__init__.py b/packages/sqlalchemy-spanner/test/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/test/_helpers.py b/packages/sqlalchemy-spanner/test/_helpers.py new file mode 100644 index 000000000000..c9d9ba7497f1 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/_helpers.py @@ -0,0 +1,80 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + + +import mock +from sqlalchemy.testing import fixtures + +try: + from opentelemetry import trace + from opentelemetry.sdk.trace import TracerProvider + from opentelemetry.sdk.trace.export import SimpleSpanProcessor + from opentelemetry.sdk.trace.export.in_memory_span_exporter import ( + InMemorySpanExporter, + ) + from opentelemetry.trace.status import StatusCode + + trace.set_tracer_provider(TracerProvider()) + + HAS_OPENTELEMETRY_INSTALLED = True +except ImportError: + HAS_OPENTELEMETRY_INSTALLED = False + + StatusCode = mock.Mock() + +_TEST_OT_EXPORTER = None +_TEST_OT_PROVIDER_INITIALIZED = False + + +def get_test_ot_exporter(): + global _TEST_OT_EXPORTER + + if _TEST_OT_EXPORTER is None: + _TEST_OT_EXPORTER = InMemorySpanExporter() + return _TEST_OT_EXPORTER + + +def use_test_ot_exporter(): + global _TEST_OT_PROVIDER_INITIALIZED + + if _TEST_OT_PROVIDER_INITIALIZED: + return + + provider = trace.get_tracer_provider() + if not hasattr(provider, "add_span_processor"): + return + provider.add_span_processor(SimpleSpanProcessor(get_test_ot_exporter())) + _TEST_OT_PROVIDER_INITIALIZED = True + + +class OpenTelemetryBase(fixtures.TestBase): + @classmethod + def setup_class(cls): + if HAS_OPENTELEMETRY_INSTALLED: + use_test_ot_exporter() + cls.ot_exporter = get_test_ot_exporter() + + def teardown(self): + if HAS_OPENTELEMETRY_INSTALLED: + self.ot_exporter.clear() + + def assertNoSpans(self): + if HAS_OPENTELEMETRY_INSTALLED: + span_list = self.ot_exporter.get_finished_spans() + self.assertEqual(len(span_list), 0) + + def assertSpanAttributes( + self, name, status=StatusCode.OK, attributes=None, span=None + ): + if HAS_OPENTELEMETRY_INSTALLED: + if not span: + span_list = self.ot_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + span = span_list[0] + + self.assertEqual(span.name, name) + self.assertEqual(span.status.status_code, status) + self.assertEqual(dict(span.attributes), attributes) diff --git a/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py new file mode 100644 index 000000000000..e762f93d2ff3 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py @@ -0,0 +1,114 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +import importlib +import mock +import pytest +import sys + +try: + from opentelemetry import trace as trace_api + from opentelemetry.trace.status import StatusCode +except ImportError: + pass + +from google.api_core.exceptions import GoogleAPICallError +from google.cloud.spanner_v1 import SpannerClient +from google.cloud.sqlalchemy_spanner import _opentelemetry_tracing +from test._helpers import OpenTelemetryBase, HAS_OPENTELEMETRY_INSTALLED + + +def _make_rpc_error(error_cls, trailing_metadata=None): + import grpc + + grpc_error = mock.create_autospec(grpc.Call, instance=True) + grpc_error.trailing_metadata.return_value = trailing_metadata + return error_cls("error", errors=(grpc_error,)) + + +# Skip all of these tests if we don't have OpenTelemetry +if HAS_OPENTELEMETRY_INSTALLED: + + class TestNoTracing(OpenTelemetryBase): + def setup(self): + self._temp_opentelemetry = sys.modules["opentelemetry"] + + sys.modules["opentelemetry"] = None + importlib.reload(_opentelemetry_tracing) + + def teardown(self): + sys.modules["opentelemetry"] = self._temp_opentelemetry + importlib.reload(_opentelemetry_tracing) + + def test_no_trace_call(self): + with _opentelemetry_tracing.trace_call("Test") as no_span: + assert no_span is None + + class TestTracing(OpenTelemetryBase): + def test_trace_call(self): + extra_attributes = { + "attribute1": "value1", + # Since our database is mocked, we have to override the + # db.instance parameter so it is a string. + "db.instance": "database_name", + } + + expected_attributes = { + "db.type": "spanner", + "db.engine": "sqlalchemy_spanner", + "db.url": SpannerClient.DEFAULT_ENDPOINT, + "net.host.name": SpannerClient.DEFAULT_ENDPOINT, + } + expected_attributes.update(extra_attributes) + + with _opentelemetry_tracing.trace_call( + "CloudSpannerSqlAlchemy.Test", extra_attributes + ) as span: + span.set_attribute("after_setup_attribute", 1) + + expected_attributes["after_setup_attribute"] = 1 + + span_list = self.ot_exporter.get_finished_spans() + assert len(span_list) == 1 + + span = span_list[0] + assert span.kind == trace_api.SpanKind.CLIENT + span_attr = dict(span.attributes) + for key in expected_attributes: + assert key in span_attr + assert span_attr[key] == expected_attributes[key] + assert span.name == "CloudSpannerSqlAlchemy.Test" + assert span.status.status_code == StatusCode.OK + + def test_trace_error(self): + extra_attributes = {"db.instance": "database_name"} + + expected_attributes = { + "db.type": "spanner", + "db.engine": "sqlalchemy_spanner", + "db.url": SpannerClient.DEFAULT_ENDPOINT, + "net.host.name": SpannerClient.DEFAULT_ENDPOINT, + } + expected_attributes.update(extra_attributes) + + with pytest.raises(GoogleAPICallError): + with _opentelemetry_tracing.trace_call( + "CloudSpannerSqlAlchemy.Test", extra_attributes, + ) as span: + from google.api_core.exceptions import InvalidArgument + + raise _make_rpc_error(InvalidArgument) + + span_list = self.ot_exporter.get_finished_spans() + assert len(span_list) == 1 + span = span_list[0] + assert span.kind == trace_api.SpanKind.CLIENT + span_attr = dict(span.attributes) + for key in expected_attributes: + assert key in span_attr + assert span_attr[key] == expected_attributes[key] + assert span.name == "CloudSpannerSqlAlchemy.Test" + assert span.status.status_code == StatusCode.ERROR From b70c855089b3e90340746056ffc071db5168c1d9 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 25 Jun 2021 11:13:35 +0300 Subject: [PATCH 084/582] feat: support interleaved tables feature (#85) --- packages/sqlalchemy-spanner/README.md | 27 +++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 13 ++++- .../sqlalchemy-spanner/test/test_suite.py | 56 +++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index e21cf89e2db9..c57e72501970 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -97,6 +97,33 @@ A migration script can produce a lot of DDL statements. If each of the statement Features and limitations ----------- +**Interleaved tables** +Cloud Spanner dialect includes two dialect-specific arguments for `Table` constructor, which help to define interleave relations: +`spanner_interleave_in` - a parent table name +`spanner_inverleave_on_delete_cascade` - a flag specifying if `ON DELETE CASCADE` statement must be used for the interleave relation +An example of interleave relations definition: +```python +team = Table( + "team", + metadata, + Column("team_id", Integer, primary_key=True), + Column("team_name", String(16), nullable=False), +) +team.create(engine) + +client = Table( + "client", + metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + spanner_interleave_on_delete_cascade=True, +) + +client.create(engine) +``` + **Unique constraints** Cloud Spanner doesn't support direct UNIQUE constraints creation. In order to achieve column values uniqueness UNIQUE indexes should be used. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 1c2f54a22f93..e98b98bbc6f4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -287,6 +287,8 @@ def visit_unique_constraint(self, constraint): def post_create_table(self, table): """Build statements to be executed after CREATE TABLE. + Includes "primary key" and "interleaved table" statements generation. + Args: table (sqlalchemy.schema.Table): Table to create. @@ -294,8 +296,17 @@ def post_create_table(self, table): str: primary key difinition to add to the table CREATE request. """ cols = [col.name for col in table.primary_key.columns] + post_cmds = " PRIMARY KEY ({})".format(", ".join(cols)) + + if table.kwargs.get("spanner_interleave_in"): + post_cmds += ",\nINTERLEAVE IN PARENT {}".format( + table.kwargs["spanner_interleave_in"] + ) + + if table.kwargs.get("spanner_inverleave_on_delete_cascade"): + post_cmds += " ON DELETE CASCADE" - return " PRIMARY KEY ({})".format(", ".join(cols)) + return post_cmds class SpannerTypeCompiler(GenericTypeCompiler): diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index b5c4c30a6457..89991ef1850f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -18,6 +18,7 @@ import pytest import decimal import pytz +from unittest import mock import sqlalchemy from sqlalchemy import create_engine @@ -1436,3 +1437,58 @@ class Address(Base): query = query.join(Address) assert str(query.statement.compile(session.bind)) == EXPECTED_QUERY + + +class InterleavedTablesTest(fixtures.TestBase): + """ + Check that CREATE TABLE statements for interleaved tables are correctly + generated. + """ + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData(bind=self._engine) + + def test_interleave(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) + + def test_interleave_on_delete_cascade(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team ON DELETE CASCADE\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + spanner_inverleave_on_delete_cascade=True, + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) From 37cbd5180b12643a67d81f96018200e0cd0ee0b1 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 29 Jun 2021 08:30:59 +0300 Subject: [PATCH 085/582] test: skip null/numeric related tests on emulator (#94) --- packages/sqlalchemy-spanner/README.md | 13 +++++++ .../sqlalchemy-spanner/test/test_suite.py | 39 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index c57e72501970..2a40d5a022f7 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -204,6 +204,19 @@ with engine.begin() as connection: ``` Connectionless way of use is also deprecated since SQLAlchemy 2.0 and soon will be removed (see in [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/connections.html#connectionless-execution-implicit-execution)). +Running tests +------------ +Spanner dialect includes a compliance, migration and unit test suite. To run the tests the `nox` package commands can be used: +``` +# Run the whole suite +$ nox + +# Run a particular test session +$ nox -s migration_test +``` +**Running tests on Spanner emulator** +The dialect test suite can be runned on [Spanner emulator](https://cloud.google.com/spanner/docs/emulator). Several tests, relating to `NULL` values of data types, are skipped when executed on emulator. + Contributing ------------ diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 89991ef1850f..85274ddc416f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,9 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +import decimal import operator +import os import pytest -import decimal import pytz from unittest import mock @@ -329,7 +330,17 @@ class DateTest(DateFixtureTest, _DateTest): and maintain DRY concept just inherit the class to run tests successfully. """ - pass + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self): + super().test_null() class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest, DateTest): @@ -349,6 +360,18 @@ def test_round_trip(self): eq_(row[0].rfc3339(), compare) assert isinstance(row[0], DatetimeWithNanoseconds) + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self): + super().test_null() + class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): """ @@ -359,7 +382,17 @@ class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): tests successfully. """ - pass + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self): + super().test_null() @pytest.mark.skip("Spanner doesn't support Time data type.") From 4e2c804e5aa6f854217b0d98cba50a6a6392bda6 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 8 Jul 2021 14:07:14 +1000 Subject: [PATCH 086/582] docs: update to state that repo is now in preview (#95) --- packages/sqlalchemy-spanner/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 2a40d5a022f7..f4baa082b879 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -2,7 +2,9 @@ Spanner dialect for SQLAlchemy represents an interface API designed to make it possible to control Cloud Spanner databases with SQLAlchemy API. The dialect is built on top of [the Spanner DB API](https://github.com/googleapis/python-spanner/tree/master/google/cloud/spanner_dbapi), which is designed in accordance with [PEP-249](https://www.python.org/dev/peps/pep-0249/). -**NOTE: This project is still in DEVELOPMENT. It may make breaking changes without prior notice and should not yet be used for production purposes.** +This project has **Preview** release status. Known limitations are listed [here](#features-and-limitations). All supported features have been tested and verified to work with the test configurations. There may be configurations and/or data model variations that have not yet been covered by the tests and that show unexpected behavior. Please report any problems that you might encounter by [creating a new issue](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/issues/new). + +**NOTE: This project may still make breaking changes without prior notice and should not yet be used for production purposes.** - [Cloud Spanner product documentation](https://cloud.google.com/spanner/docs) - [SQLAlchemy product documentation](https://www.sqlalchemy.org/) From 6f20b1f5f1a29bf9ffccacc765a6d9d54029b7aa Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 8 Jul 2021 14:18:07 +1000 Subject: [PATCH 087/582] docs: update to include text about support status (#96) --- packages/sqlalchemy-spanner/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index f4baa082b879..f601c0770926 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -222,11 +222,11 @@ The dialect test suite can be runned on [Spanner emulator](https://cloud.google. Contributing ------------ -Contributions to this library are welcome and encouraged. - -See [CONTRIBUTING](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get +Contributions to this library are welcome and encouraged. Please report issues, file feature requests, and send pull requests. See [CONTRIBUTING](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get started. +**Note that this project is not officially supported by Google as part of the Cloud Spanner product.** + Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See the [Code of Conduct](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/code-of-conduct.md) for more information. From b98744757a71b78c7e26f648309b9845d3c6857e Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Tue, 20 Jul 2021 09:22:31 +1000 Subject: [PATCH 088/582] fix: correct typo in spanner_interleave_on_delete_cascade keyword (#99) Co-authored-by: larkee --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- packages/sqlalchemy-spanner/test/test_suite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e98b98bbc6f4..c68332e8a9cb 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -303,7 +303,7 @@ def post_create_table(self, table): table.kwargs["spanner_interleave_in"] ) - if table.kwargs.get("spanner_inverleave_on_delete_cascade"): + if table.kwargs.get("spanner_interleave_on_delete_cascade"): post_cmds += " ON DELETE CASCADE" return post_cmds diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 85274ddc416f..51d345225491 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1520,7 +1520,7 @@ def test_interleave_on_delete_cascade(self): Column("client_id", Integer, primary_key=True), Column("client_name", String(16), nullable=False), spanner_interleave_in="team", - spanner_inverleave_on_delete_cascade=True, + spanner_interleave_on_delete_cascade=True, ) with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: client.create(self._engine) From 61a9dc5e9c6a02dca94056910a48771d37e963b0 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Tue, 10 Aug 2021 15:31:13 +1000 Subject: [PATCH 089/582] chore: license fixes (#101) --- packages/sqlalchemy-spanner/LICENSE | 9 +++++---- packages/sqlalchemy-spanner/test_migration_env.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/LICENSE b/packages/sqlalchemy-spanner/LICENSE index 08eea89fa5ef..d64569567334 100644 --- a/packages/sqlalchemy-spanner/LICENSE +++ b/packages/sqlalchemy-spanner/LICENSE @@ -1,6 +1,7 @@ - Apache License + + Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,10 +193,10 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/packages/sqlalchemy-spanner/test_migration_env.py b/packages/sqlalchemy-spanner/test_migration_env.py index 883ebc1e0145..a87e356b7654 100644 --- a/packages/sqlalchemy-spanner/test_migration_env.py +++ b/packages/sqlalchemy-spanner/test_migration_env.py @@ -1,3 +1,17 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from logging.config import fileConfig from sqlalchemy import engine_from_config From 91f3fc76a2c5ba99cb266c978e997c5a46d6fb0a Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 13 Aug 2021 10:51:54 +0300 Subject: [PATCH 090/582] Create BENCHMARKS.md (#102) --- packages/sqlalchemy-spanner/BENCHMARKS.md | 24 +++++++++++++++++++ packages/sqlalchemy-spanner/test/benchmark.py | 17 ++++++++----- 2 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 packages/sqlalchemy-spanner/BENCHMARKS.md diff --git a/packages/sqlalchemy-spanner/BENCHMARKS.md b/packages/sqlalchemy-spanner/BENCHMARKS.md new file mode 100644 index 000000000000..2d7c4f204c8b --- /dev/null +++ b/packages/sqlalchemy-spanner/BENCHMARKS.md @@ -0,0 +1,24 @@ +# Benchmarks + +The performance test suite is located in [test/benchmark.py](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/test/benchmark.py) and intended to compare execution time difference between SQLAlchemy dialect for Spanner and pure Spanner client. + +The test suite requirements: +- `scipy` Python package installed +- the original dialect requirements + +Use `PROJECT`, `INSTANCE` and `DATABASE` module constants to set a project to execute tests on. + +# 07-11-2021 + +|Test|mean, sec|error|std_dev| +|----|-------|-----|--------| +|SPANNER insert_one_row_with_fetch_after| 0.91|0.01|0.09| +|ALCHEMY insert_one_row_with_fetch_after| 1.07| 0.0|0.03| +|SPANNER read_one_row| 0.33| 0.0| 0.01| +|ALCHEMY read_one_row| 0.3| 0.0| 0.01| +|SPANNER insert_many_rows| 1.37| 0.02| 0.12| +|ALCHEMY insert_many_rows| 24.41| 0.07| 0.49| +|SPANNER select_many_rows| 0.31| 0.02| 0.08| +|ALCHEMY select_many_rows| 0.22| 0.03| 0.01| +|SPANNER insert_many_rows_with_mutations| 0.34| 0.0| 0.03| +|SQLALCHEMY insert_many_rows_with_mutations| 25.1| 0.03| 0.31| diff --git a/packages/sqlalchemy-spanner/test/benchmark.py b/packages/sqlalchemy-spanner/test/benchmark.py index be027adedd8b..b600e790f0a5 100644 --- a/packages/sqlalchemy-spanner/test/benchmark.py +++ b/packages/sqlalchemy-spanner/test/benchmark.py @@ -34,6 +34,10 @@ Table, ) +PROJECT = "project-id" +INSTANCE = "instance-id" +DATABASE = "database-id" + def measure_execution_time(function): """Decorator to measure a wrapped method execution time.""" @@ -73,13 +77,13 @@ def __init__(self): def _cleanup(self): """Drop the test table.""" - conn = spanner_dbapi.connect("sqlalchemy-dialect-test", "compliance-test") + conn = spanner_dbapi.connect(INSTANCE, DATABASE) conn.database.update_ddl(["DROP TABLE Singers"]) conn.close() def _create_table(self): """Create a table for performace testing.""" - conn = spanner_dbapi.connect("sqlalchemy-dialect-test", "compliance-test") + conn = spanner_dbapi.connect(INSTANCE, DATABASE) conn.database.update_ddl( [ """ @@ -118,8 +122,8 @@ class SpannerBenchmarkTest(BenchmarkTestBase): def __init__(self): super().__init__() self._client = Client() - self._instance = self._client.instance("sqlalchemy-dialect-test") - self._database = self._instance.database("compliance-test") + self._instance = self._client.instance(INSTANCE) + self._database = self._instance.database(DATABASE) self._many_rows = [] self._many_rows2 = [] @@ -177,8 +181,9 @@ class SQLAlchemyBenchmarkTest(BenchmarkTestBase): def __init__(self): super().__init__() self._engine = create_engine( - "spanner:///projects/appdev-soda-spanner-staging/instances/" - "sqlalchemy-dialect-test/databases/compliance-test" + "spanner:///projects/{project}/instances/{instance}/databases/{db}".format( + project=PROJECT, instance=INSTANCE, db=DATABASE, + ) ) metadata = MetaData(bind=self._engine) self._table = Table("Singers", metadata, autoload=True) From 88780a8c7e8114cc76f7ac56ce36a89d310745ac Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Wed, 25 Aug 2021 19:51:45 +1200 Subject: [PATCH 091/582] test: remove pytz dependency (#108) Co-authored-by: larkee --- packages/sqlalchemy-spanner/test/test_suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 51d345225491..906b20fa2a75 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,11 +14,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +from datetime import timezone import decimal import operator import os import pytest -import pytz from unittest import mock import sqlalchemy @@ -945,7 +945,7 @@ def test_row_w_scalar_select(self): eq_( row["somelabel"], - DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=pytz.UTC), + DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=timezone.utc), ) From cf03f5ed1943cecfd54d92822a98b06b10b5ee2b Mon Sep 17 00:00:00 2001 From: "google-cloud-policy-bot[bot]" <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> Date: Thu, 2 Sep 2021 17:17:29 -0600 Subject: [PATCH 092/582] chore: add SECURITY.md (#111) Co-authored-by: google-cloud-policy-bot[bot] <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/SECURITY.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/sqlalchemy-spanner/SECURITY.md diff --git a/packages/sqlalchemy-spanner/SECURITY.md b/packages/sqlalchemy-spanner/SECURITY.md new file mode 100644 index 000000000000..8b58ae9c01ae --- /dev/null +++ b/packages/sqlalchemy-spanner/SECURITY.md @@ -0,0 +1,7 @@ +# Security Policy + +To report a security issue, please use [g.co/vulnz](https://g.co/vulnz). + +The Google Security Team will respond within 5 working days of your report on g.co/vulnz. + +We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue. From 2d65d82eadf2f6c66da39247e7b6b24831fd200b Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Tue, 7 Sep 2021 17:37:59 -0600 Subject: [PATCH 093/582] chore: create sync-repo-settings (#114) This repo does not use Kokoro for presubmits, so it needs a set of requiredStatusCheckContexts different from [the default](https://github.com/googleapis/repo-automation-bots/blob/21bd620e5e09f3bc6e98995bcd1bce6c9c9ee51a/packages/sync-repo-settings/src/required-checks.json#L45-L48) for Python. --- .../.github/sync-repo-settings.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml new file mode 100644 index 000000000000..7ce8f88491a5 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -0,0 +1,12 @@ +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings +# Rules for main branch protection +branchProtectionRules: +# Identifies the protection rule pattern. Name of the branch to be protected. +# Defaults to `main` +- pattern: main + requiresCodeOwnerReviews: true + requiresStrictStatusChecks: true + requiredStatusCheckContexts: + - 'tests' + - 'cla/google' + - 'ci/circleci: build-and-test' From 90eb84c4e1a6cbb151782f346ea74d0991473b47 Mon Sep 17 00:00:00 2001 From: "google-cloud-policy-bot[bot]" <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> Date: Wed, 8 Sep 2021 02:54:25 +0000 Subject: [PATCH 094/582] chore: add a Code of Conduct (#110) chore: add a Code of Conduct --- .../sqlalchemy-spanner/CODE_OF_CONDUCT.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 packages/sqlalchemy-spanner/CODE_OF_CONDUCT.md diff --git a/packages/sqlalchemy-spanner/CODE_OF_CONDUCT.md b/packages/sqlalchemy-spanner/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..46b2a08ea6d1 --- /dev/null +++ b/packages/sqlalchemy-spanner/CODE_OF_CONDUCT.md @@ -0,0 +1,43 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, +and in the interest of fostering an open and welcoming community, +we pledge to respect all people who contribute through reporting issues, +posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project +a harassment-free experience for everyone, +regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, +such as physical or electronic +addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, +project maintainers commit themselves to fairly and consistently +applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct +may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by opening an issue +or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) From 5b484a0f0fa084d2d685134761d2b410b8580dc5 Mon Sep 17 00:00:00 2001 From: "google-cloud-policy-bot[bot]" <80869356+google-cloud-policy-bot[bot]@users.noreply.github.com> Date: Wed, 8 Sep 2021 05:40:26 +0000 Subject: [PATCH 095/582] chore: add CONTRIBUTING.md (#112) chore: add CONTRIBUTING.md --- packages/sqlalchemy-spanner/CONTRIBUTING.md | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/sqlalchemy-spanner/CONTRIBUTING.md diff --git a/packages/sqlalchemy-spanner/CONTRIBUTING.md b/packages/sqlalchemy-spanner/CONTRIBUTING.md new file mode 100644 index 000000000000..6272489dae31 --- /dev/null +++ b/packages/sqlalchemy-spanner/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows [Google's Open Source Community +Guidelines](https://opensource.google/conduct/). From 58fe99a29df7c221db90e89cc840ae5f9499929f Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 8 Sep 2021 12:39:19 +0300 Subject: [PATCH 096/582] feat: set user-agent string to distinguish SQLAlchemy requests (#116) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 4 +++- .../sqlalchemy-spanner/test/test_suite.py | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index c68332e8a9cb..0e372fa4e76d 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pkg_resources import re from sqlalchemy import types, ForeignKeyConstraint @@ -433,9 +434,10 @@ def create_connect_args(self, url): ), url.database, ) + dist = pkg_resources.get_distribution("sqlalchemy-spanner") return ( [match.group("instance"), match.group("database"), match.group("project")], - {}, + {"user_agent": dist.project_name + "/" + dist.version}, ) @engine_to_connection diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 906b20fa2a75..74345b720c8c 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -18,6 +18,7 @@ import decimal import operator import os +import pkg_resources import pytest from unittest import mock @@ -1525,3 +1526,23 @@ def test_interleave_on_delete_cascade(self): with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: client.create(self._engine) execute.assert_called_once_with(EXP_QUERY, []) + + +class UserAgentTest(fixtures.TestBase): + """Check that SQLAlchemy dialect uses correct user agent.""" + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData(bind=self._engine) + + def test_user_agent(self): + dist = pkg_resources.get_distribution("sqlalchemy-spanner") + + with self._engine.connect() as connection: + assert ( + connection.connection.instance._client._client_info.user_agent + == dist.project_name + "/" + dist.version + ) From ea425e1b4eb3b9d0826b447d2a7227dab8e64faa Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 10 Sep 2021 13:45:19 +0300 Subject: [PATCH 097/582] fix: rollback failed exception log (#106) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 0e372fa4e76d..45993354bd39 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -800,13 +800,12 @@ def do_rollback(self, dbapi_connection): To prevent rollback exception, don't rollback committed/rolled back transactions. """ - if ( - not isinstance(dbapi_connection, spanner_dbapi.Connection) - and dbapi_connection.connection._transaction - and ( - dbapi_connection.connection._transaction.rolled_back - or dbapi_connection.connection._transaction.committed - ) + if not isinstance(dbapi_connection, spanner_dbapi.Connection): + dbapi_connection = dbapi_connection.connection + + if dbapi_connection._transaction and ( + dbapi_connection._transaction.rolled_back + or dbapi_connection._transaction.committed ): pass else: From fdaec7063c686577c7e9f17760bbf24477ec4d4d Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 14 Sep 2021 10:41:36 +0300 Subject: [PATCH 098/582] test: don't fail on errors caused by massive test instance deletion (#120) --- .../create_test_database.py | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 498b54489d0a..a635b7ff86dc 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -18,6 +18,7 @@ import os import time +from google.api_core.exceptions import ResourceExhausted from google.cloud.spanner_v1 import Client from google.cloud.spanner_v1.instance import Instance @@ -37,8 +38,8 @@ CLIENT = Client(project=PROJECT) -def reap_old_instances(): - # Delete test instances that are older than four hours. +def delete_stale_test_instances(): + """Delete test instances that are older than four hours.""" cutoff = int(time.time()) - 4 * 60 * 60 instances_pbs = CLIENT.list_instances( "labels.python-spanner-sqlalchemy-systest:true" @@ -50,11 +51,19 @@ def reap_old_instances(): create_time = int(instance.labels["created"]) if create_time > cutoff: continue - # Backups are not used in sqlalchemy dialect test, therefore instance can just be deleted. - instance.delete() - - -def prep_instance(): + # Backups are not used in sqlalchemy dialect test, + # therefore instance can just be deleted. + try: + instance.delete() + except ResourceExhausted: + print( + "Unable to drop stale instance '{}'. May need manual delete.".format( + instance.instance_id + ) + ) + + +def create_test_instance(): configs = list(CLIENT.list_instance_configs()) if not USE_EMULATOR: # Filter out non "us" locations @@ -62,8 +71,12 @@ def prep_instance(): instance_config = configs[0].name create_time = str(int(time.time())) - unique_resource_id = '%s%d' % ('-', 1000 * time.time()) - instance_id = 'sqlalchemy-dialect-test' if USE_EMULATOR else "sqlalchemy-test" + unique_resource_id + unique_resource_id = "%s%d" % ("-", 1000 * time.time()) + instance_id = ( + "sqlalchemy-dialect-test" + if USE_EMULATOR + else "sqlalchemy-test" + unique_resource_id + ) labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} instance = CLIENT.instance(instance_id, instance_config, labels=labels) @@ -86,5 +99,5 @@ def prep_instance(): config.write(configfile) -reap_old_instances() -prep_instance() +delete_stale_test_instances() +create_test_instance() From 3ecf84f4bee90b1e56301dfb2884815915aded40 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 16 Sep 2021 05:46:25 +0300 Subject: [PATCH 099/582] fix: array columns reflection (#119) Fixes #118 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 42 +++++++++++++------ .../sqlalchemy-spanner/test/test_suite.py | 28 +++++++++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 45993354bd39..8a36210454b5 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -42,6 +42,7 @@ "STRING": types.String, "TIME": types.TIME, "TIMESTAMP": types.TIMESTAMP, + "ARRAY": types.ARRAY, } _type_map_inv = { @@ -476,28 +477,43 @@ def get_columns(self, connection, table_name, schema=None, **kw): columns = snap.execute_sql(sql) for col in columns: - if col[1].startswith("STRING"): - end = col[1].index(")") - size = int_from_size(col[1][7:end]) - type_ = _type_map["STRING"](length=size) - # add test creating a table with bytes - elif col[1].startswith("BYTES"): - end = col[1].index(")") - size = int_from_size(col[1][6:end]) - type_ = _type_map["BYTES"](length=size) - else: - type_ = _type_map[col[1]] - cols_desc.append( { "name": col[0], - "type": type_, + "type": self._designate_type(col[1]), "nullable": col[2] == "YES", "default": None, } ) return cols_desc + def _designate_type(self, str_repr): + """ + Designate an SQLAlchemy data type from a Spanner + string representation. + + Args: + str_repr (str): String representation of a type. + + Returns: + An SQLAlchemy data type. + """ + if str_repr.startswith("STRING"): + end = str_repr.index(")") + size = int_from_size(str_repr[7:end]) + return _type_map["STRING"](length=size) + # add test creating a table with bytes + elif str_repr.startswith("BYTES"): + end = str_repr.index(")") + size = int_from_size(str_repr[6:end]) + return _type_map["BYTES"](length=size) + elif str_repr.startswith("ARRAY"): + inner_type_str = str_repr[6:-1] + inner_type = self._designate_type(inner_type_str) + return _type_map["ARRAY"](inner_type) + else: + return _type_map[str_repr] + @engine_to_connection def get_indexes(self, connection, table_name, schema=None, **kw): """Get the table indexes. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 74345b720c8c..aa8d3f250cfd 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -49,6 +49,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relation from sqlalchemy.orm import Session +from sqlalchemy.types import ARRAY from sqlalchemy.types import Integer from sqlalchemy.types import Numeric from sqlalchemy.types import Text @@ -901,6 +902,33 @@ def test_binary_reflection(self): assert isinstance(typ, LargeBinary) eq_(typ.length, 20) + @testing.requires.table_reflection + def test_array_reflection(self): + """Check array columns reflection.""" + orig_meta = self.metadata + + str_array = ARRAY(String(16)) + int_array = ARRAY(Integer) + Table( + "arrays_test", + orig_meta, + Column("id", Integer, primary_key=True), + Column("str_array", str_array), + Column("int_array", int_array), + ) + orig_meta.create_all() + + # autoload the table and check its columns reflection + tab = Table("arrays_test", orig_meta, autoload=True) + col_types = [col.type for col in tab.columns] + for type_ in ( + str_array, + int_array, + ): + assert type_ in col_types + + tab.drop() + class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): @testing.requires.foreign_key_constraint_reflection From b507b60db68465a5fe8818f0739d29d1607956d7 Mon Sep 17 00:00:00 2001 From: HemangChothani <50404902+HemangChothani@users.noreply.github.com> Date: Fri, 17 Sep 2021 14:03:19 +0530 Subject: [PATCH 100/582] feat: add code samples (#55) --- packages/sqlalchemy-spanner/CONTRIBUTING.md | 26 ++ packages/sqlalchemy-spanner/noxfile.py | 25 +- .../sqlalchemy-spanner/samples/__init__.py | 0 .../sqlalchemy-spanner/samples/conftest.py | 92 +++++ .../sqlalchemy-spanner/samples/snippets.py | 337 ++++++++++++++++++ .../samples/snippets_test.py | 227 ++++++++++++ 6 files changed, 706 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/samples/__init__.py create mode 100644 packages/sqlalchemy-spanner/samples/conftest.py create mode 100644 packages/sqlalchemy-spanner/samples/snippets.py create mode 100644 packages/sqlalchemy-spanner/samples/snippets_test.py diff --git a/packages/sqlalchemy-spanner/CONTRIBUTING.md b/packages/sqlalchemy-spanner/CONTRIBUTING.md index 6272489dae31..6294c4529e49 100644 --- a/packages/sqlalchemy-spanner/CONTRIBUTING.md +++ b/packages/sqlalchemy-spanner/CONTRIBUTING.md @@ -26,3 +26,29 @@ information on using pull requests. This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/). + +## Running tests + +SQLAlchemy Spanner dialect includes a test suite, which can be executed both on a live service and Spanner emulator. + +**Using pytest** +To execute the test suite with standard `pytest` package you only need to checkout to the package folder and run: +``` +pytest -v +``` + +**Using nox** +The package includes a configuration file for `nox` package, which allows to execute the dialect test suite in an isolated virtual environment. To execute all the `nox` sessions checkout to the dialect folder and then run command: +``` +nox +``` +To execute only the dialect compliance test suite execute command: +``` +nox -s compliance_test +``` + +**Live service** +To run the test suite on a live service use [setup.cfg](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/setup.cfg) `db.default` attribute to set URI of the project, instance and database, where the tests should be executed. + +**Emulator** +As the dialect is built on top of the Spanner DB API, it also supports running on Spanner emulator. To make it happen you need to set an environment variable, pointing to the emulator service, for example `SPANNER_EMULATOR_HOST=localhost:9010` \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 840998fdf7ec..d10f44cda496 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -64,7 +64,7 @@ class = StreamHandler BLACK_VERSION = "black==19.10b0" -BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py"] +BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] DEFAULT_PYTHON_VERSION = "3.8" @@ -178,3 +178,26 @@ def migration_test(session): session.run("python", "migration_test_cleanup.py") if os.path.exists("test.cfg"): os.remove("test.cfg") + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def snippets(session): + """Run the documentation example snippets.""" + # Sanity check: Only run snippets system tests if the environment variable + # is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): + session.skip("Credentials must be set via environment variable.") + + session.install("pytest") + session.install("sqlalchemy") + session.install( + "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" + ) + session.install("-e", ".") + session.run("python", "create_test_database.py") + session.run( + "py.test", + "--quiet", + os.path.join("samples", "snippets_test.py"), + *session.posargs, + ) diff --git a/packages/sqlalchemy-spanner/samples/__init__.py b/packages/sqlalchemy-spanner/samples/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/samples/conftest.py b/packages/sqlalchemy-spanner/samples/conftest.py new file mode 100644 index 000000000000..f3f0fcaae66b --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/conftest.py @@ -0,0 +1,92 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +import pytest + +from sqlalchemy import ( + Column, + Integer, + MetaData, + String, + Table, + create_engine, + ForeignKey, +) + + +@pytest.fixture +def db_url(): + return ( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + + +@pytest.fixture +def table_id(): + now = datetime.datetime.now() + table_id = "example_table_{}_{}".format( + now.strftime("%Y%m%d%H%M%S"), uuid.uuid4().hex[:8] + ) + return table_id + + +@pytest.fixture +def table(db_url, table_id): + engine = create_engine(db_url) + metadata = MetaData(bind=engine) + + table = Table( + table_id, + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + table.create() + yield table + table.drop() + + +@pytest.fixture +def table_w_foreign_key(db_url, table): + engine = create_engine(db_url) + metadata = MetaData(bind=engine) + + table_fk = Table( + "table_fk", + metadata, + Column("id", Integer, primary_key=True), + Column("name", String(16), nullable=False), + Column( + table.name + "_user_id", + Integer, + ForeignKey(table.c.user_id, name=table.name + "user_id"), + ), + ) + table_fk.create() + yield table_fk + table_fk.drop() + + +@pytest.fixture +def connection(db_url): + engine = create_engine(db_url) + return engine.connect() + + +def insert_data(conn, table, data): + conn.execute(table.insert(), data) diff --git a/packages/sqlalchemy-spanner/samples/snippets.py b/packages/sqlalchemy-spanner/samples/snippets.py new file mode 100644 index 000000000000..b309ea0b3ff6 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/snippets.py @@ -0,0 +1,337 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bs + +""" +This application demonstrates how to do basic operations with Cloud +Spanner database. +For more information, see the README.md under /python-spanner-sqlalchemy. +""" + +from sqlalchemy import ( + Column, + create_engine, + Index, + Integer, + inspect, + MetaData, + String, + Table, +) + + +# [START spanner_sqlalchemy_autocommit_on] +def enable_autocommit_mode(connection, url): + """Enable AUTOCOMMIT mode.""" + level = connection.get_isolation_level() + print("Connection default mode is {}.".format(level)) + + connection.execution_options(isolation_level="AUTOCOMMIT") + level = connection.get_isolation_level() + print("Connection mode is now {}.".format(level)) + + +# [END spanner_sqlalchemy_autocommit_on] + + +# [START spanner_sqlalchemy_create_table] +def create_table(url, table_id): + """Create a table.""" + engine = create_engine(url) + metadata = MetaData(bind=engine) + + table = Table( + table_id, + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + table.create() + + print("Table {} successfully created.".format(table.name)) + + +# [END spanner_sqlalchemy_create_table] + + +# [START spanner_sqlalchemy_drop_table] +def drop_table(table): + """Drop the table.""" + table.drop() + + print("Table {} successfully dropped.".format(table.name)) + + +# [END spanner_sqlalchemy_drop_table] + + +# [START spanner_sqlalchemy_get_table_names] +def get_table_names(url): + """Retrieve the list of the table names in the database. + + The table must already exist and can be created using + `create_table.` + """ + engine = create_engine(url) + insp = inspect(engine) + names = insp.get_table_names() + + print("Retrieved table names:") + for name in names: + print(name) + + +# [END spanner_sqlalchemy_get_table_names] + + +# [START spanner_sqlalchemy_create_unique_index] +def create_unique_index(table): + """Create unique index. + + The table must already exist and can be created using + `create_table.` + """ + index = Index("some_index", table.c.user_name, unique=True) + index.create() + print("Index created.") + + +# [END spanner_sqlalchemy_create_unique_index] + + +# [START spanner_sqlalchemy_delete_all_rows] +def delete_all_rows(connection, table): + """Delete all rows from the table. + + The table must already exist and can be created using + `create_table.` + """ + rows = connection.execute(table.select()).fetchall() + print("Row count:", len(rows)) + + connection.execute(table.delete()) + + rows = connection.execute(table.select()).fetchall() + print("Row count after deletion:", len(rows)) + + +# [END spanner_sqlalchemy_delete_all_rows] + + +# [START spanner_sqlalchemy_delete_row] +def delete_row_with_where_clause(connection, table): + """Delete a row. + + The table must already exist and can be created using + `create_table.` + """ + rows = connection.execute(table.select()).fetchall() + print("Row count:", len(rows)) + + connection.execute(table.delete().where(table.c.user_id == 1)) + + rows = connection.execute(table.select()).fetchall() + print("Row count after deletion:", len(rows)) + + +# [END spanner_sqlalchemy_delete_row] + + +# [START spanner_sqlalchemy_table_exists] +def table_exists(table): + """Check the table exists. + + The table must already exist and can be created using + `create_table.` + """ + result = table.exists() + if result is True: + print("Table exists.") + + +# [END spanner_sqlalchemy_table_exists] + + +# [START spanner_sqlalchemy_fetch_rows] +def fetch_rows(connection, table): + """Fetch all rows from the table. + + The table must already exist and can be created using + `create_table.` + """ + rows = connection.execute(table.select()).fetchall() + + print("Fetched rows: ", rows) + + +# [END spanner_sqlalchemy_fetch_rows] + + +# [START spanner_sqlalchemy_fetch_row] +def fetch_row_with_where_clause(connection, table): + """Fetch row with a WHERE clause. + + The table must already exist and can be created using + `create_table.` + """ + row = list(connection.execute(table.select().where(table.c.user_id == 1))) + + print("Fetched row: ", row) + + +# [END spanner_sqlalchemy_fetch_row] + + +# [START spanner_sqlalchemy_fetch_rows_with_limit_offset] +def fetch_rows_with_limit_offset(connection, table): + """Fetch rows from the table with LIMIT and OFFSET clauses. + + The table must already exist and can be created using + `create_table.` + """ + rows = list(connection.execute(table.select().limit(2).offset(1))) + + print("Fetched rows: ", rows) + + +# [END spanner_sqlalchemy_fetch_rows_with_limit_offset] + + +# [START spanner_sqlalchemy_fetch_rows_with_order_by] +def fetch_rows_with_order_by(connection, table): + """Fetch all rows ordered. + + The table must already exist and can be created using + `create_table.` + """ + rows = list( + connection.execute(table.select().order_by(table.c.user_name)).fetchall() + ) + print("Ordered rows: ", rows) + + +# [END spanner_sqlalchemy_fetch_rows_with_order_by] + + +# [START spanner_sqlalchemy_filter_data_startswith] +def filter_data_startswith(connection, table): + """Filter data with STARTSWITH clause. + + The table must already exist and can be created using + `create_table.` + """ + rows = list( + connection.execute(table.select().where(table.c.user_name.startswith("abcd%"))) + ) + print("Fetched rows: ", rows) + + +# [END spanner_sqlalchemy_filter_data_startswith] + + +# [START spanner_sqlalchemy_get_table_columns] +def get_table_columns(url, table): + """Retrieve the list of columns of the table. + + The table must already exist and can be created using + `create_table.` + """ + engine = create_engine(url) + insp = inspect(engine) + columns = insp.get_columns(table.name) + + print("Fetched columns: ", columns) + + +# [END spanner_sqlalchemy_get_table_columns] + + +# [START spanner_sqlalchemy_get_foreign_key] +def get_table_foreign_key(url, table): + """Retrieve a Foreign Key. + + The table must already exist and can be created using + `create_table.` + """ + engine = create_engine(url) + insp = inspect(engine) + f_keys = insp.get_foreign_keys(table.name) + + if f_keys: + print("Fetched foreign keys: ", f_keys) + + +# [END spanner_sqlalchemy_get_foreign_key] + + +# [START spanner_sqlalchemy_get_indexes] +def get_table_indexes(url, table): + """Retrieve the table indexes. + + The table must already exist and can be created using + `create_table.` + """ + engine = create_engine(url) + insp = inspect(engine) + indexes = insp.get_indexes(table.name) + + if indexes: + print("Fetched indexes: ", indexes) + + +# [END spanner_sqlalchemy_get_indexes] + + +# [START spanner_sqlalchemy_get_primary_key] +def get_table_primary_key(url, table): + """Retrieve the table Primary Key. + + The table must already exist and can be created using + `create_table.` + """ + engine = create_engine(url) + insp = inspect(engine) + p_key = insp.get_pk_constraint(table.name) + + if p_key: + print("Fetched primary key: ", p_key) + + +# [END spanner_sqlalchemy_get_primary_key] + + +# [START spanner_sqlalchemy_insert_row] +def insert_row(connection, table): + """Insert row into the table. + + The table must already exist and can be created using + `create_table.` + """ + connection.execute(table.insert(), {"user_id": 1, "user_name": "ABC"}) + + row = list(connection.execute(table.select())) + + print("Inserted row: ", row) + + +# [END spanner_sqlalchemy_insert_row] + + +# [START spanner_sqlalchemy_update_row] +def update_row(connection, table): + """Update a row in the table. + + The table must already exist and can be created using + `create_table.` + """ + connection.execute( + table.update().where(table.c.user_id == 2).values(user_name="GEH") + ) + row = list(connection.execute(table.select().where(table.c.user_id == 2))) + + print("Updated row: ", row) + + +# [END spanner_sqlalchemy_update_row] diff --git a/packages/sqlalchemy-spanner/samples/snippets_test.py b/packages/sqlalchemy-spanner/samples/snippets_test.py new file mode 100644 index 000000000000..9866d638a3de --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/snippets_test.py @@ -0,0 +1,227 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bs + +from samples import snippets +from samples.conftest import insert_data +from sqlalchemy import ( + Column, + create_engine, + Index, + Integer, + inspect, + MetaData, + String, + Table, +) + +DATA = [ + {"user_id": 1, "user_name": "abcdefg"}, + {"user_id": 2, "user_name": "ab/cdefg"}, + {"user_id": 3, "user_name": "ab%cdefg"}, + {"user_id": 4, "user_name": "ab_cdefg"}, + {"user_id": 5, "user_name": "abcde/fg"}, + {"user_id": 6, "user_name": "abcde%fg"}, +] + + +def table_obj(database_url, tab_id): + """Helper to produce a `Table` object for the given table id.""" + engine = create_engine(database_url) + metadata = MetaData(bind=engine) + + table = Table( + tab_id, + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + return table + + +def test_enable_autocommit_mode(capsys, connection, db_url): + snippets.enable_autocommit_mode(connection, db_url) + + out, err = capsys.readouterr() + assert "Connection default mode is SERIALIZABLE" in out + assert "Connection mode is now AUTOCOMMIT" in out + + +def test_create_table(capsys, db_url, table_id): + snippets.create_table(db_url, table_id) + + out, err = capsys.readouterr() + assert "Table {} successfully created".format(table_id) in out + + table = table_obj(db_url, table_id) + assert table.exists() is True + table.drop() + + +def test_drop_table(capsys, db_url, table_id): + table = table_obj(db_url, table_id) + table.create() + + snippets.drop_table(table) + + out, err = capsys.readouterr() + assert "Table {} successfully dropped".format(table_id) in out + assert table.exists() is False + + +def test_get_table_names(capsys, db_url, table): + snippets.get_table_names(db_url) + + out, err = capsys.readouterr() + assert "Retrieved table names:" in out + assert table.name in out + + +def test_table_create_unique_index(capsys, db_url, table): + snippets.create_unique_index(table) + + engine = create_engine(db_url) + insp = inspect(engine) + indexes = insp.get_indexes(table.name) + + out, err = capsys.readouterr() + + assert "Index created" in out + assert indexes[0]["unique"] is True + + +def test_table_delete_all_rows(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.delete_all_rows(connection, table) + + out, err = capsys.readouterr() + assert "Row count: 6" in out + assert "Row count after deletion: 0" in out + + +def test_table_delete_row_with_where_clause(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.delete_row_with_where_clause(connection, table) + + out, err = capsys.readouterr() + assert "Row count: 6" in out + assert "Row count after deletion: 5" in out + + +def test_exists_table(capsys, table): + snippets.table_exists(table) + + out, err = capsys.readouterr() + assert "Table exists" in out + + +def test_table_fetch_rows(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.fetch_rows(connection, table) + + out, err = capsys.readouterr() + assert "Fetched rows:" in out + + for row in DATA: # check that all rows were fetched + assert str(tuple(row.values())) in out + + +def test_table_fetch_row_with_where_clause(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.fetch_row_with_where_clause(connection, table) + + out, err = capsys.readouterr() + assert str(tuple(DATA[0].values())) in out + + +def test_table_fetch_rows_with_limit_offset(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.fetch_rows_with_limit_offset(connection, table) + + out, err = capsys.readouterr() + assert "Fetched rows:" in out + assert str(tuple(DATA[1].values())) in out + assert str(tuple(DATA[2].values())) in out + + +def test_table_fetch_rows_with_order_by(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.fetch_rows_with_order_by(connection, table) + + out, err = capsys.readouterr() + assert "Ordered rows:" in out + + rows = [] + for row in sorted(DATA, key=lambda r: r["user_name"]): + rows.append(tuple(row.values())) + + assert str(rows) in out + + +def test_table_filter_data_startswith(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.filter_data_startswith(connection, table) + + out, err = capsys.readouterr() + assert "Fetched rows:" in out + + rows = [] + for ind in (0, 4, 5): + rows.append(tuple(DATA[ind].values())) + + assert str(rows) in out + + +def test_table_get_columns(capsys, db_url, table): + snippets.get_table_columns(db_url, table) + out, err = capsys.readouterr() + assert "Fetched columns:" in out + + for col in table.columns: + assert col.name in out + + +def test_table_get_foreign_key(capsys, db_url, table_w_foreign_key): + snippets.get_table_foreign_key(db_url, table_w_foreign_key) + out, err = capsys.readouterr() + + assert "Fetched foreign keys:" in out + + +def test_table_get_indexes(capsys, db_url, table): + index = Index("some_index", table.c.user_name, unique=True) + index.create() + + snippets.get_table_indexes(db_url, table) + out, err = capsys.readouterr() + + assert "Fetched indexes:" in out + + +def test_table_get_primary_key(capsys, db_url, table): + snippets.get_table_primary_key(db_url, table) + out, err = capsys.readouterr() + assert "Fetched primary key:" in out + + +def test_table_insert_row(capsys, connection, table): + snippets.insert_row(connection, table) + + out, err = capsys.readouterr() + assert "Inserted row:" in out + + rows = list(connection.execute(table.select())) + assert len(rows) == 1 + + +def test_table_update_row(capsys, connection, table): + insert_data(connection, table, DATA) + snippets.update_row(connection, table) + + out, err = capsys.readouterr() + assert "Updated row:" in out + + rows = list(connection.execute(table.select())) + rows[0][1] == "GEH" From fd0d81231a90274886007b03dc2ef44509a51cc2 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 11 Oct 2021 06:39:33 +0300 Subject: [PATCH 101/582] fix: ALTER COLUMN NOT NULL directive fails because of inappropriate syntax (#124) * fix: ALTER COLUMN NOT NULL directive fails because of inappropriate syntax * add alembic into nox session dependencies * alembic dependency --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 37 ++++++++++++++++++- .../migration_test_cleanup.py | 8 ++-- packages/sqlalchemy-spanner/noxfile.py | 6 +++ packages/sqlalchemy-spanner/setup.py | 6 ++- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 8a36210454b5..1d0cda07a862 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -15,10 +15,17 @@ import pkg_resources import re -from sqlalchemy import types, ForeignKeyConstraint +from alembic.ddl.base import ( + ColumnNullable, + ColumnType, + alter_column, + alter_table, + format_type, +) +from sqlalchemy import ForeignKeyConstraint, types, util from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect -from sqlalchemy import util +from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql.compiler import ( selectable, DDLCompiler, @@ -27,6 +34,7 @@ SQLCompiler, RESERVED_WORDS, ) + from google.cloud import spanner_dbapi from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call @@ -864,3 +872,28 @@ def do_execute_no_params(self, cursor, statement, context=None): } with trace_call("SpannerSqlAlchemy.ExecuteNoParams", trace_attributes): cursor.execute(statement) + + +# Alembic ALTER operation override +@compiles(ColumnNullable, "spanner") +def visit_column_nullable( + element: "ColumnNullable", compiler: "SpannerDDLCompiler", **kw +) -> str: + return "%s %s %s %s" % ( + alter_table(compiler, element.table_name, element.schema), + alter_column(compiler, element.column_name), + format_type(compiler, element.existing_type), + "" if element.nullable else "NOT NULL", + ) + + +# Alembic ALTER operation override +@compiles(ColumnType, "spanner") +def visit_column_type( + element: "ColumnType", compiler: "SpannerDDLCompiler", **kw +) -> str: + return "%s %s %s" % ( + alter_table(compiler, element.table_name, element.schema), + alter_column(compiler, element.column_name), + "%s" % format_type(compiler, element.type_), + ) diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py index 485f2a429eff..01a9a5281966 100644 --- a/packages/sqlalchemy-spanner/migration_test_cleanup.py +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -27,11 +27,11 @@ config.read("setup.cfg") db_url = config.get("db", "default") -project = re.findall(r'projects(.*?)instances', db_url) -instance_id = re.findall(r'instances(.*?)databases', db_url) +project = re.findall(r"projects(.*?)instances", db_url) +instance_id = re.findall(r"instances(.*?)databases", db_url) -client = spanner.Client(project="".join(project).replace('/', '')) -instance = client.instance(instance_id="".join(instance_id).replace('/', '')) +client = spanner.Client(project="".join(project).replace("/", "")) +instance = client.instance(instance_id="".join(instance_id).replace("/", "")) database = instance.database("compliance-test") database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index d10f44cda496..1e5eb9ede70d 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -60,6 +60,12 @@ class = StreamHandler sa.Column('id', sa.Integer, primary_key=True), sa.Column('name', sa.String(50), nullable=False), sa.Column('description', sa.Unicode(200)), + ) + op.alter_column( + 'account', + 'name', + existing_type=sa.String(50), + nullable=True, )""" diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 3852af3d5da7..09d67985117f 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -19,7 +19,11 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" -dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.3.0"] +dependencies = [ + "sqlalchemy>=1.1.13, <=1.3.23", + "google-cloud-spanner>=3.3.0", + "alembic", +] extras = { "tracing": [ "opentelemetry-api >= 1.1.0", From e4d71c1d5f7724273f5d4bed590ef2f1b04072ad Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 11 Oct 2021 14:56:16 +0300 Subject: [PATCH 102/582] feat: support read_only connections (#125) --- packages/sqlalchemy-spanner/README.md | 10 +++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 16 ++++++++++- .../sqlalchemy-spanner/test/test_suite.py | 28 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index f601c0770926..155d3094f32c 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -158,6 +158,16 @@ eng = create_engine("spanner:///projects/project-id/instances/instance-id/databa autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") ``` +**ReadOnly transactions** +By default, transactions produced by a Spanner connection are in ReadWrite mode. However, some applications require an ability to grant ReadOnly access to users/methods; for these cases Spanner dialect supports the `read_only` execution option, which switches a connection into ReadOnly mode: +```python +with engine.connect().execution_options(read_only=True) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() +``` +Note that execution options are applied lazily - on the `execute()` method call, right before it. + +ReadOnly/ReadWrite mode of a connection can't be changed while a transaction is in progress - first you must commit or rollback it. + **DDL and transactions** DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 1d0cda07a862..a9abec598dab 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -24,7 +24,7 @@ ) from sqlalchemy import ForeignKeyConstraint, types, util from sqlalchemy.engine.base import Engine -from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.engine.default import DefaultDialect, DefaultExecutionContext from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql.compiler import ( selectable, @@ -116,6 +116,19 @@ def wrapper(self, connection, *args, **kwargs): return wrapper +class SpannerExecutionContext(DefaultExecutionContext): + def pre_exec(self): + """ + Apply execution options to the DB API connection before + executing the next SQL operation. + """ + super(SpannerExecutionContext, self).pre_exec() + + read_only = self.execution_options.get("read_only", None) + if read_only is not None: + self._dbapi_connection.connection.read_only = read_only + + class SpannerIdentifierPreparer(IdentifierPreparer): """Identifiers compiler. @@ -393,6 +406,7 @@ class SpannerDialect(DefaultDialect): preparer = SpannerIdentifierPreparer statement_compiler = SpannerSQLCompiler type_compiler = SpannerTypeCompiler + execution_ctx_cls = SpannerExecutionContext @classmethod def dbapi(cls): diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index aa8d3f250cfd..500114c318fb 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1574,3 +1574,31 @@ def test_user_agent(self): connection.connection.instance._client._client_info.user_agent == dist.project_name + "/" + dist.version ) + + +class ExecutionOptionsTest(fixtures.TestBase): + """ + Check that `execution_options()` method correctly + sets parameters on the underlying DB API connection. + """ + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData(bind=self._engine) + + self._table = Table( + "execution_options", + self._metadata, + Column("opt_id", Integer, primary_key=True), + Column("opt_name", String(16), nullable=False), + ) + + self._metadata.create_all(self._engine) + + def test_read_only(self): + with self._engine.connect().execution_options(read_only=True) as connection: + connection.execute(select(["*"], from_obj=self._table)).fetchall() + assert connection.connection.read_only is True From eed94b7d688e61551975d4dd93f3f878ba8bb021 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 13 Oct 2021 10:57:53 +1100 Subject: [PATCH 103/582] chore: setup autorelease (#113) Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/build.sh | 36 ++ .../.kokoro/continuous/common.cfg | 27 + .../.kokoro/continuous/continuous.cfg | 1 + .../.kokoro/docker/docs/Dockerfile | 59 +++ .../.kokoro/docker/docs/fetch_gpg_keys.sh | 37 ++ .../.kokoro/docs/common.cfg | 63 +++ .../.kokoro/docs/docs-presubmit.cfg | 28 + .../sqlalchemy-spanner/.kokoro/docs/docs.cfg | 1 + .../.kokoro/populate-secrets.sh | 35 ++ .../.kokoro/presubmit/common.cfg | 27 + .../.kokoro/presubmit/presubmit.cfg | 7 + .../.kokoro/presubmit/system-3.8.cfg | 7 + .../.kokoro/publish-docs.sh | 56 ++ .../sqlalchemy-spanner/.kokoro/release.sh | 24 + .../.kokoro/release/common.cfg | 30 ++ .../.kokoro/release/release.cfg | 1 + .../sqlalchemy-spanner/.kokoro/trampoline.sh | 20 + .../.kokoro/trampoline_v2.sh | 479 ++++++++++++++++++ 18 files changed, 938 insertions(+) create mode 100755 packages/sqlalchemy-spanner/.kokoro/build.sh create mode 100644 packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile create mode 100755 packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh create mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/common.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg create mode 100755 packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh create mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg create mode 100755 packages/sqlalchemy-spanner/.kokoro/publish-docs.sh create mode 100755 packages/sqlalchemy-spanner/.kokoro/release.sh create mode 100644 packages/sqlalchemy-spanner/.kokoro/release/common.cfg create mode 100644 packages/sqlalchemy-spanner/.kokoro/release/release.cfg create mode 100755 packages/sqlalchemy-spanner/.kokoro/trampoline.sh create mode 100755 packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh new file mode 100755 index 000000000000..5f57c204506d --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +set -eo pipefail + +if [[ -z "${PROJECT_ROOT:-}" ]]; then + PROJECT_ROOT="github/python-spanner-sqlalchemy" +fi + +cd "${PROJECT_ROOT}" + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Setup service account credentials. +export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json +export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") +export GOOGLE_CLOUD_PROJECT=$(cat "${KOKORO_GFILE_DIR}/project-id.json") + +export RUNNING_SPANNER_BACKEND_TESTS=1 + +if [[ $KOKORO_JOB_NAME == *"docs"* ]] +then + echo "Running docs generation." + # Remove old nox + python3 -m pip uninstall --yes --quiet nox-automation + + # Install nox + python3 -m pip install --upgrade --quiet nox + # Generate docs. + python3 -m nox -s docs docfx +fi diff --git a/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg b/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg new file mode 100644 index 000000000000..3af6b61876e7 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg @@ -0,0 +1,27 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Download resources for system tests (service account key, etc.) +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" + +# Use the trampoline script to run in docker. +build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg b/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg new file mode 100644 index 000000000000..18a4c35325b8 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto diff --git a/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile b/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile new file mode 100644 index 000000000000..cf3922d790f1 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile @@ -0,0 +1,59 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +from ubuntu:20.04 + +ENV DEBIAN_FRONTEND noninteractive + +# Ensure local Python is preferred over distribution Python. +ENV PATH /usr/local/bin:$PATH + +# Install dependencies. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + apt-transport-https \ + build-essential \ + ca-certificates \ + curl \ + dirmngr \ + git \ + gpg-agent \ + graphviz \ + libbz2-dev \ + libdb5.3-dev \ + libexpat1-dev \ + libffi-dev \ + liblzma-dev \ + libreadline-dev \ + libsnappy-dev \ + libssl-dev \ + libsqlite3-dev \ + portaudio19-dev \ + python3-distutils \ + redis-server \ + software-properties-common \ + ssh \ + sudo \ + tcl \ + tcl-dev \ + tk \ + tk-dev \ + uuid-dev \ + wget \ + zlib1g-dev \ + && add-apt-repository universe \ + && apt-get update \ + && apt-get -y install jq \ + && apt-get clean autoclean \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* \ + && rm -f /var/cache/apt/archives/*.deb + +RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ + && python3.8 /tmp/get-pip.py \ + && rm /tmp/get-pip.py + +CMD ["python3.8"] diff --git a/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh b/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh new file mode 100755 index 000000000000..2b2b7e953816 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# A script to fetch gpg keys with retry. +# Avoid jinja parsing the file. +# + +function retry { + if [[ "${#}" -le 1 ]]; then + echo "Usage: ${0} retry_count commands.." + exit 1 + fi + local retries=${1} + local command="${@:2}" + until [[ "${retries}" -le 0 ]]; do + $command && return 0 + if [[ $? -ne 0 ]]; then + echo "command failed, retrying" + ((retries--)) + fi + done + return 1 +} + +# 3.6.9, 3.7.5 (Ned Deily) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D + +# 3.8.0 (Łukasz Langa) +retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ + E3FF2839C048B25C084DEBE9B26995E310250568 + +# diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg new file mode 100644 index 000000000000..76db11b1901c --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg @@ -0,0 +1,63 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "python-spanner-sqlalchemy/.kokoro/trampoline_v2.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-spanner-sqlalchemy/.kokoro/publish-docs.sh" +} + +env_vars: { + key: "STAGING_BUCKET" + value: "docs-staging" +} + +env_vars: { + key: "V2_STAGING_BUCKET" + value: "docs-staging-v2" +} + +# It will upload the docker image after successful builds. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "true" +} + +# It will always build the docker image. +env_vars: { + key: "TRAMPOLINE_DOCKERFILE" + value: ".kokoro/docker/docs/Dockerfile" +} + +# Fetch the token needed for reporting release status to GitHub +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "yoshi-automation-github-key" + } + } +} + +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "docuploader_service_account" + } + } +} diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg new file mode 100644 index 000000000000..5e07943d6308 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg @@ -0,0 +1,28 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "STAGING_BUCKET" + value: "gcloud-python-test" +} + +env_vars: { + key: "V2_STAGING_BUCKET" + value: "gcloud-python-test" +} + +# We only upload the image in the main `docs` build. +env_vars: { + key: "TRAMPOLINE_IMAGE_UPLOAD" + value: "false" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" +} + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "docs docfx" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh b/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh new file mode 100755 index 000000000000..bf0be603a62b --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +set -eo pipefail + +function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} +function msg { println "$*" >&2 ;} +function println { printf '%s\n' "$(now) $*" ;} + + +# Populates requested secrets set in SECRET_MANAGER_KEYS from service account: +# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com +SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" +msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" +mkdir -p ${SECRET_LOCATION} +for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") +do + msg "Retrieving secret ${key}" + docker run --entrypoint=gcloud \ + --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ + gcr.io/google.com/cloudsdktool/cloud-sdk \ + secrets versions access latest \ + --project cloud-devrel-kokoro-resources \ + --secret ${key} > \ + "${SECRET_LOCATION}/${key}" + if [[ $? == 0 ]]; then + msg "Secret written to ${SECRET_LOCATION}/${key}" + else + msg "Error retrieving secret ${key}" + fi +done diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg new file mode 100644 index 000000000000..3af6b61876e7 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg @@ -0,0 +1,27 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Download resources for system tests (service account key, etc.) +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" + +# Use the trampoline script to run in docker. +build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg new file mode 100644 index 000000000000..b158096f0ae2 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Disable system tests. +env_vars: { + key: "RUN_SYSTEM_TESTS" + value: "false" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg new file mode 100644 index 000000000000..5213a568eea5 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Only run this nox session. +env_vars: { + key: "NOX_SESSION" + value: "system-3.8" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh b/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh new file mode 100755 index 000000000000..41e4460df98a --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +set -eo pipefail + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +export PATH="${HOME}/.local/bin:${PATH}" + +# Install nox +python3 -m pip install --user --upgrade --quiet nox +python3 -m nox --version + +# build docs +nox -s docs + +python3 -m pip install --user gcp-docuploader + +# create metadata +python3 -m docuploader create-metadata \ + --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --version=$(python3 setup.py --version) \ + --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + --distribution-name=$(python3 setup.py --name) \ + --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + +cat docs.metadata + +# upload docs +python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" + + +# docfx yaml files +nox -s docfx + +# create metadata. +python3 -m docuploader create-metadata \ + --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ + --version=$(python3 setup.py --version) \ + --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ + --distribution-name=$(python3 setup.py --name) \ + --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ + --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ + --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) + +cat docs.metadata + +# upload docs +python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" diff --git a/packages/sqlalchemy-spanner/.kokoro/release.sh b/packages/sqlalchemy-spanner/.kokoro/release.sh new file mode 100755 index 000000000000..c03a31f09eb0 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/release.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +set -eo pipefail + +# Start the releasetool reporter +python3 -m pip install gcp-releasetool +python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script + +# Ensure that we have the latest versions of Twine, Wheel, and Setuptools. +python3 -m pip install --upgrade twine wheel setuptools + +# Disable buffering, so that the logs stream through. +export PYTHONUNBUFFERED=1 + +# Move into the package, build the distribution and upload. +TWINE_PASSWORD=$(cat "${KOKORO_GFILE_DIR}/secret_manager/google-cloud-pypi-token") +cd github/python-spanner-sqlalchemy +python3 setup.py sdist bdist_wheel +twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/sqlalchemy-spanner/.kokoro/release/common.cfg b/packages/sqlalchemy-spanner/.kokoro/release/common.cfg new file mode 100644 index 000000000000..9a818a878c82 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/release/common.cfg @@ -0,0 +1,30 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" +} +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-spanner-sqlalchemy/.kokoro/release.sh" +} + +# Tokens needed to report release status back to GitHub +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem,google-cloud-pypi-token" +} diff --git a/packages/sqlalchemy-spanner/.kokoro/release/release.cfg b/packages/sqlalchemy-spanner/.kokoro/release/release.cfg new file mode 100644 index 000000000000..8f43917d92fe --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/release/release.cfg @@ -0,0 +1 @@ +# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.kokoro/trampoline.sh b/packages/sqlalchemy-spanner/.kokoro/trampoline.sh new file mode 100755 index 000000000000..427c287ff2c8 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/trampoline.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +set -eo pipefail + +# Always run the cleanup script, regardless of the success of bouncing into +# the container. +function cleanup() { + chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + echo "cleanup"; +} +trap cleanup EXIT + +$(dirname $0)/populate-secrets.sh # Secret Manager secrets. +python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" diff --git a/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh b/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh new file mode 100755 index 000000000000..957848c45353 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh @@ -0,0 +1,479 @@ +#!/usr/bin/env bash +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +# trampoline_v2.sh +# +# This script does 3 things. +# +# 1. Prepare the Docker image for the test +# 2. Run the Docker with appropriate flags to run the test +# 3. Upload the newly built Docker image +# +# in a way that is somewhat compatible with trampoline_v1. +# +# To run this script, first download few files from gcs to /dev/shm. +# (/dev/shm is passed into the container as KOKORO_GFILE_DIR). +# +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/secrets_viewer_service_account.json /dev/shm +# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/automl_secrets.txt /dev/shm +# +# Then run the script. +# .kokoro/trampoline_v2.sh +# +# These environment variables are required: +# TRAMPOLINE_IMAGE: The docker image to use. +# TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. +# +# You can optionally change these environment variables: +# TRAMPOLINE_IMAGE_UPLOAD: +# (true|false): Whether to upload the Docker image after the +# successful builds. +# TRAMPOLINE_BUILD_FILE: The script to run in the docker container. +# TRAMPOLINE_WORKSPACE: The workspace path in the docker container. +# Defaults to /workspace. +# Potentially there are some repo specific envvars in .trampolinerc in +# the project root. + + +set -euo pipefail + +TRAMPOLINE_VERSION="2.0.5" + +if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then + readonly IO_COLOR_RED="$(tput setaf 1)" + readonly IO_COLOR_GREEN="$(tput setaf 2)" + readonly IO_COLOR_YELLOW="$(tput setaf 3)" + readonly IO_COLOR_RESET="$(tput sgr0)" +else + readonly IO_COLOR_RED="" + readonly IO_COLOR_GREEN="" + readonly IO_COLOR_YELLOW="" + readonly IO_COLOR_RESET="" +fi + +function function_exists { + [ $(LC_ALL=C type -t $1)"" == "function" ] +} + +# Logs a message using the given color. The first argument must be one +# of the IO_COLOR_* variables defined above, such as +# "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the +# given color. The log message will also have an RFC-3339 timestamp +# prepended (in UTC). You can disable the color output by setting +# TERM=vt100. +function log_impl() { + local color="$1" + shift + local timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" + echo "================================================================" + echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" + echo "================================================================" +} + +# Logs the given message with normal coloring and a timestamp. +function log() { + log_impl "${IO_COLOR_RESET}" "$@" +} + +# Logs the given message in green with a timestamp. +function log_green() { + log_impl "${IO_COLOR_GREEN}" "$@" +} + +# Logs the given message in yellow with a timestamp. +function log_yellow() { + log_impl "${IO_COLOR_YELLOW}" "$@" +} + +# Logs the given message in red with a timestamp. +function log_red() { + log_impl "${IO_COLOR_RED}" "$@" +} + +readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) +readonly tmphome="${tmpdir}/h" +mkdir -p "${tmphome}" + +function cleanup() { + rm -rf "${tmpdir}" +} +trap cleanup EXIT + +RUNNING_IN_CI="${RUNNING_IN_CI:-false}" + +# The workspace in the container, defaults to /workspace. +TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" + +pass_down_envvars=( + # TRAMPOLINE_V2 variables. + # Tells scripts whether they are running as part of CI or not. + "RUNNING_IN_CI" + # Indicates which CI system we're in. + "TRAMPOLINE_CI" + # Indicates the version of the script. + "TRAMPOLINE_VERSION" +) + +log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" + +# Detect which CI systems we're in. If we're in any of the CI systems +# we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be +# the name of the CI system. Both envvars will be passing down to the +# container for telling which CI system we're in. +if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then + # descriptive env var for indicating it's on CI. + RUNNING_IN_CI="true" + TRAMPOLINE_CI="kokoro" + if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then + if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then + log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." + exit 1 + fi + # This service account will be activated later. + TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" + else + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + gcloud auth list + fi + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet + fi + pass_down_envvars+=( + # KOKORO dynamic variables. + "KOKORO_BUILD_NUMBER" + "KOKORO_BUILD_ID" + "KOKORO_JOB_NAME" + "KOKORO_GIT_COMMIT" + "KOKORO_GITHUB_COMMIT" + "KOKORO_GITHUB_PULL_REQUEST_NUMBER" + "KOKORO_GITHUB_PULL_REQUEST_COMMIT" + # For FlakyBot + "KOKORO_GITHUB_COMMIT_URL" + "KOKORO_GITHUB_PULL_REQUEST_URL" + ) +elif [[ "${TRAVIS:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="travis" + pass_down_envvars+=( + "TRAVIS_BRANCH" + "TRAVIS_BUILD_ID" + "TRAVIS_BUILD_NUMBER" + "TRAVIS_BUILD_WEB_URL" + "TRAVIS_COMMIT" + "TRAVIS_COMMIT_MESSAGE" + "TRAVIS_COMMIT_RANGE" + "TRAVIS_JOB_NAME" + "TRAVIS_JOB_NUMBER" + "TRAVIS_JOB_WEB_URL" + "TRAVIS_PULL_REQUEST" + "TRAVIS_PULL_REQUEST_BRANCH" + "TRAVIS_PULL_REQUEST_SHA" + "TRAVIS_PULL_REQUEST_SLUG" + "TRAVIS_REPO_SLUG" + "TRAVIS_SECURE_ENV_VARS" + "TRAVIS_TAG" + ) +elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="github-workflow" + pass_down_envvars+=( + "GITHUB_WORKFLOW" + "GITHUB_RUN_ID" + "GITHUB_RUN_NUMBER" + "GITHUB_ACTION" + "GITHUB_ACTIONS" + "GITHUB_ACTOR" + "GITHUB_REPOSITORY" + "GITHUB_EVENT_NAME" + "GITHUB_EVENT_PATH" + "GITHUB_SHA" + "GITHUB_REF" + "GITHUB_HEAD_REF" + "GITHUB_BASE_REF" + ) +elif [[ "${CIRCLECI:-}" == "true" ]]; then + RUNNING_IN_CI="true" + TRAMPOLINE_CI="circleci" + pass_down_envvars+=( + "CIRCLE_BRANCH" + "CIRCLE_BUILD_NUM" + "CIRCLE_BUILD_URL" + "CIRCLE_COMPARE_URL" + "CIRCLE_JOB" + "CIRCLE_NODE_INDEX" + "CIRCLE_NODE_TOTAL" + "CIRCLE_PREVIOUS_BUILD_NUM" + "CIRCLE_PROJECT_REPONAME" + "CIRCLE_PROJECT_USERNAME" + "CIRCLE_REPOSITORY_URL" + "CIRCLE_SHA1" + "CIRCLE_STAGE" + "CIRCLE_USERNAME" + "CIRCLE_WORKFLOW_ID" + "CIRCLE_WORKFLOW_JOB_ID" + "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" + "CIRCLE_WORKFLOW_WORKSPACE_ID" + ) +fi + +# Configure the service account for pulling the docker image. +function repo_root() { + local dir="$1" + while [[ ! -d "${dir}/.git" ]]; do + dir="$(dirname "$dir")" + done + echo "${dir}" +} + +# Detect the project root. In CI builds, we assume the script is in +# the git tree and traverse from there, otherwise, traverse from `pwd` +# to find `.git` directory. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + PROGRAM_PATH="$(realpath "$0")" + PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" + PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" +else + PROJECT_ROOT="$(repo_root $(pwd))" +fi + +log_yellow "Changing to the project root: ${PROJECT_ROOT}." +cd "${PROJECT_ROOT}" + +# To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need +# to use this environment variable in `PROJECT_ROOT`. +if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then + + mkdir -p "${tmpdir}/gcloud" + gcloud_config_dir="${tmpdir}/gcloud" + + log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." + export CLOUDSDK_CONFIG="${gcloud_config_dir}" + + log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." + gcloud auth activate-service-account \ + --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" + log_yellow "Configuring Container Registry access" + gcloud auth configure-docker --quiet +fi + +required_envvars=( + # The basic trampoline configurations. + "TRAMPOLINE_IMAGE" + "TRAMPOLINE_BUILD_FILE" +) + +if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then + source "${PROJECT_ROOT}/.trampolinerc" +fi + +log_yellow "Checking environment variables." +for e in "${required_envvars[@]}" +do + if [[ -z "${!e:-}" ]]; then + log "Missing ${e} env var. Aborting." + exit 1 + fi +done + +# We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 +# script: e.g. "github/repo-name/.kokoro/run_tests.sh" +TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" +log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" + +# ignore error on docker operations and test execution +set +e + +log_yellow "Preparing Docker image." +# We only download the docker image in CI builds. +if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + # Download the docker image specified by `TRAMPOLINE_IMAGE` + + # We may want to add --max-concurrent-downloads flag. + + log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." + if docker pull "${TRAMPOLINE_IMAGE}"; then + log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="true" + else + log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." + has_image="false" + fi +else + # For local run, check if we have the image. + if docker images "${TRAMPOLINE_IMAGE}:latest" | grep "${TRAMPOLINE_IMAGE}"; then + has_image="true" + else + has_image="false" + fi +fi + + +# The default user for a Docker container has uid 0 (root). To avoid +# creating root-owned files in the build directory we tell docker to +# use the current user ID. +user_uid="$(id -u)" +user_gid="$(id -g)" +user_name="$(id -un)" + +# To allow docker in docker, we add the user to the docker group in +# the host os. +docker_gid=$(cut -d: -f3 < <(getent group docker)) + +update_cache="false" +if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then + # Build the Docker image from the source. + context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") + docker_build_flags=( + "-f" "${TRAMPOLINE_DOCKERFILE}" + "-t" "${TRAMPOLINE_IMAGE}" + "--build-arg" "UID=${user_uid}" + "--build-arg" "USERNAME=${user_name}" + ) + if [[ "${has_image}" == "true" ]]; then + docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") + fi + + log_yellow "Start building the docker image." + if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then + echo "docker build" "${docker_build_flags[@]}" "${context_dir}" + fi + + # ON CI systems, we want to suppress docker build logs, only + # output the logs when it fails. + if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then + if docker build "${docker_build_flags[@]}" "${context_dir}" \ + > "${tmpdir}/docker_build.log" 2>&1; then + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + cat "${tmpdir}/docker_build.log" + fi + + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + log_yellow "Dumping the build logs:" + cat "${tmpdir}/docker_build.log" + exit 1 + fi + else + if docker build "${docker_build_flags[@]}" "${context_dir}"; then + log_green "Finished building the docker image." + update_cache="true" + else + log_red "Failed to build the Docker image, aborting." + exit 1 + fi + fi +else + if [[ "${has_image}" != "true" ]]; then + log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." + exit 1 + fi +fi + +# We use an array for the flags so they are easier to document. +docker_flags=( + # Remove the container after it exists. + "--rm" + + # Use the host network. + "--network=host" + + # Run in priviledged mode. We are not using docker for sandboxing or + # isolation, just for packaging our dev tools. + "--privileged" + + # Run the docker script with the user id. Because the docker image gets to + # write in ${PWD} you typically want this to be your user id. + # To allow docker in docker, we need to use docker gid on the host. + "--user" "${user_uid}:${docker_gid}" + + # Pass down the USER. + "--env" "USER=${user_name}" + + # Mount the project directory inside the Docker container. + "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" + "--workdir" "${TRAMPOLINE_WORKSPACE}" + "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" + + # Mount the temporary home directory. + "--volume" "${tmphome}:/h" + "--env" "HOME=/h" + + # Allow docker in docker. + "--volume" "/var/run/docker.sock:/var/run/docker.sock" + + # Mount the /tmp so that docker in docker can mount the files + # there correctly. + "--volume" "/tmp:/tmp" + # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR + # TODO(tmatsuo): This part is not portable. + "--env" "TRAMPOLINE_SECRET_DIR=/secrets" + "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" + "--env" "KOKORO_GFILE_DIR=/secrets/gfile" + "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" + "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" +) + +# Add an option for nicer output if the build gets a tty. +if [[ -t 0 ]]; then + docker_flags+=("-it") +fi + +# Passing down env vars +for e in "${pass_down_envvars[@]}" +do + if [[ -n "${!e:-}" ]]; then + docker_flags+=("--env" "${e}=${!e}") + fi +done + +# If arguments are given, all arguments will become the commands run +# in the container, otherwise run TRAMPOLINE_BUILD_FILE. +if [[ $# -ge 1 ]]; then + log_yellow "Running the given commands '" "${@:1}" "' in the container." + readonly commands=("${@:1}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" +else + log_yellow "Running the tests in a Docker container." + docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") + if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then + echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" + fi + docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" +fi + + +test_retval=$? + +if [[ ${test_retval} -eq 0 ]]; then + log_green "Build finished with ${test_retval}" +else + log_red "Build finished with ${test_retval}" +fi + +# Only upload it when the test passes. +if [[ "${update_cache}" == "true" ]] && \ + [[ $test_retval == 0 ]] && \ + [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then + log_yellow "Uploading the Docker image." + if docker push "${TRAMPOLINE_IMAGE}"; then + log_green "Finished uploading the Docker image." + else + log_red "Failed uploading the Docker image." + fi + # Call trampoline_after_upload_hook if it's defined. + if function_exists trampoline_after_upload_hook; then + trampoline_after_upload_hook + fi + +fi + +exit "${test_retval}" From 94dc9948b27f37bb7ec9a64b698eabdd36ee0747 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 13 Oct 2021 02:00:07 +0200 Subject: [PATCH 104/582] Add renovate.json (#109) Co-authored-by: skuruppu --- packages/sqlalchemy-spanner/renovate.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/sqlalchemy-spanner/renovate.json diff --git a/packages/sqlalchemy-spanner/renovate.json b/packages/sqlalchemy-spanner/renovate.json new file mode 100644 index 000000000000..f45d8f110c30 --- /dev/null +++ b/packages/sqlalchemy-spanner/renovate.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "config:base" + ] +} From 4d6fb7db97a6d2a7dc312aea6e5d2c15f93b71e4 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 13 Oct 2021 11:04:47 +1100 Subject: [PATCH 105/582] chore: add CODEOWNERS (#130) --- packages/sqlalchemy-spanner/.github/CODEOWNERS | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.github/CODEOWNERS diff --git a/packages/sqlalchemy-spanner/.github/CODEOWNERS b/packages/sqlalchemy-spanner/.github/CODEOWNERS new file mode 100644 index 000000000000..54b9c39b00ab --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/CODEOWNERS @@ -0,0 +1,8 @@ +# Code owners file. +# This file controls who is tagged for review for any given pull request. +# +# For syntax help see: +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax + +# The @googleapis/api-spanner is the default owner for changes in this repo +* @googleapis/api-spanner From 1e5c54d4d8d64fa1dfce7cb96be1e2ba1202207e Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 13 Oct 2021 02:07:55 +0200 Subject: [PATCH 106/582] chore(deps): update python orb to v1.4.0 (#128) Co-authored-by: skuruppu --- packages/sqlalchemy-spanner/.circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.circleci/config.yml b/packages/sqlalchemy-spanner/.circleci/config.yml index eabed9f35111..4ba15aeff8a0 100644 --- a/packages/sqlalchemy-spanner/.circleci/config.yml +++ b/packages/sqlalchemy-spanner/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2.1 orbs: - python: circleci/python@1.3.3 + python: circleci/python@1.4.0 jobs: build-and-test: From 6fb3e176cd85ab699db6fd2ab2a19e95bff1a8ef Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 13 Oct 2021 11:59:38 +1100 Subject: [PATCH 107/582] chore: remove duplicate files (#132) Keep the auto-generated files instead of the manually added files. --- .../sqlalchemy-spanner/code-of-conduct.md | 63 ------------------- packages/sqlalchemy-spanner/contributing.md | 54 ---------------- 2 files changed, 117 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/code-of-conduct.md delete mode 100644 packages/sqlalchemy-spanner/contributing.md diff --git a/packages/sqlalchemy-spanner/code-of-conduct.md b/packages/sqlalchemy-spanner/code-of-conduct.md deleted file mode 100644 index f8b12cb550a3..000000000000 --- a/packages/sqlalchemy-spanner/code-of-conduct.md +++ /dev/null @@ -1,63 +0,0 @@ -# Google Open Source Community Guidelines - -At Google, we recognize and celebrate the creativity and collaboration of open -source contributors and the diversity of skills, experiences, cultures, and -opinions they bring to the projects and communities they participate in. - -Every one of Google's open source projects and communities are inclusive -environments, based on treating all individuals respectfully, regardless of -gender identity and expression, sexual orientation, disabilities, -neurodiversity, physical appearance, body size, ethnicity, nationality, race, -age, religion, or similar personal characteristic. - -We value diverse opinions, but we value respectful behavior more. - -Respectful behavior includes: - -* Being considerate, kind, constructive, and helpful. -* Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or - physically threatening behavior, speech, and imagery. -* Not engaging in unwanted physical contact. - -Some Google open source projects [may adopt][] an explicit project code of -conduct, which may have additional detailed expectations for participants. Most -of those projects will use our [modified Contributor Covenant][]. - -[may adopt]: https://opensource.google/docs/releasing/preparing/#conduct -[modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ - -## Resolve peacefully - -We do not believe that all conflict is necessarily bad; healthy debate and -disagreement often yields positive results. However, it is never okay to be -disrespectful. - -If you see someone behaving disrespectfully, you are encouraged to address the -behavior directly with those involved. Many issues can be resolved quickly and -easily, and this gives people more control over the outcome of their dispute. -If you are unable to resolve the matter for any reason, or if the behavior is -threatening or harassing, report it. We are dedicated to providing an -environment where participants feel welcome and safe. - -## Reporting problems - -Some Google open source projects may adopt a project-specific code of conduct. -In those cases, a Google employee will be identified as the Project Steward, -who will receive and handle reports of code of conduct violations. In the event -that a project hasn’t identified a Project Steward, you can report problems by -emailing opensource@google.com. - -We will investigate every complaint, but you may not receive a direct response. -We will use our discretion in determining when and how to follow up on reported -incidents, which may range from not taking action to permanent expulsion from -the project and project-sponsored spaces. We will notify the accused of the -report and provide them an opportunity to discuss it before any action is -taken. The identity of the reporter will be omitted from the details of the -report supplied to the accused. In potentially harmful situations, such as -ongoing harassment or threats to anyone's safety, we may take action without -notice. - -*This document was adapted from the [IndieWeb Code of Conduct][] and can also -be found at .* - -[IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct diff --git a/packages/sqlalchemy-spanner/contributing.md b/packages/sqlalchemy-spanner/contributing.md deleted file mode 100644 index 6294c4529e49..000000000000 --- a/packages/sqlalchemy-spanner/contributing.md +++ /dev/null @@ -1,54 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution; -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code Reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. - -## Community Guidelines - -This project follows [Google's Open Source Community -Guidelines](https://opensource.google/conduct/). - -## Running tests - -SQLAlchemy Spanner dialect includes a test suite, which can be executed both on a live service and Spanner emulator. - -**Using pytest** -To execute the test suite with standard `pytest` package you only need to checkout to the package folder and run: -``` -pytest -v -``` - -**Using nox** -The package includes a configuration file for `nox` package, which allows to execute the dialect test suite in an isolated virtual environment. To execute all the `nox` sessions checkout to the dialect folder and then run command: -``` -nox -``` -To execute only the dialect compliance test suite execute command: -``` -nox -s compliance_test -``` - -**Live service** -To run the test suite on a live service use [setup.cfg](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/setup.cfg) `db.default` attribute to set URI of the project, instance and database, where the tests should be executed. - -**Emulator** -As the dialect is built on top of the Spanner DB API, it also supports running on Spanner emulator. To make it happen you need to set an environment variable, pointing to the emulator service, for example `SPANNER_EMULATOR_HOST=localhost:9010` \ No newline at end of file From 77a0da6413adf7cddadcb3fa156e68b69a8a2576 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 13 Oct 2021 13:58:32 +1100 Subject: [PATCH 108/582] chore: setup kokoro build.sh to run all jobs (#131) Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/build.sh | 35 +++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index 5f57c204506d..6f33e29811c8 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -21,16 +21,27 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") export GOOGLE_CLOUD_PROJECT=$(cat "${KOKORO_GFILE_DIR}/project-id.json") -export RUNNING_SPANNER_BACKEND_TESTS=1 - -if [[ $KOKORO_JOB_NAME == *"docs"* ]] -then - echo "Running docs generation." - # Remove old nox - python3 -m pip uninstall --yes --quiet nox-automation - - # Install nox - python3 -m pip install --upgrade --quiet nox - # Generate docs. - python3 -m nox -s docs docfx +# Remove old nox +python3 -m pip uninstall --yes --quiet nox-automation + +# Install nox +python3 -m pip install --upgrade --quiet nox +python3 -m nox --version + +# If this is a continuous build, send the test log to the FlakyBot. +# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/flakybot. +if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then + cleanup() { + chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot + $KOKORO_GFILE_DIR/linux_amd64/flakybot + } + trap cleanup EXIT HUP +fi + +# If NOX_SESSION is set, it only runs the specified session, +# otherwise run all the sessions. +if [[ -n "${NOX_SESSION:-}" ]]; then + python3 -m nox -s ${NOX_SESSION:-} +else + python3 -m nox fi From f56abb073ccdd8468134f8d99d974373e5224e45 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 10 Nov 2021 10:03:49 +1100 Subject: [PATCH 109/582] test: enable tests to run on kokoro (#134) Co-authored-by: Ilya Gurov --- .../sqlalchemy-spanner/.circleci/config.yml | 19 ------------- .../.kokoro/presubmit/presubmit.cfg | 6 ---- .../create_test_database.py | 4 +-- .../cloud/sqlalchemy_spanner/requirements.py | 8 ++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- .../migration_test_cleanup.py | 28 +++++++++---------- packages/sqlalchemy-spanner/noxfile.py | 12 ++++++-- .../sqlalchemy-spanner/samples/conftest.py | 16 +++++++++-- packages/sqlalchemy-spanner/setup.cfg | 3 -- packages/sqlalchemy-spanner/test/_helpers.py | 20 +++++++++++++ .../sqlalchemy-spanner/test/test_suite.py | 18 ++++-------- 11 files changed, 74 insertions(+), 62 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.circleci/config.yml diff --git a/packages/sqlalchemy-spanner/.circleci/config.yml b/packages/sqlalchemy-spanner/.circleci/config.yml deleted file mode 100644 index 4ba15aeff8a0..000000000000 --- a/packages/sqlalchemy-spanner/.circleci/config.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: 2.1 - -orbs: - python: circleci/python@1.4.0 - -jobs: - build-and-test: - executor: python/default - steps: - - checkout - - run: sudo apt install python3.8 - - run: echo $GCLOUD_SERVICE_KEY > "$GOOGLE_APPLICATION_CREDENTIALS" - - run: python3 -m pip install nox - - run: python3 -m nox - -workflows: - main: - jobs: - - build-and-test diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg index b158096f0ae2..18a4c35325b8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg @@ -1,7 +1 @@ # Format: //devtools/kokoro/config/proto/build.proto - -# Disable system tests. -env_vars: { - key: "RUN_SYSTEM_TESTS" - value: "false" -} diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index a635b7ff86dc..a30bcb500040 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -82,11 +82,11 @@ def create_test_instance(): instance = CLIENT.instance(instance_id, instance_config, labels=labels) created_op = instance.create() - created_op.result(120) # block until completion + created_op.result(1800) # block until completion database = instance.database("compliance-test") created_op = database.create() - created_op.result(120) + created_op.result(1800) config = configparser.ConfigParser() url = "spanner:///projects/{project}/instances/{instance_id}/databases/compliance-test".format( diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 1b9298478151..97fbd54680bc 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -17,6 +17,14 @@ class Requirements(SuiteRequirements): + @property + def sane_rowcount(self): + return exclusions.closed() + + @property + def sane_multi_rowcount(self): + return exclusions.closed() + @property def foreign_key_constraint_name_reflection(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index a9abec598dab..d65fc0a96855 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -394,7 +394,7 @@ class SpannerDialect(DefaultDialect): execute_sequence_format = list supports_alter = True - supports_sane_rowcount = True + supports_sane_rowcount = False supports_sane_multi_rowcount = False supports_default_values = False supports_sequences = True diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py index 01a9a5281966..6226635939f6 100644 --- a/packages/sqlalchemy-spanner/migration_test_cleanup.py +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -14,24 +14,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -import configparser -import os import re +import sys from google.cloud import spanner -config = configparser.ConfigParser() -if os.path.exists("test.cfg"): - config.read("test.cfg") -else: - config.read("setup.cfg") -db_url = config.get("db", "default") -project = re.findall(r"projects(.*?)instances", db_url) -instance_id = re.findall(r"instances(.*?)databases", db_url) +def main(argv): + db_url = argv[0] -client = spanner.Client(project="".join(project).replace("/", "")) -instance = client.instance(instance_id="".join(instance_id).replace("/", "")) -database = instance.database("compliance-test") + project = re.findall(r"projects(.*?)instances", db_url) + instance_id = re.findall(r"instances(.*?)databases", db_url) -database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) + client = spanner.Client(project="".join(project).replace("/", "")) + instance = client.instance(instance_id="".join(instance_id).replace("/", "")) + database = instance.database("compliance-test") + + database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 1e5eb9ede70d..04b2875d3494 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -147,12 +147,20 @@ def migration_test(session): session.install("-e", ".") session.install("alembic") + project = os.getenv( + "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + ) + db_url = ( + f"spanner:///projects/{project}/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + config = configparser.ConfigParser() if os.path.exists("test.cfg"): config.read("test.cfg") else: config.read("setup.cfg") - db_url = config.get("db", "default") + db_url = config.get("db", "default", fallback=db_url) session.run("alembic", "init", "test_migration") @@ -181,7 +189,7 @@ def migration_test(session): # clearing the migration data os.remove("alembic.ini") shutil.rmtree("test_migration") - session.run("python", "migration_test_cleanup.py") + session.run("python", "migration_test_cleanup.py", db_url) if os.path.exists("test.cfg"): os.remove("test.cfg") diff --git a/packages/sqlalchemy-spanner/samples/conftest.py b/packages/sqlalchemy-spanner/samples/conftest.py index f3f0fcaae66b..5a4f622e4e2e 100644 --- a/packages/sqlalchemy-spanner/samples/conftest.py +++ b/packages/sqlalchemy-spanner/samples/conftest.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import configparser import datetime +import os import uuid import pytest @@ -30,11 +32,21 @@ @pytest.fixture def db_url(): - return ( - "spanner:///projects/appdev-soda-spanner-staging/instances/" + project = os.getenv( + "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + ) + db_url = ( + f"spanner:///projects/{project}/instances/" "sqlalchemy-dialect-test/databases/compliance-test" ) + config = configparser.ConfigParser() + if os.path.exists("test.cfg"): + config.read("test.cfg") + else: + config.read("setup.cfg") + return config.get("db", "default", fallback=db_url) + @pytest.fixture def table_id(): diff --git a/packages/sqlalchemy-spanner/setup.cfg b/packages/sqlalchemy-spanner/setup.cfg index 7050a471883c..7b1c6800ff0a 100644 --- a/packages/sqlalchemy-spanner/setup.cfg +++ b/packages/sqlalchemy-spanner/setup.cfg @@ -24,6 +24,3 @@ python_files=test/*test_*.py [sqla_testing] requirement_cls=google.cloud.sqlalchemy_spanner.requirements:Requirements profile_file=test/profiles.txt - -[db] -default=spanner:///projects/appdev-soda-spanner-staging/instances/sqlalchemy-dialect-test/databases/compliance-test \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/test/_helpers.py b/packages/sqlalchemy-spanner/test/_helpers.py index c9d9ba7497f1..dd18a149d4b5 100644 --- a/packages/sqlalchemy-spanner/test/_helpers.py +++ b/packages/sqlalchemy-spanner/test/_helpers.py @@ -5,7 +5,9 @@ # https://developers.google.com/open-source/licenses/bsd +import configparser import mock +import os from sqlalchemy.testing import fixtures try: @@ -29,6 +31,24 @@ _TEST_OT_PROVIDER_INITIALIZED = False +PROJECT = os.getenv( + "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), +) +DB_URL = ( + f"spanner:///projects/{PROJECT}/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" +) + + +def get_db_url(): + config = configparser.ConfigParser() + if os.path.exists("test.cfg"): + config.read("test.cfg") + else: + config.read("setup.cfg") + return config.get("db", "default", fallback=DB_URL) + + def get_test_ot_exporter(): global _TEST_OT_EXPORTER diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 500114c318fb..ea40bf093f9f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -111,6 +111,7 @@ UnicodeTextTest as _UnicodeTextTest, _UnicodeFixture as _UnicodeFixtureTest, ) +from test._helpers import get_db_url config.test_schema = "" @@ -678,7 +679,7 @@ def define_temp_tables(cls, metadata): Column("foo", sqlalchemy.INT), sqlalchemy.Index("user_tmp_uq", "name", unique=True), sqlalchemy.Index("user_tmp_ix", "foo"), - **kw + **kw, ) if ( testing.requires.view_reflection.enabled @@ -1508,10 +1509,7 @@ class InterleavedTablesTest(fixtures.TestBase): """ def setUp(self): - self._engine = create_engine( - "spanner:///projects/appdev-soda-spanner-staging/instances/" - "sqlalchemy-dialect-test/databases/compliance-test" - ) + self._engine = create_engine(get_db_url()) self._metadata = MetaData(bind=self._engine) def test_interleave(self): @@ -1560,10 +1558,7 @@ class UserAgentTest(fixtures.TestBase): """Check that SQLAlchemy dialect uses correct user agent.""" def setUp(self): - self._engine = create_engine( - "spanner:///projects/appdev-soda-spanner-staging/instances/" - "sqlalchemy-dialect-test/databases/compliance-test" - ) + self._engine = create_engine(get_db_url()) self._metadata = MetaData(bind=self._engine) def test_user_agent(self): @@ -1583,10 +1578,7 @@ class ExecutionOptionsTest(fixtures.TestBase): """ def setUp(self): - self._engine = create_engine( - "spanner:///projects/appdev-soda-spanner-staging/instances/" - "sqlalchemy-dialect-test/databases/compliance-test" - ) + self._engine = create_engine(get_db_url()) self._metadata = MetaData(bind=self._engine) self._table = Table( From 8c45409a5f8c63a3495a4eef0bca9062522ba13c Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 10 Nov 2021 11:58:14 +1100 Subject: [PATCH 110/582] docs: reformatted README titles (#141) --- packages/sqlalchemy-spanner/README.md | 53 +++++++++++++-------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 155d3094f32c..b8c557b6d41b 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -9,8 +9,7 @@ This project has **Preview** release status. Known limitations are listed [here] - [Cloud Spanner product documentation](https://cloud.google.com/spanner/docs) - [SQLAlchemy product documentation](https://www.sqlalchemy.org/) -Quick Start ------------ +## Quick Start In order to use this package, you first need to go through the following steps: @@ -19,8 +18,7 @@ In order to use this package, you first need to go through the following steps: 3. [Enable the Google Cloud Spanner API.](https://cloud.google.com/spanner) 4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html) -Installation ------------ +## Installation To install an in-development version of the package, clone its Git-repository: ``` @@ -32,9 +30,9 @@ python setup.py install ``` During setup the dialect will be registered with entry points. -A Minimal App ------------ -**Create a table** +## A Minimal App + +### Create a table ```python from sqlalchemy import ( Column, @@ -59,7 +57,8 @@ user = Table( metadata.create_all(engine) ``` -**Insert a row** + +### Insert a row ```python from sqlalchemy import ( MetaData, @@ -76,7 +75,7 @@ with engine.begin() as connection: connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) ``` -**Read** +### Read ```python from sqlalchemy import MetaData, Table, create_engine, select @@ -90,16 +89,16 @@ with engine.begin() as connection: print(row) ``` -Migration ------------ +## Migration + SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. **Warning!** A migration script can produce a lot of DDL statements. If each of the statements are executed separately, performance issues can occur. To avoid these, it's highly recommended to use the [Alembic batch context](https://alembic.sqlalchemy.org/en/latest/batch.html) feature to pack DDL statements into groups of statements. -Features and limitations ------------ -**Interleaved tables** +## Features and limitations + +### Interleaved tables Cloud Spanner dialect includes two dialect-specific arguments for `Table` constructor, which help to define interleave relations: `spanner_interleave_in` - a parent table name `spanner_inverleave_on_delete_cascade` - a flag specifying if `ON DELETE CASCADE` statement must be used for the interleave relation @@ -126,7 +125,7 @@ client = Table( client.create(engine) ``` -**Unique constraints** +### Unique constraints Cloud Spanner doesn't support direct UNIQUE constraints creation. In order to achieve column values uniqueness UNIQUE indexes should be used. Instead of direct UNIQUE constraint creation: @@ -147,7 +146,7 @@ Table( Index("uix_1", "col1", unique=True), ) ``` -**Autocommit mode** +### Autocommit mode Spanner dialect supports both `SERIALIZABLE` and `AUTOCOMMIT` isolation levels. `SERIALIZABLE` is the default one, where transactions need to be committed manually. `AUTOCOMMIT` mode corresponds to automatically committing of a query right in its execution time. Isolation level change example: @@ -158,7 +157,7 @@ eng = create_engine("spanner:///projects/project-id/instances/instance-id/databa autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") ``` -**ReadOnly transactions** +### ReadOnly transactions By default, transactions produced by a Spanner connection are in ReadWrite mode. However, some applications require an ability to grant ReadOnly access to users/methods; for these cases Spanner dialect supports the `read_only` execution option, which switches a connection into ReadOnly mode: ```python with engine.connect().execution_options(read_only=True) as connection: @@ -168,13 +167,13 @@ Note that execution options are applied lazily - on the `execute()` method call, ReadOnly/ReadWrite mode of a connection can't be changed while a transaction is in progress - first you must commit or rollback it. -**DDL and transactions** +### DDL and transactions DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. -**Dropping a table** +### Dropping a table Cloud Spanner, by default, doesn't drop tables, which have secondary indexes and/or foreign key constraints. In Spanner dialect for SQLAlchemy, however, this restriction is omitted - if a table you are trying to delete has indexes/foreign keys, they will be dropped automatically right before dropping the table. -**Data types** +### Data types Data types table mapping SQLAlchemy types to Cloud Spanner types: | SQLAlchemy | Spanner | @@ -193,14 +192,13 @@ Data types table mapping SQLAlchemy types to Cloud Spanner types: | NUMERIC | NUMERIC | -**Other limitations** +### Other limitations - WITH RECURSIVE statement is not supported. - Named schemas are not supported. - Temporary tables are not supported, real tables are used instead. - Numeric type dimensions (scale and precision) are constant. See the [docs](https://cloud.google.com/spanner/docs/data-types#numeric_types). -Best practices ------------ +## Best practices When a SQLAlchemy function is called, a new connection to a database is established and a Spanner session object is fetched. In case of connectionless execution these fetches are done for every `execute()` call, which can cause a significant latency. To avoid initiating a Spanner session on every `execute()` call it's recommended to write code in connection-bounded fashion. Once a `Connection()` object is explicitly initiated, it fetches a Spanner session object and uses it for all the following calls made on this `Connection()` object. Non-optimal connectionless use: @@ -216,8 +214,8 @@ with engine.begin() as connection: ``` Connectionless way of use is also deprecated since SQLAlchemy 2.0 and soon will be removed (see in [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/connections.html#connectionless-execution-implicit-execution)). -Running tests ------------- +## Running tests + Spanner dialect includes a compliance, migration and unit test suite. To run the tests the `nox` package commands can be used: ``` # Run the whole suite @@ -226,11 +224,10 @@ $ nox # Run a particular test session $ nox -s migration_test ``` -**Running tests on Spanner emulator** +### Running tests on Spanner emulator The dialect test suite can be runned on [Spanner emulator](https://cloud.google.com/spanner/docs/emulator). Several tests, relating to `NULL` values of data types, are skipped when executed on emulator. -Contributing ------------- +## Contributing Contributions to this library are welcome and encouraged. Please report issues, file feature requests, and send pull requests. See [CONTRIBUTING](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get started. From 8a9ac562a70069ce8d61dc080b59215c4addfe13 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 10 Nov 2021 14:04:15 +1100 Subject: [PATCH 111/582] test: require kokoro test run as a presubmit (#143) --- packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index 7ce8f88491a5..f09df682aecc 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -9,4 +9,4 @@ branchProtectionRules: requiredStatusCheckContexts: - 'tests' - 'cla/google' - - 'ci/circleci: build-and-test' + - 'kokoro' From 76c7b0a53bb5a5ec20f56847e2a389b54ae73ee9 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 17 Nov 2021 16:36:54 +1100 Subject: [PATCH 112/582] test: require Kokoro as a presubmit (#147) --- packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index f09df682aecc..444cb62a056b 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -9,4 +9,4 @@ branchProtectionRules: requiredStatusCheckContexts: - 'tests' - 'cla/google' - - 'kokoro' + - 'Kokoro' From 6c8ac6a832ddf374015f04a4efc0927e7474bb1c Mon Sep 17 00:00:00 2001 From: skuruppu Date: Fri, 19 Nov 2021 12:06:04 +1100 Subject: [PATCH 113/582] test: run snippets tests on Kokoro (#152) --- packages/sqlalchemy-spanner/noxfile.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 04b2875d3494..54b1ed0350cf 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -197,10 +197,9 @@ def migration_test(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def snippets(session): """Run the documentation example snippets.""" - # Sanity check: Only run snippets system tests if the environment variable - # is set. - if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): - session.skip("Credentials must be set via environment variable.") + # Sanity check: Snippets tests can't be run against the emulator. + if os.environ.get("SPANNER_EMULATOR_HOST"): + session.skip("Snippets can't be run against the emulator.") session.install("pytest") session.install("sqlalchemy") From 02fc1219dfee8e1a04b9b54871b05effbd22d749 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 19 Nov 2021 04:46:11 +0300 Subject: [PATCH 114/582] docs: add query hints example (#153) --- packages/sqlalchemy-spanner/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index b8c557b6d41b..0f741e55e3fd 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -157,6 +157,29 @@ eng = create_engine("spanner:///projects/project-id/instances/instance-id/databa autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") ``` +### Query hints +Spanner dialect supports [query hints](https://cloud.google.com/spanner/docs/query-syntax#table_hints), which give the ability to set additional query execution parameters. Usage example: +```python +session = Session(engine) + +Base = declarative_base() + +class User(Base): + """Data model.""" + + __tablename__ = "users" + id = Column(Integer, primary_key=True) + name = Column(String(50)) + + +query = session.query(User) +query = query.with_hint( + selectable=User, text="@{FORCE_INDEX=index_name}" +) +query = query.filter(User.name.in_(["val1", "val2"])) +query.statement.compile(session.bind) +``` + ### ReadOnly transactions By default, transactions produced by a Spanner connection are in ReadWrite mode. However, some applications require an ability to grant ReadOnly access to users/methods; for these cases Spanner dialect supports the `read_only` execution option, which switches a connection into ReadOnly mode: ```python From a5edded802954d502dec50f28b6af910ce636537 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Fri, 19 Nov 2021 14:43:39 +1100 Subject: [PATCH 115/582] Revert "test: run snippets tests on Kokoro (#152)" (#154) This reverts commit c4629f3546435ebc636c2ebb5c283f8c2b6b34c2. --- packages/sqlalchemy-spanner/noxfile.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 54b1ed0350cf..04b2875d3494 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -197,9 +197,10 @@ def migration_test(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def snippets(session): """Run the documentation example snippets.""" - # Sanity check: Snippets tests can't be run against the emulator. - if os.environ.get("SPANNER_EMULATOR_HOST"): - session.skip("Snippets can't be run against the emulator.") + # Sanity check: Only run snippets system tests if the environment variable + # is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): + session.skip("Credentials must be set via environment variable.") session.install("pytest") session.install("sqlalchemy") From 158c875da0d95050ba26814f14ff4165171e4938 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Fri, 19 Nov 2021 15:29:11 +1100 Subject: [PATCH 116/582] test: separate GH actions (#151) --- .../.github/sync-repo-settings.yaml | 5 +- .../.github/workflows/test_suite.yml | 62 ++++++++++++++++++- .../sqlalchemy-spanner/create_test_config.py | 41 ++++++++++++ .../create_test_database.py | 29 +++++---- packages/sqlalchemy-spanner/noxfile.py | 3 + 5 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 packages/sqlalchemy-spanner/create_test_config.py diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index 444cb62a056b..2cfe97555bc0 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -7,6 +7,9 @@ branchProtectionRules: requiresCodeOwnerReviews: true requiresStrictStatusChecks: true requiredStatusCheckContexts: - - 'tests' + - 'lint' + - 'unit' + - 'compliance_tests' + - 'migration_tests' - 'cla/google' - 'Kokoro' diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 7a6d4653d66c..292c3d69a573 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -5,7 +5,40 @@ on: pull_request: name: SQLAlchemy Spanner dialect jobs: - tests: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Lint + run: nox -s lint_setup_py lint blacken + + unit: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Unit Tests + run: nox -s unit + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + + compliance_tests: runs-on: ubuntu-latest services: @@ -23,9 +56,32 @@ jobs: python-version: 3.8 - name: Install nox run: python -m pip install nox - - name: Run SQLAlchemy tests - run: nox + - name: Run Compliance Tests + run: nox -s compliance_test env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + migration_tests: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Migration Tests + run: nox -s migration_test + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/create_test_config.py b/packages/sqlalchemy-spanner/create_test_config.py new file mode 100644 index 000000000000..34d5b863d931 --- /dev/null +++ b/packages/sqlalchemy-spanner/create_test_config.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import configparser +import sys + + +def set_test_config(project, instance): + config = configparser.ConfigParser() + url = ( + f"spanner:///projects/{project}/instances/{instance}/" + "databases/compliance-test" + ) + config.add_section("db") + config["db"]["default"] = url + + with open("test.cfg", "w") as configfile: + config.write(configfile) + + +def main(argv): + project = argv[0] + instance = argv[1] + set_test_config(project, instance) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index a30bcb500040..2899c0d2d09e 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -18,7 +18,8 @@ import os import time -from google.api_core.exceptions import ResourceExhausted +from create_test_config import set_test_config +from google.api_core.exceptions import AlreadyExists, ResourceExhausted from google.cloud.spanner_v1 import Client from google.cloud.spanner_v1.instance import Instance @@ -81,22 +82,20 @@ def create_test_instance(): instance = CLIENT.instance(instance_id, instance_config, labels=labels) - created_op = instance.create() - created_op.result(1800) # block until completion + try: + created_op = instance.create() + created_op.result(1800) # block until completion + except AlreadyExists: + pass # instance was already created - database = instance.database("compliance-test") - created_op = database.create() - created_op.result(1800) + try: + database = instance.database("compliance-test") + created_op = database.create() + created_op.result(1800) + except AlreadyExists: + pass # instance was already created - config = configparser.ConfigParser() - url = "spanner:///projects/{project}/instances/{instance_id}/databases/compliance-test".format( - project=PROJECT, instance_id=instance_id - ) - config.add_section("db") - config["db"]["default"] = url - - with open("test.cfg", "w") as configfile: - config.write(configfile) + set_test_config(PROJECT, instance_id) delete_stale_test_instances() diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 04b2875d3494..06eff539c7d8 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -133,6 +133,7 @@ def unit(session): session.install("opentelemetry-api==1.1.0") session.install("opentelemetry-sdk==1.1.0") session.install("opentelemetry-instrumentation==0.20b0") + session.run("python", "create_test_config.py", "my-project", "my-instance") session.run("py.test", "--quiet", os.path.join("test/unit"), *session.posargs) @@ -147,6 +148,8 @@ def migration_test(session): session.install("-e", ".") session.install("alembic") + session.run("python", "create_test_database.py") + project = os.getenv( "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), ) From e569e72840c31adc395a42971a1037a65db5aa58 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 19 Nov 2021 08:06:12 +0300 Subject: [PATCH 117/582] feat: support stale reads (#146) --- packages/sqlalchemy-spanner/README.md | 39 +++++++++++++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 13 +++++++ .../sqlalchemy-spanner/test/test_suite.py | 20 ++++++++-- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 0f741e55e3fd..ab3651b4540f 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -190,6 +190,45 @@ Note that execution options are applied lazily - on the `execute()` method call, ReadOnly/ReadWrite mode of a connection can't be changed while a transaction is in progress - first you must commit or rollback it. +### Stale reads +To use the Spanner [Stale Reads](https://cloud.google.com/spanner/docs/reads#perform-stale-read) with SQLAlchemy you can tweak the connection execution options with a wanted staleness value. For example: +```python +# maximum staleness +with engine.connect().execution_options( + read_only=True, + staleness={"max_staleness": datetime.timedelta(seconds=5)} +) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() +``` + +```python +# exact staleness +with engine.connect().execution_options( + read_only=True, + staleness={"exact_staleness": datetime.timedelta(seconds=5)} +) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() +``` + +```python +# min read timestamp +with engine.connect().execution_options( + read_only=True, + staleness={"min_read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} +) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() +``` + +```python +# read timestamp +with engine.connect().execution_options( + read_only=True, + staleness={"read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} +) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() +``` +Note that the set option will be dropped when the connection is returned back to the pool. + ### DDL and transactions DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index d65fc0a96855..118672e48483 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -25,7 +25,9 @@ from sqlalchemy import ForeignKeyConstraint, types, util from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect, DefaultExecutionContext +from sqlalchemy.event import listens_for from sqlalchemy.ext.compiler import compiles +from sqlalchemy.pool import Pool from sqlalchemy.sql.compiler import ( selectable, DDLCompiler, @@ -38,6 +40,13 @@ from google.cloud import spanner_dbapi from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call + +@listens_for(Pool, "reset") +def reset_connection(dbapi_conn, connection_record): + """An event of returning a connection back to a pool.""" + dbapi_conn.connection.staleness = None + + # Spanner-to-SQLAlchemy types map _type_map = { "BOOL": types.Boolean, @@ -128,6 +137,10 @@ def pre_exec(self): if read_only is not None: self._dbapi_connection.connection.read_only = read_only + staleness = self.execution_options.get("staleness", None) + if staleness is not None: + self._dbapi_connection.connection.staleness = staleness + class SpannerIdentifierPreparer(IdentifierPreparer): """Identifiers compiler. diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index ea40bf093f9f..74c5d447b666 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from datetime import timezone +import datetime import decimal import operator import os @@ -975,7 +975,9 @@ def test_row_w_scalar_select(self): eq_( row["somelabel"], - DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=timezone.utc), + DatetimeWithNanoseconds( + 2006, 5, 12, 12, 0, 0, tzinfo=datetime.timezone.utc + ), ) @@ -1578,7 +1580,7 @@ class ExecutionOptionsTest(fixtures.TestBase): """ def setUp(self): - self._engine = create_engine(get_db_url()) + self._engine = create_engine(get_db_url(), pool_size=1) self._metadata = MetaData(bind=self._engine) self._table = Table( @@ -1594,3 +1596,15 @@ def test_read_only(self): with self._engine.connect().execution_options(read_only=True) as connection: connection.execute(select(["*"], from_obj=self._table)).fetchall() assert connection.connection.read_only is True + + def test_staleness(self): + with self._engine.connect().execution_options( + read_only=True, staleness={"max_staleness": datetime.timedelta(seconds=5)} + ) as connection: + connection.execute(select(["*"], from_obj=self._table)).fetchall() + assert connection.connection.staleness == { + "max_staleness": datetime.timedelta(seconds=5) + } + + with self._engine.connect() as connection: + assert connection.connection.staleness is None From cb173981160cf1c9c4c871ac3b3dee52dc6e681e Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 19 Nov 2021 08:50:33 +0300 Subject: [PATCH 118/582] feat: support computed columns (#139) Closes #137 --- .../cloud/sqlalchemy_spanner/requirements.py | 7 ++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 29 ++++-- .../sqlalchemy-spanner/test/test_suite.py | 98 +++++++++++++++++++ 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 97fbd54680bc..2f30157bc60b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -18,6 +18,13 @@ class Requirements(SuiteRequirements): @property + def computed_columns(self): + return exclusions.open() + + @property + def computed_columns_stored(self): + return exclusions.open() + def sane_rowcount(self): return exclusions.closed() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 118672e48483..c38a9b8f495b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -267,6 +267,13 @@ def limit_clause(self, select, **kw): class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" + def visit_computed_column(self, generated, **kw): + """Computed column operator.""" + text = "AS (%s) STORED" % self.sql_compiler.process( + generated.sqltext, include_table=False, literal_binds=True + ) + return text + def visit_drop_table(self, drop_table): """ Cloud Spanner doesn't drop tables which have indexes @@ -492,7 +499,7 @@ def get_columns(self, connection, table_name, schema=None, **kw): list: The table every column dict-like description. """ sql = """ -SELECT column_name, spanner_type, is_nullable +SELECT column_name, spanner_type, is_nullable, generation_expression FROM information_schema.columns WHERE table_catalog = '' @@ -512,14 +519,20 @@ def get_columns(self, connection, table_name, schema=None, **kw): columns = snap.execute_sql(sql) for col in columns: - cols_desc.append( - { - "name": col[0], - "type": self._designate_type(col[1]), - "nullable": col[2] == "YES", - "default": None, + col_desc = { + "name": col[0], + "type": self._designate_type(col[1]), + "nullable": col[2] == "YES", + "default": None, + } + + if col[3] is not None: + col_desc["computed"] = { + "persisted": True, + "sqltext": col[3], } - ) + cols_desc.append(col_desc) + return cols_desc def _designate_type(self, str_repr): diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 74c5d447b666..0bc4030caf51 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -29,11 +29,13 @@ from sqlalchemy import ForeignKey from sqlalchemy import MetaData from sqlalchemy.schema import DDL +from sqlalchemy.schema import Computed from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures +from sqlalchemy.testing import is_true from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -54,6 +56,9 @@ from sqlalchemy.types import Numeric from sqlalchemy.types import Text from sqlalchemy.testing import requires +from sqlalchemy.testing.fixtures import ( + ComputedReflectionFixtureTest as _ComputedReflectionFixtureTest, +) from google.api_core.datetime_helpers import DatetimeWithNanoseconds @@ -89,6 +94,7 @@ QuotedNameArgumentTest as _QuotedNameArgumentTest, ComponentReflectionTest as _ComponentReflectionTest, CompositeKeyReflectionTest as _CompositeKeyReflectionTest, + ComputedReflectionTest as _ComputedReflectionTest, ) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 @@ -1608,3 +1614,95 @@ def test_staleness(self): with self._engine.connect() as connection: assert connection.connection.staleness is None + + +class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): + @classmethod + def define_tables(cls, metadata): + """SPANNER OVERRIDE: + + Avoid using default values for computed columns. + """ + Table( + "computed_default_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_col", Integer, Computed("normal + 42")), + Column("with_default", Integer), + ) + + t = Table( + "computed_column_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_no_flag", Integer, Computed("normal + 42")), + ) + + if testing.requires.schemas.enabled: + t2 = Table( + "computed_column_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_no_flag", Integer, Computed("normal / 42")), + schema=config.test_schema, + ) + + if testing.requires.computed_columns_virtual.enabled: + t.append_column( + Column( + "computed_virtual", + Integer, + Computed("normal + 2", persisted=False), + ) + ) + if testing.requires.schemas.enabled: + t2.append_column( + Column( + "computed_virtual", + Integer, + Computed("normal / 2", persisted=False), + ) + ) + if testing.requires.computed_columns_stored.enabled: + t.append_column( + Column( + "computed_stored", Integer, Computed("normal - 42", persisted=True), + ) + ) + if testing.requires.schemas.enabled: + t2.append_column( + Column( + "computed_stored", + Integer, + Computed("normal * 42", persisted=True), + ) + ) + + +class ComputedReflectionTest(_ComputedReflectionTest, ComputedReflectionFixtureTest): + @pytest.mark.skip("Default values are not supported.") + def test_computed_col_default_not_set(self): + pass + + def test_get_column_returns_computed(self): + """ + SPANNER OVERRIDE: + + In Spanner all the generated columns are STORED, + meaning there are no persisted and not persisted + (in the terms of the SQLAlchemy) columns. The + method override omits the persistence reflection checks. + """ + insp = inspect(config.db) + + cols = insp.get_columns("computed_default_table") + data = {c["name"]: c for c in cols} + for key in ("id", "normal", "with_default"): + is_true("computed" not in data[key]) + compData = data["computed_col"] + is_true("computed" in compData) + is_true("sqltext" in compData["computed"]) + eq_(self.normalize(compData["computed"]["sqltext"]), "normal+42") From 09ed79a4502f9a940a0c7f8645d3d11e08ad9f95 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 24 Nov 2021 14:32:34 +1100 Subject: [PATCH 119/582] test: run compliance tests separately (#150) Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> Co-authored-by: Ilya Gurov --- .../presubmit/{system-3.8.cfg => compliance.cfg} | 2 +- .../.kokoro/presubmit/presubmit.cfg | 6 ++++++ packages/sqlalchemy-spanner/noxfile.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) rename packages/sqlalchemy-spanner/.kokoro/presubmit/{system-3.8.cfg => compliance.cfg} (80%) diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg similarity index 80% rename from packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg rename to packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg index 5213a568eea5..3383be455b5e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/system-3.8.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg @@ -3,5 +3,5 @@ # Only run this nox session. env_vars: { key: "NOX_SESSION" - value: "system-3.8" + value: "compliance_test" } diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg index 18a4c35325b8..3aa9014481f6 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg @@ -1 +1,7 @@ # Format: //devtools/kokoro/config/proto/build.proto + +# Disable system tests. +env_vars: { + key: "RUN_COMPLIANCE_TESTS" + value: "false" +} diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 06eff539c7d8..5ec81b97481d 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -116,6 +116,18 @@ def lint_setup_py(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def compliance_test(session): """Run SQLAlchemy dialect compliance test suite.""" + + # Check the value of `RUN_COMPLIANCE_TESTS` env var. It defaults to true. + if os.environ.get("RUN_COMPLIANCE_TESTS", "true") == "false": + session.skip("RUN_COMPLIANCE_TESTS is set to false, skipping") + # Sanity check: Only run tests if the environment variable is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( + "SPANNER_EMULATOR_HOST", "" + ): + session.skip( + "Credentials or emulator host must be set via environment variable" + ) + session.install("pytest") session.install("mock") session.install("-e", ".") From 505f3dc5aacb89fca2c62edbf2ccf319ab4b6bca Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Thu, 25 Nov 2021 17:25:39 +1300 Subject: [PATCH 120/582] chore: update benchmark to better compare performance (#157) * chore: update benchmark to better compare performance * style: fix lint Co-authored-by: larkee --- .../create_test_database.py | 1 + packages/sqlalchemy-spanner/test/benchmark.py | 101 +++++++++++++----- 2 files changed, 77 insertions(+), 25 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 2899c0d2d09e..8abbed65bb54 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -82,6 +82,7 @@ def create_test_instance(): instance = CLIENT.instance(instance_id, instance_config, labels=labels) + try: created_op = instance.create() created_op.result(1800) # block until completion diff --git a/packages/sqlalchemy-spanner/test/benchmark.py b/packages/sqlalchemy-spanner/test/benchmark.py index b600e790f0a5..0ff50ae5da1a 100644 --- a/packages/sqlalchemy-spanner/test/benchmark.py +++ b/packages/sqlalchemy-spanner/test/benchmark.py @@ -16,6 +16,7 @@ A test suite to check Spanner dialect for SQLAlchemy performance in comparison with the original Spanner client. """ +import base64 import datetime import random from scipy.stats import sem @@ -23,6 +24,8 @@ import time from google.api_core.exceptions import Aborted +from google.api_core.exceptions import NotFound +from google.cloud import spanner from google.cloud import spanner_dbapi from google.cloud.spanner_v1 import Client, KeySet from sqlalchemy import ( @@ -64,26 +67,42 @@ class BenchmarkTestBase: Organizes testing data preparation and cleanup. """ + _many_rows_ids = [] + _many_rows2_ids = [] + def __init__(self): + self._cleanup() self._create_table() - self._one_row = ( - 1, - "Pete", - "Allison", - datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d"), - b"123", - ) + self._one_row = { + "id": 1, + "first_name": "Pete", + "last_name": "Allison", + "birth_date": datetime.date(1998, 10, 6), + "picture": b"123", + } + self.keys = set([1]) + if not self._many_rows_ids: + for i in range(99): + self._many_rows_ids.append(self._generate_id()) + self._many_rows2_ids.append(self._generate_id()) def _cleanup(self): """Drop the test table.""" conn = spanner_dbapi.connect(INSTANCE, DATABASE) - conn.database.update_ddl(["DROP TABLE Singers"]) + try: + conn.database.update_ddl(["DROP TABLE Singers"]) + except NotFound: + pass conn.close() def _create_table(self): """Create a table for performace testing.""" conn = spanner_dbapi.connect(INSTANCE, DATABASE) + try: + conn.database.update_ddl(["DROP TABLE Singers"]) + except NotFound: + pass conn.database.update_ddl( [ """ @@ -96,10 +115,17 @@ def _create_table(self): ) PRIMARY KEY (id) """ ] - ).result(120) + ).result() conn.close() + def _generate_id(self): + num = 1 + while num in self.keys: + num = round(random.random() * 1000000) + self.keys.add(num) + return num + def run(self): """Execute every test case.""" measures = {} @@ -117,7 +143,7 @@ def run(self): class SpannerBenchmarkTest(BenchmarkTestBase): - """The original Spanner performace testing class.""" + """The original Spanner performance testing class.""" def __init__(self): super().__init__() @@ -127,12 +153,20 @@ def __init__(self): self._many_rows = [] self._many_rows2 = [] - birth_date = datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d") - for i in range(99): - num = round(random.random() * 1000000) - self._many_rows.append((num, "Pete", "Allison", birth_date, b"123")) - num2 = round(random.random() * 1000000) - self._many_rows2.append((num2, "Pete", "Allison", birth_date, b"123")) + birth_date = datetime.date(1998, 10, 6) + picture = base64.b64encode(u"123".encode()) + for num in self._many_rows_ids: + self._many_rows.append( + { + "id": num, + "first_name": "Pete", + "last_name": "Allison", + "birth_date": birth_date, + "picture": picture, + } + ) + for num in self._many_rows2_ids: + self._many_rows2.append((num, "Pete", "Allison", birth_date, picture)) # initiate a session with self._database.snapshot(): @@ -192,9 +226,8 @@ def __init__(self): self._many_rows = [] self._many_rows2 = [] - birth_date = datetime.datetime(1998, 10, 6).strftime("%Y-%m-%d") - for i in range(99): - num = round(random.random() * 1000000) + birth_date = datetime.date(1998, 10, 6) + for num in self._many_rows_ids: self._many_rows.append( { "id": num, @@ -204,10 +237,10 @@ def __init__(self): "picture": b"123", } ) - num2 = round(random.random() * 1000000) + for num in self._many_rows2_ids: self._many_rows2.append( { - "id": num2, + "id": num, "first_name": "Pete", "last_name": "Allison", "birth_date": birth_date, @@ -255,8 +288,16 @@ def insert_one_row(transaction, one_row): Inserts a single row into a database and then fetches it back. """ transaction.execute_update( - "INSERT Singers (id, first_name, last_name, birth_date, picture) " - " VALUES {}".format(str(one_row)) + "INSERT INTO `Singers` (id, first_name, last_name, birth_date, picture)" + " VALUES (@id, @first_name, @last_name, @birth_date, @picture)", + params=one_row, + param_types={ + "id": spanner.param_types.INT64, + "first_name": spanner.param_types.STRING, + "last_name": spanner.param_types.STRING, + "birth_date": spanner.param_types.DATE, + "picture": spanner.param_types.BYTES, + }, ) last_name = transaction.execute_sql( "SELECT last_name FROM Singers WHERE id=1" @@ -273,8 +314,18 @@ def insert_many_rows(transaction, many_rows): statements = [] for row in many_rows: statements.append( - "INSERT Singers (id, first_name, last_name, birth_date, picture) " - " VALUES {}".format(str(row)) + ( + "INSERT INTO `Singers` (id, first_name, last_name, birth_date, picture)" + " VALUES (@id, @first_name, @last_name, @birth_date, @picture)", + row, + { + "id": spanner.param_types.INT64, + "first_name": spanner.param_types.STRING, + "last_name": spanner.param_types.STRING, + "birth_date": spanner.param_types.DATE, + "picture": spanner.param_types.BYTES, + }, + ) ) _, count = transaction.batch_update(statements) if sum(count) != 99: From e4dbc9274138fbf93ee67b35e0bf5475b9733aac Mon Sep 17 00:00:00 2001 From: skuruppu Date: Fri, 26 Nov 2021 12:59:51 +1100 Subject: [PATCH 121/582] test: require Kokoro compliance test run (#156) Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index 2cfe97555bc0..c8e9158a7cd1 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -13,3 +13,4 @@ branchProtectionRules: - 'migration_tests' - 'cla/google' - 'Kokoro' + - 'Kokoro Compliance Tests' From 4edc235d4f3c18e4e8ba1f2ffaebe830cdb4c364 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 2 Dec 2021 02:51:23 +0300 Subject: [PATCH 122/582] fix: raise Unimplemented error when creating temporary tables (#159) Co-authored-by: skuruppu Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- packages/sqlalchemy-spanner/README.md | 2 +- .../google/cloud/sqlalchemy_spanner/provision.py | 2 +- .../google/cloud/sqlalchemy_spanner/requirements.py | 5 +++++ .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 3 +++ packages/sqlalchemy-spanner/test/test_suite.py | 3 --- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index ab3651b4540f..46eae9142e6d 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -257,7 +257,7 @@ Data types table mapping SQLAlchemy types to Cloud Spanner types: ### Other limitations - WITH RECURSIVE statement is not supported. - Named schemas are not supported. -- Temporary tables are not supported, real tables are used instead. +- Temporary tables are not supported. - Numeric type dimensions (scale and precision) are constant. See the [docs](https://cloud.google.com/spanner/docs/data-types#numeric_types). ## Best practices diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py index 91ff8e924bf2..ce8f36e6dea0 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py @@ -17,4 +17,4 @@ @temp_table_keyword_args.for_db("spanner") def _spanner_temp_table_keyword_args(cfg, eng): - return {} + return {"prefixes": ["TEMPORARY"]} diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 2f30157bc60b..245eebbca5b4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -68,6 +68,11 @@ def isolation_level(self): def sequences(self): return exclusions.closed() + @property + def temporary_tables(self): + """Target database supports temporary tables.""" + return exclusions.closed() + def get_order_by_collation(self, _): """Get the default collation name. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index c38a9b8f495b..8f008cad6c84 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -341,6 +341,9 @@ def post_create_table(self, table): cols = [col.name for col in table.primary_key.columns] post_cmds = " PRIMARY KEY ({})".format(", ".join(cols)) + if "TEMPORARY" in table._prefixes: + raise NotImplementedError("Temporary tables are not supported.") + if table.kwargs.get("spanner_interleave_in"): post_cmds += ",\nINTERLEAVE IN PARENT {}".format( table.kwargs["spanner_interleave_in"] diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 0bc4030caf51..d0976629881c 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -36,7 +36,6 @@ from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_true -from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy import literal_column @@ -676,7 +675,6 @@ def define_temp_tables(cls, metadata): creating unique constraints. Overriding the test to replace constraints with indexes in testing data. """ - kw = temp_table_keyword_args(config, config.db) user_tmp = Table( "user_tmp", metadata, @@ -685,7 +683,6 @@ def define_temp_tables(cls, metadata): Column("foo", sqlalchemy.INT), sqlalchemy.Index("user_tmp_uq", "name", unique=True), sqlalchemy.Index("user_tmp_ix", "foo"), - **kw, ) if ( testing.requires.view_reflection.enabled From d54b7f3c0f8a195367c25c7a77910a4df265a61c Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Thu, 2 Dec 2021 17:07:32 +1300 Subject: [PATCH 123/582] fix: calculate limit value correctly for offset only queries (#160) Co-authored-by: larkee --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- .../sqlalchemy-spanner/test/test_suite.py | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 8f008cad6c84..9ba879ee98e2 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -259,7 +259,7 @@ def limit_clause(self, select, **kw): text += "\n LIMIT " + self.process(select._limit_clause, **kw) if select._offset_clause is not None: if select._limit_clause is None: - text += "\n LIMIT 9223372036854775805" + text += f"\n LIMIT {9223372036854775807-select._offset}" text += " OFFSET " + self.process(select._offset_clause, **kw) return text diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index d0976629881c..549bd2c7c854 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1613,6 +1613,31 @@ def test_staleness(self): assert connection.connection.staleness is None +class LimitOffsetTest(fixtures.TestBase): + """ + Check that SQL with an offset and no limit is being generated correctly. + """ + + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + self._metadata = MetaData(bind=self._engine) + + self._table = Table( + "users", + self._metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + + self._metadata.create_all(self._engine) + + def test_offset_only(self): + for offset in [1, 7, 10, 100, 1000, 10000]: + + with self._engine.connect().execution_options(read_only=True) as connection: + list(connection.execute(self._table.select().offset(offset)).fetchall()) + + class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): @classmethod def define_tables(cls, metadata): From fd3d1839bab86c0663ef0f54193b94f32a2a8ad1 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 3 Dec 2021 13:26:18 +0300 Subject: [PATCH 124/582] test: increase the package testing coverage (#161) --- .../_opentelemetry_tracing.py | 2 +- .../cloud/sqlalchemy_spanner/provision.py | 2 +- .../cloud/sqlalchemy_spanner/requirements.py | 2 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 8 +++- packages/sqlalchemy-spanner/noxfile.py | 18 +++++++- .../sqlalchemy-spanner/test/test_suite.py | 41 +++++++++++++++---- 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py index ed3b5b9d7751..cc0e8ac6bad7 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py @@ -52,9 +52,9 @@ def trace_call(name, extra_attributes=None): name, kind=trace.SpanKind.CLIENT, attributes=attributes ) as span: try: - span.set_status(Status(StatusCode.OK)) yield span except GoogleAPICallError as error: span.set_status(Status(StatusCode.ERROR)) span.record_exception(error) raise + span.set_status(Status(StatusCode.OK)) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py index ce8f36e6dea0..f56aaccf70b5 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/provision.py @@ -15,6 +15,6 @@ from sqlalchemy.testing.provision import temp_table_keyword_args -@temp_table_keyword_args.for_db("spanner") +@temp_table_keyword_args.for_db("spanner") # pragma: no cover def _spanner_temp_table_keyword_args(cfg, eng): return {"prefixes": ["TEMPORARY"]} diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 245eebbca5b4..8e30dd7a7a1e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -16,7 +16,7 @@ from sqlalchemy.testing.requirements import SuiteRequirements -class Requirements(SuiteRequirements): +class Requirements(SuiteRequirements): # pragma: no cover @property def computed_columns(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 9ba879ee98e2..68a0f94efc58 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -373,10 +373,14 @@ def visit_TEXT(self, type_, **kw): def visit_ARRAY(self, type_, **kw): return "ARRAY<{}>".format(self.process(type_.item_type, **kw)) - def visit_BINARY(self, type_, **kw): + def visit_BINARY(self, type_, **kw): # pragma: no cover + """ + The BINARY type is superseded by large_binary in + newer versions of SQLAlchemy (>1.4). + """ return "BYTES({})".format(type_.length or "MAX") - def visit_large_binary(self, type_, **kw): + def visit_large_binary(self, type_, **kw): # pragma: no cover return "BYTES({})".format(type_.length or "MAX") def visit_DECIMAL(self, type_, **kw): diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 5ec81b97481d..a47975032f5e 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -128,11 +128,25 @@ def compliance_test(session): "Credentials or emulator host must be set via environment variable" ) + session.install( + "pytest", "pytest-cov", "pytest-asyncio", + ) + session.install("pytest") session.install("mock") - session.install("-e", ".") + session.install("-e", ".[tracing]") session.run("python", "create_test_database.py") - session.run("pytest", "-v") + + session.run( + "py.test", + "--cov=google.cloud.sqlalchemy_spanner", + "--cov=tests", + "--cov-append", + "--cov-config=.coveragerc", + "--cov-report=", + "--cov-fail-under=0", + "test", + ) @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 549bd2c7c854..7915c49cc47a 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -20,6 +20,7 @@ import os import pkg_resources import pytest +import unittest from unittest import mock import sqlalchemy @@ -726,6 +727,7 @@ def test_reflect_bytes_column_max_len(self): self.metadata.create_all() Table("bytes_table", MetaData(bind=self.bind), autoload=True) + inspect(config.db).get_columns("bytes_table") @testing.provide_metadata def _test_get_unique_constraints(self, schema=None): @@ -1576,24 +1578,25 @@ def test_user_agent(self): ) -class ExecutionOptionsTest(fixtures.TestBase): +class ExecutionOptionsTest(fixtures.TestBase, unittest.TestCase): """ Check that `execution_options()` method correctly sets parameters on the underlying DB API connection. """ - def setUp(self): - self._engine = create_engine(get_db_url(), pool_size=1) - self._metadata = MetaData(bind=self._engine) + @classmethod + def setUpClass(cls): + cls._engine = create_engine(get_db_url(), pool_size=1) + cls._metadata = MetaData(bind=cls._engine) - self._table = Table( + cls._table = Table( "execution_options", - self._metadata, + cls._metadata, Column("opt_id", Integer, primary_key=True), Column("opt_name", String(16), nullable=False), ) - self._metadata.create_all(self._engine) + cls._metadata.create_all(cls._engine) def test_read_only(self): with self._engine.connect().execution_options(read_only=True) as connection: @@ -1602,11 +1605,11 @@ def test_read_only(self): def test_staleness(self): with self._engine.connect().execution_options( - read_only=True, staleness={"max_staleness": datetime.timedelta(seconds=5)} + read_only=True, staleness={"exact_staleness": datetime.timedelta(seconds=5)} ) as connection: connection.execute(select(["*"], from_obj=self._table)).fetchall() assert connection.connection.staleness == { - "max_staleness": datetime.timedelta(seconds=5) + "exact_staleness": datetime.timedelta(seconds=5) } with self._engine.connect() as connection: @@ -1638,6 +1641,26 @@ def test_offset_only(self): list(connection.execute(self._table.select().offset(offset)).fetchall()) +class TemporaryTableTest(fixtures.TestBase): + """ + Check that temporary tables raise an error on creation. + """ + + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + self._metadata = MetaData(bind=self._engine) + + def test_temporary_prefix(self): + with pytest.raises(NotImplementedError): + Table( + "users", + self._metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + prefixes=["TEMPORARY"], + ).create() + + class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): @classmethod def define_tables(cls, metadata): From 7bb418f092729cd897b16399951b9917d0257b22 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 7 Dec 2021 01:35:42 +0300 Subject: [PATCH 125/582] feat: support JSON data type (#135) * feat: support JSON data type * fix type * bug fixes * erase excess test override * erase excess override * fix errors Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> Co-authored-by: skuruppu --- .../cloud/sqlalchemy_spanner/requirements.py | 4 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 62 ++++++++ .../sqlalchemy-spanner/test/test_suite.py | 134 +++++++++++++++++- 3 files changed, 196 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 8e30dd7a7a1e..d552dc34b759 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -17,6 +17,10 @@ class Requirements(SuiteRequirements): # pragma: no cover + @property + def json_type(self): + return exclusions.open() + @property def computed_columns(self): return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 68a0f94efc58..ff01e277d1f6 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -34,9 +34,13 @@ GenericTypeCompiler, IdentifierPreparer, SQLCompiler, + OPERATORS, RESERVED_WORDS, ) +from sqlalchemy.sql.default_comparator import operator_lookup +from sqlalchemy.sql.operators import json_getitem_op +from google.cloud.spanner_v1.data_types import JsonObject from google.cloud import spanner_dbapi from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call @@ -47,6 +51,10 @@ def reset_connection(dbapi_conn, connection_record): dbapi_conn.connection.staleness = None +# register a method to get a single value of a JSON object +OPERATORS[json_getitem_op] = operator_lookup["json_getitem_op"] + + # Spanner-to-SQLAlchemy types map _type_map = { "BOOL": types.Boolean, @@ -60,8 +68,10 @@ def reset_connection(dbapi_conn, connection_record): "TIME": types.TIME, "TIMESTAMP": types.TIMESTAMP, "ARRAY": types.ARRAY, + "JSON": types.JSON, } + _type_map_inv = { types.Boolean: "BOOL", types.BINARY: "BYTES(MAX)", @@ -210,6 +220,53 @@ def visit_like_op_binary(self, binary, operator, **kw): binary.right._compiler_dispatch(self, **kw), ) + def _generate_generic_binary(self, binary, opstring, eager_grouping=False, **kw): + """The method is overriden to process JSON data type cases.""" + _in_binary = kw.get("_in_binary", False) + + kw["_in_binary"] = True + + if isinstance(opstring, str): + text = ( + binary.left._compiler_dispatch( + self, eager_grouping=eager_grouping, **kw + ) + + opstring + + binary.right._compiler_dispatch( + self, eager_grouping=eager_grouping, **kw + ) + ) + if _in_binary and eager_grouping: + text = "(%s)" % text + else: + # got JSON data + right_value = getattr( + binary.right, "value", None + ) or binary.right._compiler_dispatch( + self, eager_grouping=eager_grouping, **kw + ) + + text = ( + binary.left._compiler_dispatch( + self, eager_grouping=eager_grouping, **kw + ) + + """, "$.""" + + str(right_value) + + '"' + ) + text = "JSON_VALUE(%s)" % text + + return text + + def visit_json_path_getitem_op_binary(self, binary, operator, **kw): + """Build a JSON_VALUE() function call.""" + expr = """JSON_VALUE(%s, "$.%s")""" + + return expr % ( + self.process(binary.left, **kw), + self.process(binary.right, **kw), + ) + def render_literal_value(self, value, type_): """Render the value of a bind parameter as a quoted literal. @@ -404,6 +461,9 @@ def visit_NUMERIC(self, type_, **kw): def visit_BIGINT(self, type_, **kw): return "INT64" + def visit_JSON(self, type_, **kw): + return "JSON" + class SpannerDialect(DefaultDialect): """Cloud Spanner dialect. @@ -434,6 +494,8 @@ class SpannerDialect(DefaultDialect): statement_compiler = SpannerSQLCompiler type_compiler = SpannerTypeCompiler execution_ctx_cls = SpannerExecutionContext + _json_serializer = JsonObject + _json_deserializer = JsonObject @classmethod def dbapi(cls): diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 7915c49cc47a..b2339466ba0a 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -20,6 +20,7 @@ import os import pkg_resources import pytest +import random import unittest from unittest import mock @@ -61,7 +62,6 @@ ) from google.api_core.datetime_helpers import DatetimeWithNanoseconds - from google.cloud import spanner_dbapi from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 @@ -98,15 +98,17 @@ ) from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 + _DateFixture as _DateFixtureTest, + _LiteralRoundTripFixture, + _UnicodeFixture as _UnicodeFixtureTest, BooleanTest as _BooleanTest, DateTest as _DateTest, - _DateFixture as _DateFixtureTest, DateTimeHistoricTest, DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, DateTimeTest as _DateTimeTest, IntegerTest as _IntegerTest, - _LiteralRoundTripFixture, + JSONTest as _JSONTest, NumericTest as _NumericTest, StringTest as _StringTest, TextTest as _TextTest, @@ -115,7 +117,6 @@ TimestampMicrosecondsTest, UnicodeVarcharTest as _UnicodeVarcharTest, UnicodeTextTest as _UnicodeTextTest, - _UnicodeFixture as _UnicodeFixtureTest, ) from test._helpers import get_db_url @@ -1751,3 +1752,128 @@ def test_get_column_returns_computed(self): is_true("computed" in compData) is_true("sqltext" in compData["computed"]) eq_(self.normalize(compData["computed"]["sqltext"]), "normal+42") + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class JSONTest(_JSONTest): + @pytest.mark.skip("Values without keys are not supported.") + def test_single_element_round_trip(self, element): + pass + + def _test_round_trip(self, data_element): + data_table = self.tables.data_table + + config.db.execute( + data_table.insert(), + {"id": random.randint(1, 100000000), "name": "row1", "data": data_element}, + ) + + row = config.db.execute(select([data_table.c.data])).first() + + eq_(row, (data_element,)) + + def test_unicode_round_trip(self): + # note we include Unicode supplementary characters as well + with config.db.connect() as conn: + conn.execute( + self.tables.data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "r1", + "data": { + util.u("rΓ©ve🐍 illΓ©"): util.u("rΓ©ve🐍 illΓ©"), + "data": {"k1": util.u("drΓ΄l🐍e")}, + }, + }, + ) + + eq_( + conn.scalar(select([self.tables.data_table.c.data])), + { + util.u("rΓ©ve🐍 illΓ©"): util.u("rΓ©ve🐍 illΓ©"), + "data": {"k1": util.u("drΓ΄l🐍e")}, + }, + ) + + @pytest.mark.skip("Parameterized types are not supported.") + def test_eval_none_flag_orm(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_index_typed_comparison(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_path_typed_comparison(self): + pass + + @pytest.mark.skip("Custom JSON de-/serializers are not supported.") + def test_round_trip_custom_json(self): + pass + + def _index_fixtures(fn): + fn = testing.combinations( + ("boolean", True), + ("boolean", False), + ("boolean", None), + ("string", "some string"), + ("string", None), + ("integer", 15), + ("integer", 1), + ("integer", 0), + ("integer", None), + ("float", 28.5), + ("float", None), + id_="sa", + )(fn) + return fn + + @_index_fixtures + def test_index_typed_access(self, datatype, value): + data_table = self.tables.data_table + data_element = {"key1": value} + with config.db.connect() as conn: + conn.execute( + data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "row1", + "data": data_element, + "nulldata": data_element, + }, + ) + + expr = data_table.c.data["key1"] + expr = getattr(expr, "as_%s" % datatype)() + + roundtrip = conn.scalar(select([expr])) + if roundtrip in ("true", "false", None): + roundtrip = str(roundtrip).capitalize() + + eq_(str(roundtrip), str(value)) + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_json_null_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_sql_null(self): + pass From 9f45058be9e064e10dd0c9920ef01d81e3b8c0df Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Tue, 7 Dec 2021 16:15:04 +1300 Subject: [PATCH 126/582] docs: update benchmarks (#155) * docs: update benchmarks * docs: update benchmark results Co-authored-by: larkee Co-authored-by: skuruppu --- packages/sqlalchemy-spanner/BENCHMARKS.md | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/sqlalchemy-spanner/BENCHMARKS.md b/packages/sqlalchemy-spanner/BENCHMARKS.md index 2d7c4f204c8b..14c44358d8d3 100644 --- a/packages/sqlalchemy-spanner/BENCHMARKS.md +++ b/packages/sqlalchemy-spanner/BENCHMARKS.md @@ -8,17 +8,19 @@ The test suite requirements: Use `PROJECT`, `INSTANCE` and `DATABASE` module constants to set a project to execute tests on. -# 07-11-2021 +The following measurements were made on a VM instance. + +# 25-11-2021 |Test|mean, sec|error|std_dev| |----|-------|-----|--------| -|SPANNER insert_one_row_with_fetch_after| 0.91|0.01|0.09| -|ALCHEMY insert_one_row_with_fetch_after| 1.07| 0.0|0.03| -|SPANNER read_one_row| 0.33| 0.0| 0.01| -|ALCHEMY read_one_row| 0.3| 0.0| 0.01| -|SPANNER insert_many_rows| 1.37| 0.02| 0.12| -|ALCHEMY insert_many_rows| 24.41| 0.07| 0.49| -|SPANNER select_many_rows| 0.31| 0.02| 0.08| -|ALCHEMY select_many_rows| 0.22| 0.03| 0.01| -|SPANNER insert_many_rows_with_mutations| 0.34| 0.0| 0.03| -|SQLALCHEMY insert_many_rows_with_mutations| 25.1| 0.03| 0.31| +|SPANNER insert_one_row_with_fetch_after| 0.16|0.0|0.03| +|ALCHEMY insert_one_row_with_fetch_after| 0.11| 0.0|0.02| +|SPANNER read_one_row| 0.04| 0.0| 0.01| +|ALCHEMY read_one_row| 0.01| 0.0| 0.0| +|SPANNER insert_many_rows| 0.33| 0.01| 0.05| +|ALCHEMY insert_many_rows| 0.32| 0.01| 0.06| +|SPANNER select_many_rows| 0.04| 0.0| 0.01| +|ALCHEMY select_many_rows| 0.03| 0.0| 0.0| +|SPANNER insert_many_rows_with_mutations| 0.07| 0.0| 0.03| +|SQLALCHEMY insert_many_rows_with_mutations| 0.31| 0.01| 0.07| From 7b02c9308cf4002edec899ba13d425b15ab61526 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Wed, 8 Dec 2021 11:44:15 +1100 Subject: [PATCH 127/582] chore: add release please config (#162) --- packages/sqlalchemy-spanner/.github/release-please.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/sqlalchemy-spanner/.github/release-please.yml diff --git a/packages/sqlalchemy-spanner/.github/release-please.yml b/packages/sqlalchemy-spanner/.github/release-please.yml new file mode 100644 index 000000000000..4507ad0598a5 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/release-please.yml @@ -0,0 +1 @@ +releaseType: python From d1e38b26fb43f3d54bc9544b80046013317fef3d Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 8 Dec 2021 05:22:18 +0300 Subject: [PATCH 128/582] test: add base class for the Spanner specific tests (#158) Co-authored-by: larkee <31196561+larkee@users.noreply.github.com> --- .../sqlalchemy-spanner/test/test_suite.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index b2339466ba0a..e0e8d610ef1b 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1510,16 +1510,20 @@ class Address(Base): assert str(query.statement.compile(session.bind)) == EXPECTED_QUERY -class InterleavedTablesTest(fixtures.TestBase): - """ - Check that CREATE TABLE statements for interleaved tables are correctly - generated. - """ +class SpannerSpecificTestBase(fixtures.TestBase): + """Base class for the Cloud Spanner related tests.""" def setUp(self): self._engine = create_engine(get_db_url()) self._metadata = MetaData(bind=self._engine) + +class InterleavedTablesTest(SpannerSpecificTestBase): + """ + Check that CREATE TABLE statements for interleaved tables are correctly + generated. + """ + def test_interleave(self): EXP_QUERY = ( "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " @@ -1562,13 +1566,9 @@ def test_interleave_on_delete_cascade(self): execute.assert_called_once_with(EXP_QUERY, []) -class UserAgentTest(fixtures.TestBase): +class UserAgentTest(SpannerSpecificTestBase): """Check that SQLAlchemy dialect uses correct user agent.""" - def setUp(self): - self._engine = create_engine(get_db_url()) - self._metadata = MetaData(bind=self._engine) - def test_user_agent(self): dist = pkg_resources.get_distribution("sqlalchemy-spanner") From 55d654a8cc2484ed1816c309f765752bbf38b176 Mon Sep 17 00:00:00 2001 From: larkee <31196561+larkee@users.noreply.github.com> Date: Wed, 8 Dec 2021 18:24:14 +1300 Subject: [PATCH 129/582] refactor: update default user agent header to match convention (#164) Co-authored-by: larkee --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- packages/sqlalchemy-spanner/test/test_suite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index ff01e277d1f6..62eda640a024 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -549,7 +549,7 @@ def create_connect_args(self, url): dist = pkg_resources.get_distribution("sqlalchemy-spanner") return ( [match.group("instance"), match.group("database"), match.group("project")], - {"user_agent": dist.project_name + "/" + dist.version}, + {"user_agent": f"gl-{dist.project_name}/{dist.version}"}, ) @engine_to_connection diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index e0e8d610ef1b..5559cfad362f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1575,7 +1575,7 @@ def test_user_agent(self): with self._engine.connect() as connection: assert ( connection.connection.instance._client._client_info.user_agent - == dist.project_name + "/" + dist.version + == f"gl-{dist.project_name}/{dist.version}" ) From e672d518383261e7a6b6647f2a19e30c4a775da1 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 9 Dec 2021 09:23:52 +1100 Subject: [PATCH 130/582] chore: setup release 1.0.0 (#165) Release-As: 1.0.0 --- packages/sqlalchemy-spanner/README.md | 10 ++++------ packages/sqlalchemy-spanner/setup.cfg | 3 --- packages/sqlalchemy-spanner/setup.py | 10 +++++++++- packages/sqlalchemy-spanner/version.py | 7 +++++++ 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 packages/sqlalchemy-spanner/version.py diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 46eae9142e6d..5927cb35555f 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -2,9 +2,7 @@ Spanner dialect for SQLAlchemy represents an interface API designed to make it possible to control Cloud Spanner databases with SQLAlchemy API. The dialect is built on top of [the Spanner DB API](https://github.com/googleapis/python-spanner/tree/master/google/cloud/spanner_dbapi), which is designed in accordance with [PEP-249](https://www.python.org/dev/peps/pep-0249/). -This project has **Preview** release status. Known limitations are listed [here](#features-and-limitations). All supported features have been tested and verified to work with the test configurations. There may be configurations and/or data model variations that have not yet been covered by the tests and that show unexpected behavior. Please report any problems that you might encounter by [creating a new issue](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/issues/new). - -**NOTE: This project may still make breaking changes without prior notice and should not yet be used for production purposes.** +Known limitations are listed [here](#features-and-limitations). All supported features have been tested and verified to work with the test configurations. There may be configurations and/or data model variations that have not yet been covered by the tests and that show unexpected behavior. Please report any problems that you might encounter by [creating a new issue](https://github.com/googleapis/python-spanner-sqlalchemy/issues/new). - [Cloud Spanner product documentation](https://cloud.google.com/spanner/docs) - [SQLAlchemy product documentation](https://www.sqlalchemy.org/) @@ -22,7 +20,7 @@ In order to use this package, you first need to go through the following steps: To install an in-development version of the package, clone its Git-repository: ``` -git clone https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy.git +git clone https://github.com/googleapis/python-spanner-sqlalchemy.git ``` Next install the package from the package `setup.py` file: ``` @@ -291,11 +289,11 @@ The dialect test suite can be runned on [Spanner emulator](https://cloud.google. ## Contributing -Contributions to this library are welcome and encouraged. Please report issues, file feature requests, and send pull requests. See [CONTRIBUTING](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get +Contributions to this library are welcome and encouraged. Please report issues, file feature requests, and send pull requests. See [CONTRIBUTING](https://github.com/googleapis/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get started. **Note that this project is not officially supported by Google as part of the Cloud Spanner product.** Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See the [Code -of Conduct](https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy/blob/main/code-of-conduct.md) for more information. +of Conduct](https://github.com/googleapis/python-spanner-sqlalchemy/blob/main/code-of-conduct.md) for more information. diff --git a/packages/sqlalchemy-spanner/setup.cfg b/packages/sqlalchemy-spanner/setup.cfg index 7b1c6800ff0a..fd3202c407c1 100644 --- a/packages/sqlalchemy-spanner/setup.cfg +++ b/packages/sqlalchemy-spanner/setup.cfg @@ -14,9 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -[egg_info] -tag_build = dev - [tool:pytest] addopts= --tb native -v -r fxX --maxfail=25 -p no:warnings python_files=test/*test_*.py diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 09d67985117f..c2cfe3ea6026 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import setuptools @@ -32,6 +33,13 @@ ] } +BASE_DIR = os.path.dirname(__file__) +VERSION_FILENAME = os.path.join(BASE_DIR, "version.py") +PACKAGE_INFO = {} +with open(VERSION_FILENAME) as f: + exec(f.read(), PACKAGE_INFO) +version = PACKAGE_INFO["__version__"] + # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. packages = [ @@ -61,7 +69,7 @@ namespace_packages=namespaces, packages=packages, url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", - version="0.1", + version=version, include_package_data=True, zip_safe=False, ) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py new file mode 100644 index 000000000000..498b5ee5d7eb --- /dev/null +++ b/packages/sqlalchemy-spanner/version.py @@ -0,0 +1,7 @@ +# Copyright 2021 Google LLC +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file or at +# https://developers.google.com/open-source/licenses/bsd + +__version__ = "1.0.0" From 9f78c53554cd9f0a6917e540bbb787de3dcfe52e Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 9 Dec 2021 00:48:38 +0000 Subject: [PATCH 131/582] chore: release 1.0.0 (#167) :robot: I have created a release \*beep\* \*boop\* --- ## [1.0.0](https://www.github.com/googleapis/python-spanner-sqlalchemy/compare/v0.1.0...v1.0.0) (2021-12-08) ### Features * add code samples ([#55](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/55)) ([406c34b](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/406c34bdb21e01a1317c074fab34d87bb3d61020)) * set user-agent string to distinguish SQLAlchemy requests ([#116](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/116)) ([b5e1a21](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/b5e1a211a0475690feed36fd222a41c216d8fb82)) * support computed columns ([#139](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/139)) ([046ca97](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/046ca975778f4793e2c37d70d2a602546f9d4699)), closes [#137](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/137) * support JSON data type ([#135](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/135)) ([184a7d5](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/184a7d576a790bbbd049fe80d589af78831379b4)) * support read_only connections ([#125](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/125)) ([352c47d](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/352c47de7bb4ea1c30b50a7fe5aee0c4d102e80e)) * support stale reads ([#146](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/146)) ([d80cb27](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/d80cb2792437731c24905c7a6919468c37779c67)) ### Bug Fixes * ALTER COLUMN NOT NULL directive fails because of inappropriate syntax ([#124](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/124)) ([c433cda](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/c433cda99fd8544810c878328a272a3a9430630f)) * array columns reflection ([#119](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/119)) ([af3b97b](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/af3b97bfa4b3ed4b223384c9ed3fa0643204d8c9)), closes [#118](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/118) * calculate limit value correctly for offset only queries ([#160](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/160)) ([6844336](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/684433682ed29d9cde8c9898796024cefeb38493)) * correct typo in spanner_interleave_on_delete_cascade keyword ([#99](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/99)) ([a0ebf75](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/a0ebf758eda351c0a20103f9e8c2243f002b2e6e)) * raise Unimplemented error when creating temporary tables ([#159](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/159)) ([646d6ac](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/646d6ac24ccd0643b67abff9da28118e0a6f6e55)) * rollback failed exception log ([#106](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/106)) ([809e6ab](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/809e6abb29f82a7fbe6587d606e8d75283f2a2fe)) ### Documentation * add query hints example ([#153](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/153)) ([9c23804](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/9c23804746bc8c638b6c22f2cb6ea57778f7fd19)) * reformatted README titles ([#141](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/141)) ([a3ccbac](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/a3ccbac476679fe8048ed2109e5489b873278c9c)) * update benchmarks ([#155](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/155)) ([3500653](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/35006536e4de31dbcba022b73f0aadf39bc89e39)) ### Miscellaneous Chores * setup release 1.0.0 ([#165](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/165)) ([37a415d](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/37a415d071d39e99f233a1c15c1c4b89bd436570)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- packages/sqlalchemy-spanner/CHANGELOG.md | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 packages/sqlalchemy-spanner/CHANGELOG.md diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md new file mode 100644 index 000000000000..d431e1bae20d --- /dev/null +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## [1.0.0](https://www.github.com/googleapis/python-spanner-sqlalchemy/compare/v0.1.0...v1.0.0) (2021-12-08) + + +### Features + +* add code samples ([#55](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/55)) ([406c34b](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/406c34bdb21e01a1317c074fab34d87bb3d61020)) +* set user-agent string to distinguish SQLAlchemy requests ([#116](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/116)) ([b5e1a21](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/b5e1a211a0475690feed36fd222a41c216d8fb82)) +* support computed columns ([#139](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/139)) ([046ca97](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/046ca975778f4793e2c37d70d2a602546f9d4699)), closes [#137](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/137) +* support JSON data type ([#135](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/135)) ([184a7d5](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/184a7d576a790bbbd049fe80d589af78831379b4)) +* support read_only connections ([#125](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/125)) ([352c47d](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/352c47de7bb4ea1c30b50a7fe5aee0c4d102e80e)) +* support stale reads ([#146](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/146)) ([d80cb27](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/d80cb2792437731c24905c7a6919468c37779c67)) + + +### Bug Fixes + +* ALTER COLUMN NOT NULL directive fails because of inappropriate syntax ([#124](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/124)) ([c433cda](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/c433cda99fd8544810c878328a272a3a9430630f)) +* array columns reflection ([#119](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/119)) ([af3b97b](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/af3b97bfa4b3ed4b223384c9ed3fa0643204d8c9)), closes [#118](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/118) +* calculate limit value correctly for offset only queries ([#160](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/160)) ([6844336](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/684433682ed29d9cde8c9898796024cefeb38493)) +* correct typo in spanner_interleave_on_delete_cascade keyword ([#99](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/99)) ([a0ebf75](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/a0ebf758eda351c0a20103f9e8c2243f002b2e6e)) +* raise Unimplemented error when creating temporary tables ([#159](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/159)) ([646d6ac](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/646d6ac24ccd0643b67abff9da28118e0a6f6e55)) +* rollback failed exception log ([#106](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/106)) ([809e6ab](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/809e6abb29f82a7fbe6587d606e8d75283f2a2fe)) + + +### Documentation + +* add query hints example ([#153](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/153)) ([9c23804](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/9c23804746bc8c638b6c22f2cb6ea57778f7fd19)) +* reformatted README titles ([#141](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/141)) ([a3ccbac](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/a3ccbac476679fe8048ed2109e5489b873278c9c)) +* update benchmarks ([#155](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/155)) ([3500653](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/35006536e4de31dbcba022b73f0aadf39bc89e39)) + + +### Miscellaneous Chores + +* setup release 1.0.0 ([#165](https://www.github.com/googleapis/python-spanner-sqlalchemy/issues/165)) ([37a415d](https://www.github.com/googleapis/python-spanner-sqlalchemy/commit/37a415d071d39e99f233a1c15c1c4b89bd436570)) From c3640682786f5feedd9f21593dd3d8fe18c5bf38 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 9 Dec 2021 16:26:33 +1100 Subject: [PATCH 132/582] chore: remove unused docs-presubmit (#166) --- .../.kokoro/docs/common.cfg | 63 ------------------- .../.kokoro/docs/docs-presubmit.cfg | 28 --------- .../sqlalchemy-spanner/.kokoro/docs/docs.cfg | 1 - 3 files changed, 92 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/common.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg deleted file mode 100644 index 76db11b1901c..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/docs/common.cfg +++ /dev/null @@ -1,63 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "python-spanner-sqlalchemy/.kokoro/trampoline_v2.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-lib-docs" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner-sqlalchemy/.kokoro/publish-docs.sh" -} - -env_vars: { - key: "STAGING_BUCKET" - value: "docs-staging" -} - -env_vars: { - key: "V2_STAGING_BUCKET" - value: "docs-staging-v2" -} - -# It will upload the docker image after successful builds. -env_vars: { - key: "TRAMPOLINE_IMAGE_UPLOAD" - value: "true" -} - -# It will always build the docker image. -env_vars: { - key: "TRAMPOLINE_DOCKERFILE" - value: ".kokoro/docker/docs/Dockerfile" -} - -# Fetch the token needed for reporting release status to GitHub -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "yoshi-automation-github-key" - } - } -} - -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "docuploader_service_account" - } - } -} diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg deleted file mode 100644 index 5e07943d6308..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/docs/docs-presubmit.cfg +++ /dev/null @@ -1,28 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "STAGING_BUCKET" - value: "gcloud-python-test" -} - -env_vars: { - key: "V2_STAGING_BUCKET" - value: "gcloud-python-test" -} - -# We only upload the image in the main `docs` build. -env_vars: { - key: "TRAMPOLINE_IMAGE_UPLOAD" - value: "false" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" -} - -# Only run this nox session. -env_vars: { - key: "NOX_SESSION" - value: "docs docfx" -} diff --git a/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg b/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg deleted file mode 100644 index 8f43917d92fe..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/docs/docs.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file From b84bcddde2f6c26930cb6ddbf3658f76e6143180 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 14 Dec 2021 04:11:48 +0300 Subject: [PATCH 133/582] fix: bump up google-cloud-spanner required version (#171) --- packages/sqlalchemy-spanner/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index c2cfe3ea6026..3b78f69c2f0d 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -22,7 +22,7 @@ description = "SQLAlchemy dialect integrated into Cloud Spanner database" dependencies = [ "sqlalchemy>=1.1.13, <=1.3.23", - "google-cloud-spanner>=3.3.0", + "google-cloud-spanner>=3.12.0", "alembic", ] extras = { From 233553abbd966b1b09e3c5a110b19e5fdc3dd36a Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 16 Dec 2021 04:32:39 +0300 Subject: [PATCH 134/582] fix: NOT NULL computed column creation failure (#173) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 23 ++++++++++++++++ .../sqlalchemy-spanner/test/test_suite.py | 27 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 62eda640a024..5e661ca5b712 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -324,6 +324,29 @@ def limit_clause(self, select, **kw): class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" + def get_column_specification(self, column, **kwargs): + """Build new column specifications. + + Overridden to move the NOT NULL statement to front + of a computed column expression definitions. + """ + colspec = ( + self.preparer.format_column(column) + + " " + + self.dialect.type_compiler.process(column.type, type_expression=column) + ) + default = self.get_column_default_string(column) + if default is not None: + colspec += " DEFAULT " + default + + if not column.nullable: + colspec += " NOT NULL" + + if column.computed is not None: + colspec += " " + self.process(column.computed) + + return colspec + def visit_computed_column(self, generated, **kw): """Computed column operator.""" text = "AS (%s) STORED" % self.sql_compiler.process( diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 5559cfad362f..75fc9a3c707c 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1753,6 +1753,33 @@ def test_get_column_returns_computed(self): is_true("sqltext" in compData["computed"]) eq_(self.normalize(compData["computed"]["sqltext"]), "normal+42") + def test_create_not_null_computed_column(self): + """ + SPANNER TEST: + + Check that on creating a computed column with a NOT NULL + clause the clause is set in front of the computed column + statement definition and doesn't cause failures. + """ + engine = create_engine(get_db_url()) + metadata = MetaData(bind=engine) + + Table( + "Singers", + metadata, + Column("SingerId", String(36), primary_key=True, nullable=False), + Column("FirstName", String(200)), + Column("LastName", String(200), nullable=False), + Column( + "FullName", + String(400), + Computed("COALESCE(FirstName || ' ', '') || LastName"), + nullable=False, + ), + ) + + metadata.create_all(engine) + @pytest.mark.skipif( bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" From cd239fcdb324076878d7b110e1fc94bbaa263414 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 21 Dec 2021 11:56:37 +0000 Subject: [PATCH 135/582] Update README.md (#178) Closes #170 --- packages/sqlalchemy-spanner/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 5927cb35555f..28d09eee9b9b 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -119,9 +119,11 @@ client = Table( spanner_interleave_in="team", spanner_interleave_on_delete_cascade=True, ) +client.add_is_dependent_on(team) client.create(engine) ``` +**Note**: Interleaved tables have a dependency between them, so the parent table must be created before the child table. When creating tables with this feature, make sure to call `add_is_dependent_on()` on the child table to request SQLAlchemy to create the parent table before the child table. ### Unique constraints Cloud Spanner doesn't support direct UNIQUE constraints creation. In order to achieve column values uniqueness UNIQUE indexes should be used. From ecbbc490ee836dc226a3d621276a8dfc4a6c8e21 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 24 Dec 2021 02:32:24 +0000 Subject: [PATCH 136/582] docs: add a README section for the autoincremented ids (#180) --- packages/sqlalchemy-spanner/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 28d09eee9b9b..b228a680fd6e 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -157,6 +157,18 @@ eng = create_engine("spanner:///projects/project-id/instances/instance-id/databa autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") ``` +### Autoincremented IDs +Cloud Spanner doesn't support autoincremented IDs mechanism due to performance reasons ([see for more details](https://cloud.google.com/spanner/docs/schema-design#primary-key-prevent-hotspots)). Though it's not encouraged to do so, in case you *need* the feature, you can simulate it manually, for example: +```python +with engine.begin() as connection: + top_id = connection.execute( + select([user.c.user_id]).order_by(user.c.user_id.desc()).limit(1) + ).fetchone() + next_id = top_id[0] + 1 if top_id else 1 + + connection.execute(user.insert(), {"user_id": next_id}) +``` + ### Query hints Spanner dialect supports [query hints](https://cloud.google.com/spanner/docs/query-syntax#table_hints), which give the ability to set additional query execution parameters. Usage example: ```python From ef560269c49806717226d238ddaf47bdbbeeac80 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 30 Dec 2021 09:50:14 +1100 Subject: [PATCH 137/582] docs: explicitly recommend uuid to generate PKs (#182) Towards #181 --- packages/sqlalchemy-spanner/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index b228a680fd6e..a29ffdfbee16 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -58,6 +58,8 @@ metadata.create_all(engine) ### Insert a row ```python +import uuid + from sqlalchemy import ( MetaData, Table, @@ -68,9 +70,10 @@ engine = create_engine( "spanner:///projects/project-id/instances/instance-id/databases/database-id" ) user = Table("users", MetaData(bind=engine), autoload=True) +user_id = uuid.uuid4().hex[:6].lower() with engine.begin() as connection: - connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) + connection.execute(user.insert(), {"user_id": user_id, "user_name": "Full Name"}) ``` ### Read @@ -158,7 +161,9 @@ autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") ``` ### Autoincremented IDs -Cloud Spanner doesn't support autoincremented IDs mechanism due to performance reasons ([see for more details](https://cloud.google.com/spanner/docs/schema-design#primary-key-prevent-hotspots)). Though it's not encouraged to do so, in case you *need* the feature, you can simulate it manually, for example: +Cloud Spanner doesn't support autoincremented IDs mechanism due to performance reasons ([see for more details](https://cloud.google.com/spanner/docs/schema-design#primary-key-prevent-hotspots)). We recommend that you use the Python [uuid](https://docs.python.org/3/library/uuid.html) module to generate primary key fields to avoid creating monotonically increasing keys. + +Though it's not encouraged to do so, in case you *need* the feature, you can simulate it manually as follows: ```python with engine.begin() as connection: top_id = connection.execute( From f64a20cb911ade84c502a9b82855103814629e93 Mon Sep 17 00:00:00 2001 From: skuruppu Date: Thu, 30 Dec 2021 13:28:16 +1100 Subject: [PATCH 138/582] chore: auto-assign issues to new Spanner owner (#175) --- packages/sqlalchemy-spanner/.github/blunderbuss.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.github/blunderbuss.yml diff --git a/packages/sqlalchemy-spanner/.github/blunderbuss.yml b/packages/sqlalchemy-spanner/.github/blunderbuss.yml new file mode 100644 index 000000000000..8715e17dc449 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/blunderbuss.yml @@ -0,0 +1,2 @@ +assign_issues: + - vi3k6i5 From 6d0f7b99f36c91ae8718cc0665497bf3fe1014de Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 10 Jan 2022 07:29:18 +0000 Subject: [PATCH 139/582] fix: connection reset fails when an additional dialect is used (#188) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 3 ++- packages/sqlalchemy-spanner/test/test_suite.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 5e661ca5b712..fa704c951beb 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -48,7 +48,8 @@ @listens_for(Pool, "reset") def reset_connection(dbapi_conn, connection_record): """An event of returning a connection back to a pool.""" - dbapi_conn.connection.staleness = None + if getattr(dbapi_conn.connection, "staleness", None) is not None: + dbapi_conn.connection.staleness = None # register a method to get a single value of a JSON object diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite.py index 75fc9a3c707c..735c0be8ea5e 100644 --- a/packages/sqlalchemy-spanner/test/test_suite.py +++ b/packages/sqlalchemy-spanner/test/test_suite.py @@ -1616,6 +1616,9 @@ def test_staleness(self): with self._engine.connect() as connection: assert connection.connection.staleness is None + with self._engine.connect() as connection: + del connection.staleness + class LimitOffsetTest(fixtures.TestBase): """ From 03cd137197f58ddc713bcb60e28efb0057c7d4cb Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 27 Jan 2022 08:10:14 +0000 Subject: [PATCH 140/582] feat: support SQLAlchemy 1.4 (#191) * WIP: update tests for SQLAlchemy 1.4 * feat: support SQLAlchemy 1.4 * fix migration bugs * test: update yaml * install 1.4 * fix the dialect name * fix caching * fix temp tables * update test suite * fix pytest * del unused * fix user agent * fix test * fix reflection test * fix test * fix tests * lint fix * fix test * migration fix * fix migration * check * fix test * fix migrations * fix migrations test * change default py version * minor fixes * test workflow changes * new tests skip * kokoro session fix --- .../.github/sync-repo-settings.yaml | 3 +- .../.github/workflows/test_suite.yml | 28 +- .../.kokoro/presubmit/compliance.cfg | 2 +- .../sqlalchemy-spanner/create_test_config.py | 4 +- .../create_test_database.py | 15 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 3 +- packages/sqlalchemy-spanner/noxfile.py | 49 +- packages/sqlalchemy-spanner/setup.py | 2 +- .../test/{test_suite.py => test_suite_13.py} | 0 .../sqlalchemy-spanner/test/test_suite_14.py | 2144 +++++++++++++++++ .../sqlalchemy-spanner/test_migration_env.py | 2 +- 11 files changed, 2229 insertions(+), 23 deletions(-) rename packages/sqlalchemy-spanner/test/{test_suite.py => test_suite_13.py} (100%) create mode 100644 packages/sqlalchemy-spanner/test/test_suite_14.py diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index c8e9158a7cd1..fd39852dc307 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -9,7 +9,8 @@ branchProtectionRules: requiredStatusCheckContexts: - 'lint' - 'unit' - - 'compliance_tests' + - 'compliance_tests_13' + - 'compliance_tests_14' - 'migration_tests' - 'cla/google' - 'Kokoro' diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 292c3d69a573..9ae088cac137 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -38,7 +38,7 @@ jobs: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - compliance_tests: + compliance_tests_13: runs-on: ubuntu-latest services: @@ -57,7 +57,31 @@ jobs: - name: Install nox run: python -m pip install nox - name: Run Compliance Tests - run: nox -s compliance_test + run: nox -s compliance_test_13 + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + + compliance_tests_14: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Compliance Tests + run: nox -s compliance_test_14 env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg index 3383be455b5e..d6cf2690b281 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg @@ -3,5 +3,5 @@ # Only run this nox session. env_vars: { key: "NOX_SESSION" - value: "compliance_test" + value: "compliance_test_13" } diff --git a/packages/sqlalchemy-spanner/create_test_config.py b/packages/sqlalchemy-spanner/create_test_config.py index 34d5b863d931..19b46d49bc5b 100644 --- a/packages/sqlalchemy-spanner/create_test_config.py +++ b/packages/sqlalchemy-spanner/create_test_config.py @@ -21,7 +21,7 @@ def set_test_config(project, instance): config = configparser.ConfigParser() url = ( - f"spanner:///projects/{project}/instances/{instance}/" + f"spanner+spanner:///projects/{project}/instances/{instance}/" "databases/compliance-test" ) config.add_section("db") @@ -38,4 +38,4 @@ def main(argv): if __name__ == "__main__": - main(sys.argv[1:]) + main(sys.argv[1:]) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 8abbed65bb54..91be45f8d7bc 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -82,19 +82,18 @@ def create_test_instance(): instance = CLIENT.instance(instance_id, instance_config, labels=labels) - try: - created_op = instance.create() - created_op.result(1800) # block until completion + created_op = instance.create() + created_op.result(1800) # block until completion except AlreadyExists: - pass # instance was already created + pass # instance was already created try: - database = instance.database("compliance-test") - created_op = database.create() - created_op.result(1800) + database = instance.database("compliance-test") + created_op = database.create() + created_op.result(1800) except AlreadyExists: - pass # instance was already created + pass # instance was already created set_test_config(PROJECT, instance_id) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index fa704c951beb..184e5b476174 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -495,7 +495,7 @@ class SpannerDialect(DefaultDialect): Represents an API layer to control Cloud Spanner database with SQLAlchemy API. """ - name = "spanner" + name = "spanner+spanner" driver = "spanner" positional = False paramstyle = "format" @@ -512,6 +512,7 @@ class SpannerDialect(DefaultDialect): supports_native_enum = True supports_native_boolean = True supports_native_decimal = True + supports_statement_cache = True ddl_compiler = SpannerDDLCompiler preparer = SpannerIdentifierPreparer diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index a47975032f5e..fb9f923d2ee4 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -64,8 +64,7 @@ class = StreamHandler op.alter_column( 'account', 'name', - existing_type=sa.String(50), - nullable=True, + existing_type=sa.String(70), )""" @@ -114,7 +113,7 @@ def lint_setup_py(session): @nox.session(python=DEFAULT_PYTHON_VERSION) -def compliance_test(session): +def compliance_test_13(session): """Run SQLAlchemy dialect compliance test suite.""" # Check the value of `RUN_COMPLIANCE_TESTS` env var. It defaults to true. @@ -132,7 +131,6 @@ def compliance_test(session): "pytest", "pytest-cov", "pytest-asyncio", ) - session.install("pytest") session.install("mock") session.install("-e", ".[tracing]") session.run("python", "create_test_database.py") @@ -145,7 +143,46 @@ def compliance_test(session): "--cov-config=.coveragerc", "--cov-report=", "--cov-fail-under=0", - "test", + "--asyncio-mode=auto", + "test/test_suite_13.py", + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def compliance_test_14(session): + """Run SQLAlchemy dialect compliance test suite.""" + + # Check the value of `RUN_COMPLIANCE_TESTS` env var. It defaults to true. + if os.environ.get("RUN_COMPLIANCE_TESTS", "true") == "false": + session.skip("RUN_COMPLIANCE_TESTS is set to false, skipping") + # Sanity check: Only run tests if the environment variable is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( + "SPANNER_EMULATOR_HOST", "" + ): + session.skip( + "Credentials or emulator host must be set via environment variable" + ) + + session.install( + "pytest", "pytest-cov", "pytest-asyncio", + ) + + session.install("mock") + session.install("-e", ".[tracing]") + session.run("python", "create_test_database.py") + + session.install("sqlalchemy>=1.4") + + session.run( + "py.test", + "--cov=google.cloud.sqlalchemy_spanner", + "--cov=tests", + "--cov-append", + "--cov-config=.coveragerc", + "--cov-report=", + "--cov-fail-under=0", + "--asyncio-mode=auto", + "test/test_suite_14.py", ) @@ -180,7 +217,7 @@ def migration_test(session): "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), ) db_url = ( - f"spanner:///projects/{project}/instances/" + f"spanner+spanner:///projects/{project}/instances/" "sqlalchemy-dialect-test/databases/compliance-test" ) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 3b78f69c2f0d..2f1be807c671 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -60,7 +60,7 @@ description=description, entry_points={ "sqlalchemy.dialects": [ - "spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" + "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" ] }, install_requires=dependencies, diff --git a/packages/sqlalchemy-spanner/test/test_suite.py b/packages/sqlalchemy-spanner/test/test_suite_13.py similarity index 100% rename from packages/sqlalchemy-spanner/test/test_suite.py rename to packages/sqlalchemy-spanner/test/test_suite_13.py diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py new file mode 100644 index 000000000000..688d822ee29f --- /dev/null +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -0,0 +1,2144 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import timezone +import decimal +import operator +import os +import pkg_resources +import pytest +import random +from unittest import mock + +import sqlalchemy +from sqlalchemy import create_engine +from sqlalchemy import inspect +from sqlalchemy import testing +from sqlalchemy import ForeignKey +from sqlalchemy import MetaData +from sqlalchemy.schema import DDL +from sqlalchemy.schema import Computed +from sqlalchemy.testing import config +from sqlalchemy.testing import engines +from sqlalchemy.testing import eq_ +from sqlalchemy.testing import provide_metadata, emits_warning +from sqlalchemy.testing import fixtures +from sqlalchemy.testing.provision import temp_table_keyword_args +from sqlalchemy.testing.schema import Column +from sqlalchemy.testing.schema import Table +from sqlalchemy import literal_column +from sqlalchemy import select +from sqlalchemy import util +from sqlalchemy import union +from sqlalchemy import event +from sqlalchemy import exists +from sqlalchemy import Boolean +from sqlalchemy import Float +from sqlalchemy import LargeBinary +from sqlalchemy import String +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relation +from sqlalchemy.orm import Session +from sqlalchemy.types import Integer +from sqlalchemy.types import Numeric +from sqlalchemy.types import Text +from sqlalchemy.testing import requires +from sqlalchemy.testing import is_true +from sqlalchemy.testing.fixtures import ( + ComputedReflectionFixtureTest as _ComputedReflectionFixtureTest, +) + +from google.api_core.datetime_helpers import DatetimeWithNanoseconds + +from google.cloud import spanner_dbapi + +from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest +from sqlalchemy.testing.suite.test_ddl import TableDDLTest as _TableDDLTest +from sqlalchemy.testing.suite.test_ddl import ( + FutureTableDDLTest as _FutureTableDDLTest, + LongNameBlowoutTest as _LongNameBlowoutTest, +) +from sqlalchemy.testing.suite.test_update_delete import ( + SimpleUpdateDeleteTest as _SimpleUpdateDeleteTest, +) +from sqlalchemy.testing.suite.test_dialect import ( + DifficultParametersTest as _DifficultParametersTest, + EscapingTest as _EscapingTest, +) +from sqlalchemy.testing.suite.test_insert import ( + InsertBehaviorTest as _InsertBehaviorTest, +) +from sqlalchemy.testing.suite.test_select import ( # noqa: F401, F403 + CompoundSelectTest as _CompoundSelectTest, + ExistsTest as _ExistsTest, + FetchLimitOffsetTest as _FetchLimitOffsetTest, + IdentityAutoincrementTest as _IdentityAutoincrementTest, + IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, + LikeFunctionsTest as _LikeFunctionsTest, + OrderByLabelTest as _OrderByLabelTest, + PostCompileParamsTest as _PostCompileParamsTest, +) +from sqlalchemy.testing.suite.test_reflection import ( + ComponentReflectionTestExtra as _ComponentReflectionTestExtra, + QuotedNameArgumentTest as _QuotedNameArgumentTest, + ComponentReflectionTest as _ComponentReflectionTest, + CompositeKeyReflectionTest as _CompositeKeyReflectionTest, + ComputedReflectionTest as _ComputedReflectionTest, + HasIndexTest as _HasIndexTest, + HasTableTest as _HasTableTest, +) +from sqlalchemy.testing.suite.test_results import RowFetchTest as _RowFetchTest +from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 + BooleanTest as _BooleanTest, + DateTest as _DateTest, + _DateFixture as __DateFixture, + DateTimeHistoricTest, + DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, + DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, + DateTimeTest as _DateTimeTest, + IntegerTest as _IntegerTest, + JSONTest as _JSONTest, + _LiteralRoundTripFixture, + NumericTest as _NumericTest, + StringTest as _StringTest, + TextTest as _TextTest, + TimeTest as _TimeTest, + TimeMicrosecondsTest as _TimeMicrosecondsTest, + TimestampMicrosecondsTest, + UnicodeVarcharTest as _UnicodeVarcharTest, + UnicodeTextTest as _UnicodeTextTest, + _UnicodeFixture as __UnicodeFixture, +) +from test._helpers import get_db_url + +config.test_schema = "" + + +class BooleanTest(_BooleanTest): + @pytest.mark.skip( + "The original test case was split into 2 parts: " + "test_render_literal_bool_true and test_render_literal_bool_false" + ) + def test_render_literal_bool(self): + pass + + def test_render_literal_bool_true(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip(Boolean(), [True], [True]) + + def test_render_literal_bool_false(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip(Boolean(), [False], [False]) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_whereclause(self): + pass + + +class ComponentReflectionTestExtra(_ComponentReflectionTestExtra): + @testing.requires.table_reflection + def test_nullable_reflection(self, connection, metadata): + t = Table( + "t", + metadata, + Column("a", Integer, nullable=True), + Column("b", Integer, nullable=False), + ) + t.create(connection) + connection.connection.commit() + eq_( + dict( + (col["name"], col["nullable"]) + for col in inspect(connection).get_columns("t") + ), + {"a": True, "b": False}, + ) + + def _type_round_trip(self, connection, metadata, *types): + t = Table( + "t", metadata, *[Column("t%d" % i, type_) for i, type_ in enumerate(types)] + ) + t.create(connection) + connection.connection.commit() + + return [c["type"] for c in inspect(connection).get_columns("t")] + + @testing.requires.table_reflection + def test_numeric_reflection(self, connection, metadata): + """ + SPANNER OVERRIDE: + + Spanner defines NUMERIC type with the constant precision=38 + and scale=9. Overriding the test to check if the NUMERIC + column is successfully created and has dimensions + correct for Cloud Spanner. + """ + for typ in self._type_round_trip(connection, metadata, Numeric(18, 5)): + assert isinstance(typ, Numeric) + eq_(typ.precision, 38) + eq_(typ.scale, 9) + + @testing.requires.table_reflection + def test_binary_reflection(self, connection, metadata): + """ + Check that a BYTES column with an explicitly + set size is correctly reflected. + """ + for typ in self._type_round_trip(connection, metadata, LargeBinary(20)): + assert isinstance(typ, LargeBinary) + eq_(typ.length, 20) + + +class ComponentReflectionTest(_ComponentReflectionTest): + @classmethod + def define_tables(cls, metadata): + cls.define_reflected_tables(metadata, None) + + @classmethod + def define_reflected_tables(cls, metadata, schema): + if schema: + schema_prefix = schema + "." + else: + schema_prefix = "" + + if testing.requires.self_referential_foreign_keys.enabled: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + Column( + "parent_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey( + "%susers.user_id" % schema_prefix, name="user_id_fk" + ), + ), + schema=schema, + test_needs_fk=True, + ) + else: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + schema=schema, + test_needs_fk=True, + ) + + Table( + "dingalings", + metadata, + Column("dingaling_id", sqlalchemy.Integer, primary_key=True), + Column( + "address_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey("%semail_addresses.address_id" % schema_prefix), + ), + Column("data", sqlalchemy.String(30)), + schema=schema, + test_needs_fk=True, + ) + Table( + "email_addresses", + metadata, + Column("address_id", sqlalchemy.Integer, primary_key=True), + Column( + "remote_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey(users.c.user_id), + ), + Column("email_address", sqlalchemy.String(20)), + sqlalchemy.PrimaryKeyConstraint("address_id", name="email_ad_pk"), + schema=schema, + test_needs_fk=True, + ) + Table( + "comment_test", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True, comment="id comment"), + Column("data", sqlalchemy.String(20), comment="data % comment"), + Column( + "d2", + sqlalchemy.String(20), + comment=r"""Comment types type speedily ' " \ '' Fun!""", + ), + schema=schema, + comment=r"""the test % ' " \ table comment""", + ) + + if testing.requires.cross_schema_fk_reflection.enabled: + if schema is None: + Table( + "local_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + Column( + "remote_id", + ForeignKey("%s.remote_table_2.id" % testing.config.test_schema), + ), + test_needs_fk=True, + schema=config.db.dialect.default_schema_name, + ) + else: + Table( + "remote_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column( + "local_id", + ForeignKey( + "%s.local_table.id" % config.db.dialect.default_schema_name + ), + ), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + Table( + "remote_table_2", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + + if testing.requires.index_reflection.enabled: + cls.define_index(metadata, users) + + if not schema: + # test_needs_fk is at the moment to force MySQL InnoDB + noncol_idx_test_nopk = Table( + "noncol_idx_test_nopk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + extend_existing=True, + ) + + noncol_idx_test_pk = Table( + "noncol_idx_test_pk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + extend_existing=True, + ) + + if testing.requires.indexes_with_ascdesc.enabled: + sqlalchemy.Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) + sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) + + if testing.requires.view_column_reflection.enabled: + cls.define_views(metadata, schema) + + @testing.combinations((False,), argnames="use_schema") + @testing.requires.foreign_key_constraint_reflection + def test_get_foreign_keys(self, connection, use_schema): + if use_schema: + schema = config.test_schema + else: + schema = None + + users, addresses = (self.tables.users, self.tables.email_addresses) + insp = inspect(connection) + expected_schema = schema + # users + + if testing.requires.self_referential_foreign_keys.enabled: + users_fkeys = insp.get_foreign_keys(users.name, schema=schema) + fkey1 = users_fkeys[0] + + with testing.requires.named_constraints.fail_if(): + eq_(fkey1["name"], "user_id_fk") + + eq_(fkey1["referred_schema"], expected_schema) + eq_(fkey1["referred_table"], users.name) + eq_(fkey1["referred_columns"], ["user_id"]) + if testing.requires.self_referential_foreign_keys.enabled: + eq_(fkey1["constrained_columns"], ["parent_user_id"]) + + # addresses + addr_fkeys = insp.get_foreign_keys(addresses.name, schema=schema) + fkey1 = addr_fkeys[0] + + with testing.requires.implicitly_named_constraints.fail_if(): + self.assert_(fkey1["name"] is not None) + + eq_(fkey1["referred_schema"], expected_schema) + eq_(fkey1["referred_table"], users.name) + eq_(fkey1["referred_columns"], ["user_id"]) + eq_(fkey1["constrained_columns"], ["remote_user_id"]) + + @testing.requires.foreign_key_constraint_reflection + @testing.combinations( + (None, True, False, False), + (None, True, False, True, testing.requires.schemas), + ("foreign_key", True, False, False), + (None, False, False, False), + (None, False, False, True, testing.requires.schemas), + (None, True, False, False), + (None, True, False, True, testing.requires.schemas), + argnames="order_by,include_plain,include_views,use_schema", + ) + def test_get_table_names( + self, connection, order_by, include_plain, include_views, use_schema + ): + + if use_schema: + schema = config.test_schema + else: + schema = None + + _ignore_tables = [ + "account", + "alembic_version", + "bytes_table", + "comment_test", + "date_table", + "noncol_idx_test_pk", + "noncol_idx_test_nopk", + "local_table", + "remote_table", + "remote_table_2", + "text_table", + "user_tmp", + ] + + insp = inspect(connection) + + if include_views: + table_names = insp.get_view_names(schema) + table_names.sort() + answer = ["email_addresses_v", "users_v"] + eq_(sorted(table_names), answer) + + if include_plain: + if order_by: + tables = [ + rec[0] + for rec in insp.get_sorted_table_and_fkc_names(schema) + if rec[0] + ] + else: + tables = insp.get_table_names(schema) + table_names = [t for t in tables if t not in _ignore_tables] + + if order_by == "foreign_key": + answer = ["users", "email_addresses", "dingalings"] + eq_(table_names, answer) + else: + answer = ["dingalings", "email_addresses", "users"] + eq_(sorted(table_names), answer) + + @classmethod + def define_temp_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + In Cloud Spanner unique indexes are used instead of directly + creating unique constraints. Overriding the test to replace + constraints with indexes in testing data. + """ + kw = temp_table_keyword_args(config, config.db) + user_tmp = Table( + "user_tmp", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + Column("foo", sqlalchemy.INT), + sqlalchemy.Index("user_tmp_uq", "name", unique=True), + sqlalchemy.Index("user_tmp_ix", "foo"), + extend_existing=True, + **kw, + ) + if ( + testing.requires.view_reflection.enabled + and testing.requires.temporary_views.enabled + ): + event.listen( + user_tmp, + "after_create", + DDL("create temporary view user_tmp_v as " "select * from user_tmp"), + ) + event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v")) + + @testing.provide_metadata + def test_reflect_string_column_max_len(self): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the STRING type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + metadata = MetaData(self.bind) + Table("text_table", metadata, Column("TestColumn", Text, nullable=False)) + metadata.create_all() + + Table("text_table", metadata, autoload=True) + + def test_reflect_bytes_column_max_len(self): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the BYTES type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + metadata = MetaData(self.bind) + Table( + "bytes_table", metadata, Column("TestColumn", LargeBinary, nullable=False), + ) + metadata.create_all() + + Table("bytes_table", metadata, autoload=True) + + @testing.combinations( + (True, testing.requires.schemas), (False,), argnames="use_schema" + ) + @testing.requires.unique_constraint_reflection + def test_get_unique_constraints(self, metadata, connection, use_schema): + # SQLite dialect needs to parse the names of the constraints + # separately from what it gets from PRAGMA index_list(), and + # then matches them up. so same set of column_names in two + # constraints will confuse it. Perhaps we should no longer + # bother with index_list() here since we have the whole + # CREATE TABLE? + + if use_schema: + schema = config.test_schema + else: + schema = None + uniques = sorted( + [ + {"name": "unique_a", "column_names": ["a"]}, + {"name": "unique_a_b_c", "column_names": ["a", "b", "c"]}, + {"name": "unique_c_a_b", "column_names": ["c", "a", "b"]}, + {"name": "unique_asc_key", "column_names": ["asc", "key"]}, + {"name": "i.have.dots", "column_names": ["b"]}, + {"name": "i have spaces", "column_names": ["c"]}, + ], + key=operator.itemgetter("name"), + ) + table = Table( + "testtbl", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("a", String(20)), + Column("b", String(30)), + Column("c", Integer), + # reserved identifiers + Column("asc", String(30)), + Column("key", String(30)), + sqlalchemy.Index("unique_a", "a", unique=True), + sqlalchemy.Index("unique_a_b_c", "a", "b", "c", unique=True), + sqlalchemy.Index("unique_c_a_b", "c", "a", "b", unique=True), + sqlalchemy.Index("unique_asc_key", "asc", "key", unique=True), + schema=schema, + ) + table.create(connection) + connection.connection.commit() + + inspector = inspect(connection) + reflected = sorted( + inspector.get_unique_constraints("testtbl", schema=schema), + key=operator.itemgetter("name"), + ) + + names_that_duplicate_index = set() + + for orig, refl in zip(uniques, reflected): + # Different dialects handle duplicate index and constraints + # differently, so ignore this flag + dupe = refl.pop("duplicates_index", None) + if dupe: + names_that_duplicate_index.add(dupe) + eq_(orig, refl) + + reflected_metadata = MetaData() + reflected = Table( + "testtbl", reflected_metadata, autoload_with=connection, schema=schema, + ) + + # test "deduplicates for index" logic. MySQL and Oracle + # "unique constraints" are actually unique indexes (with possible + # exception of a unique that is a dupe of another one in the case + # of Oracle). make sure # they aren't duplicated. + idx_names = set([idx.name for idx in reflected.indexes]) + uq_names = set( + [ + uq.name + for uq in reflected.constraints + if isinstance(uq, sqlalchemy.UniqueConstraint) + ] + ).difference(["unique_c_a_b"]) + + assert not idx_names.intersection(uq_names) + if names_that_duplicate_index: + eq_(names_that_duplicate_index, idx_names) + eq_(uq_names, set()) + + @testing.provide_metadata + def test_unique_constraint_raises(self): + """ + Checking that unique constraint creation + fails due to a ProgrammingError. + """ + metadata = MetaData(self.bind) + Table( + "user_tmp_failure", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + sqlalchemy.UniqueConstraint("name", name="user_tmp_uq"), + ) + + with pytest.raises(spanner_dbapi.exceptions.ProgrammingError): + metadata.create_all() + + @testing.provide_metadata + def _test_get_table_names(self, schema=None, table_type="table", order_by=None): + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + _ignore_tables = [ + "comment_test", + "noncol_idx_test_pk", + "noncol_idx_test_nopk", + "local_table", + "remote_table", + "remote_table_2", + ] + meta = self.metadata + + insp = inspect(meta.bind) + + if table_type == "view": + table_names = insp.get_view_names(schema) + table_names.sort() + answer = ["email_addresses_v", "users_v"] + eq_(sorted(table_names), answer) + else: + if order_by: + tables = [ + rec[0] + for rec in insp.get_sorted_table_and_fkc_names(schema) + if rec[0] + ] + else: + tables = insp.get_table_names(schema) + table_names = [t for t in tables if t not in _ignore_tables] + + if order_by == "foreign_key": + answer = {"dingalings", "email_addresses", "user_tmp", "users"} + eq_(set(table_names), answer) + else: + answer = ["dingalings", "email_addresses", "user_tmp", "users"] + eq_(sorted(table_names), answer) + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_indexes(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_unique_constraints(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_columns(self): + pass + + +class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): + @testing.requires.foreign_key_constraint_reflection + def test_fk_column_order(self): + """ + SPANNER OVERRIDE: + + Spanner column usage reflection doesn't support determenistic + ordering. Overriding the test to check that columns are + reflected correctly, without considering their order. + """ + # test for issue #5661 + insp = inspect(self.bind) + foreign_keys = insp.get_foreign_keys(self.tables.tb2.name) + eq_(len(foreign_keys), 1) + fkey1 = foreign_keys[0] + eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) + eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) + + +@pytest.mark.skip("Spanner doesn't support quotes in table names.") +class QuotedNameArgumentTest(_QuotedNameArgumentTest): + pass + + +class _DateFixture(__DateFixture): + compare = None + + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + + class Decorated(sqlalchemy.TypeDecorator): + impl = cls.datatype + cache_ok = True + + Table( + "date_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("date_data", cls.datatype), + Column("decorated_date_data", Decorated), + ) + + +class DateTest(_DateTest): + """ + SPANNER OVERRIDE: + + DateTest tests used same class method to create table, so to avoid those failures + and maintain DRY concept just inherit the class to run tests successfully. + """ + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + +class CTETest(_CTETest): + @classmethod + def define_tables(cls, metadata): + """ + The original method creates a foreign key without a name, + which causes troubles on test cleanup. Overriding the + method to explicitly set a foreign key name. + """ + Table( + "some_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", ForeignKey("some_table.id", name="fk_some_table")), + ) + + Table( + "some_other_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", Integer), + ) + + @pytest.mark.skip("INSERT from WITH subquery is not supported") + def test_insert_from_select_round_trip(self): + """ + The test checks if an INSERT can be done from a cte, like: + + WITH some_cte AS (...) + INSERT INTO some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_scalar_subq_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_from_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("UPDATE from WITH subquery is not supported") + def test_update_from_round_trip(self): + """ + The test checks if an UPDATE can be done from a cte, like: + + WITH some_cte AS (...) + UPDATE some_other_table + SET (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("WITH RECURSIVE subqueries are not supported") + def test_select_recursive_round_trip(self): + pass + + +class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest, DateTest): + @pytest.mark.skip("Spanner dates are time zone independent") + def test_select_direct(self): + pass + + def test_round_trip(self): + """ + SPANNER OVERRIDE: + + Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid + assert failures convert datetime input to the desire timestamp format. + """ + date_table = self.tables.date_table + config.db.execute(date_table.insert(), {"date_data": self.data, "id": 250}) + + row = config.db.execute(select([date_table.c.date_data])).first() + compare = self.compare or self.data + compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + eq_(row[0].rfc3339(), compare) + assert isinstance(row[0], DatetimeWithNanoseconds) + + def test_round_trip_decorated(self, connection): + """ + SPANNER OVERRIDE: + + Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid + assert failures convert datetime input to the desire timestamp format. + """ + date_table = self.tables.date_table + + connection.execute( + date_table.insert(), {"id": 1, "decorated_date_data": self.data} + ) + + row = connection.execute(select(date_table.c.decorated_date_data)).first() + + compare = self.compare or self.data + compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + eq_(row[0].rfc3339(), compare) + assert isinstance(row[0], DatetimeWithNanoseconds) + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + +class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): + """ + SPANNER OVERRIDE: + + DateTimeTest tests have the same failures same as DateTimeMicrosecondsTest tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + @pytest.mark.skip("Spanner dates are time zone independent") + def test_select_direct(self): + pass + + +@pytest.mark.skip("Not supported by Spanner") +class DifficultParametersTest(_DifficultParametersTest): + pass + + +class FetchLimitOffsetTest(_FetchLimitOffsetTest): + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit_simple_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_simple_limit_expr_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_bound_offset(self, connection): + pass + + def test_limit_render_multiple_times(self, connection): + table = self.tables.some_table + stmt = select(table.c.id).limit(1).scalar_subquery() + + u = union(select(stmt), select(stmt)).subquery().select() + + self._assert_result( + connection, u, [(2,)], + ) + + +@pytest.mark.skip("Spanner doesn't support autoincrement") +class IdentityAutoincrementTest(_IdentityAutoincrementTest): + pass + + +class EscapingTest(_EscapingTest): + @provide_metadata + def test_percent_sign_round_trip(self): + """Test that the DBAPI accommodates for escaped / nonescaped + percent signs in a way that matches the compiler + + SPANNER OVERRIDE + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + m = self.metadata + t = Table("t", m, Column("data", String(50))) + t.create(config.db) + with config.db.begin() as conn: + conn.execute(t.insert(), dict(data="some % value")) + + eq_( + conn.scalar( + select([t.c.data]).where( + t.c.data == literal_column("'some % value'") + ) + ), + "some % value", + ) + + conn.execute(t.delete()) + conn.execute(t.insert(), dict(data="some %% other value")) + eq_( + conn.scalar( + select([t.c.data]).where( + t.c.data == literal_column("'some %% other value'") + ) + ), + "some %% other value", + ) + + +class ExistsTest(_ExistsTest): + def test_select_exists(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select((exists().where(stuff.c.data == "some data"),)) + ).fetchall(), + [(True,)], + ) + + def test_select_exists_false(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select((exists().where(stuff.c.data == "no data"),)) + ).fetchall(), + [(False,)], + ) + + +class TableDDLTest(_TableDDLTest): + @pytest.mark.skip( + "Spanner table name must start with an uppercase or lowercase letter" + ) + def test_underscore_names(self): + pass + + @pytest.mark.skip("Table names incuding schemas are not supported by Spanner") + def test_create_table_schema(self): + pass + + +class FutureTableDDLTest(_FutureTableDDLTest): + @pytest.mark.skip("Table names incuding schemas are not supported by Spanner") + def test_create_table_schema(self): + pass + + @pytest.mark.skip( + "Spanner table name must start with an uppercase or lowercase letter" + ) + def test_underscore_names(self): + pass + + +@pytest.mark.skip("Max identifier length in Spanner is 128") +class LongNameBlowoutTest(_LongNameBlowoutTest): + pass + + +@pytest.mark.skip("Spanner doesn't support Time data type.") +class TimeTests(_TimeMicrosecondsTest, _TimeTest): + pass + + +@pytest.mark.skip("Spanner doesn't coerce dates from datetime.") +class DateTimeCoercedToDateTimeTest(_DateTimeCoercedToDateTimeTest): + pass + + +class IntegerTest(_IntegerTest): + @provide_metadata + def _round_trip(self, datatype, data): + """ + SPANNER OVERRIDE: + + This is the helper method for integer class tests which creates a table and + performs an insert operation. + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + metadata = self.metadata + int_table = Table( + "integer_table", + metadata, + Column("id", Integer, primary_key=True, test_needs_autoincrement=True), + Column("integer_data", datatype), + ) + + metadata.create_all(config.db) + + config.db.execute(int_table.insert(), {"id": 1, "integer_data": data}) + + row = config.db.execute(select([int_table.c.integer_data])).first() + + eq_(row, (data,)) + + if util.py3k: + assert isinstance(row[0], int) + else: + assert isinstance(row[0], (long, int)) # noqa + + +class _UnicodeFixture(__UnicodeFixture): + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + Table( + "unicode_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("unicode_data", cls.datatype), + ) + + def test_round_trip_executemany(self): + """ + SPANNER OVERRIDE + + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + unicode_table = self.tables.unicode_table + + config.db.execute( + unicode_table.insert(), + [{"id": i, "unicode_data": self.data} for i in range(3)], + ) + + rows = config.db.execute(select([unicode_table.c.unicode_data])).fetchall() + eq_(rows, [(self.data,) for i in range(3)]) + for row in rows: + assert isinstance(row[0], util.text_type) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal(self): + pass + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + +class UnicodeVarcharTest(_UnicodeFixture, _UnicodeVarcharTest): + """ + SPANNER OVERRIDE: + + UnicodeVarcharTest class inherits the __UnicodeFixture class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +class UnicodeTextTest(_UnicodeFixture, _UnicodeTextTest): + """ + SPANNER OVERRIDE: + + UnicodeTextTest class inherits the __UnicodeFixture class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +class RowFetchTest(_RowFetchTest): + def test_row_w_scalar_select(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner returns a DatetimeWithNanoseconds() for date + data types. Overriding the test to use a DatetimeWithNanoseconds + type value as an expected result. + -------------- + + test that a scalar select as a column is returned as such + and that type conversion works OK. + + (this is half a SQLAlchemy Core test and half to catch database + backends that may have unusual behavior with scalar selects.) + """ + datetable = self.tables.has_dates + s = select([datetable.alias("x").c.today]).scalar_subquery() + s2 = select([datetable.c.id, s.label("somelabel")]) + row = config.db.execute(s2).first() + + eq_( + row["somelabel"], + DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=timezone.utc), + ) + + +class InsertBehaviorTest(_InsertBehaviorTest): + @pytest.mark.skip("Spanner doesn't support empty inserts") + def test_empty_insert(self): + pass + + @pytest.mark.skip("Spanner doesn't support empty inserts") + def test_empty_insert_multiple(self): + pass + + @pytest.mark.skip("Spanner doesn't support auto increment") + def test_insert_from_select_autoinc(self): + pass + + @pytest.mark.skip("Spanner doesn't support default column values") + def test_insert_from_select_with_defaults(self): + pass + + def test_autoclose_on_insert(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support tables with an auto increment primary key, + following insertions will fail with `400 id must not be NULL in table + autoinc_pk`. + + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + if config.requirements.returning.enabled: + engine = engines.testing_engine(options={"implicit_returning": False}) + else: + engine = config.db + + with engine.begin() as conn: + r = conn.execute( + self.tables.autoinc_pk.insert(), dict(id=1, data="some data") + ) + + assert r._soft_closed + assert not r.closed + assert r.is_insert + assert not r.returns_rows + + +class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): + __backend__ = True + + def test_nolength_binary(self): + metadata = MetaData() + foo = Table("foo", metadata, Column("one", LargeBinary)) + + foo.create(config.db) + foo.drop(config.db) + + +class StringTest(_StringTest): + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + +class TextTest(_TextTest): + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + Table( + "text_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("text_data", Text), + ) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_roundtrip(self, connection): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_empty_strings(self, connection): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_null_strings(self, connection): + pass + + +class NumericTest(_NumericTest): + @testing.fixture + def do_numeric_test(self, metadata, connection): + @testing.emits_warning(r".*does \*not\* support Decimal objects natively") + def run(type_, input_, output, filter_=None, check_scale=False): + t = Table( + "t", + metadata, + Column("x", type_), + Column("id", Integer, primary_key=True), + ) + t.create(connection) + connection.connection.commit() + connection.execute( + t.insert(), [{"x": x, "id": i} for i, x in enumerate(input_)] + ) + + result = {row[0] for row in connection.execute(t.select())} + output = set(output) + if filter_: + result = set(filter_(x) for x in result) + output = set(filter_(x) for x in output) + eq_(result, output) + if check_scale: + eq_([str(x) for x in result], [str(x) for x in output]) + + return run + + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric_asfloat(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563")], + [15.7563], + ) + + def test_render_literal_float(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Float(4), + [decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_generic_float_type + def test_float_custom_scale(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(None, decimal_return_scale=7, asdecimal=True), + [decimal.Decimal("15.7563827"), decimal.Decimal("15.7563827")], + [decimal.Decimal("15.7563827")], + check_scale=True, + ) + + def test_numeric_as_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + do_numeric_test( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + def test_numeric_as_float(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + do_numeric_test( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [15.7563], + ) + + @requires.floats_to_four_decimals + def test_float_as_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(precision=8, asdecimal=True), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563"), None], + [decimal.Decimal("15.7563"), None], + filter_=lambda n: n is not None and round(n, 4) or None, + ) + + def test_float_as_float(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(precision=8), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_numerics_general + def test_precision_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + + Remove an extra digits after decimal point as cloud spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + numbers = set( + [ + decimal.Decimal("54.246451650"), + decimal.Decimal("0.004354"), + decimal.Decimal("900.0"), + ] + ) + do_numeric_test(Numeric(precision=18, scale=9), numbers, numbers) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal_large(self, do_numeric_test): + """test exceedingly large decimals. + + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + numbers = set( + [ + decimal.Decimal("4E+8"), + decimal.Decimal("5748E+15"), + decimal.Decimal("1.521E+15"), + decimal.Decimal("000000000.1E+9"), + ] + ) + do_numeric_test(Numeric(precision=25, scale=2), numbers, numbers) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal(self, do_numeric_test): + """test exceedingly small decimals. + + Decimal reports values with E notation when the exponent + is greater than 6. + + SPANNER OVERRIDE: + + Remove extra digits after decimal point as Cloud Spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + numbers = set( + [ + decimal.Decimal("1E-2"), + decimal.Decimal("1E-3"), + decimal.Decimal("1E-4"), + decimal.Decimal("1E-5"), + decimal.Decimal("1E-6"), + decimal.Decimal("1E-7"), + decimal.Decimal("1E-8"), + decimal.Decimal("0.105940696"), + decimal.Decimal("0.005940696"), + decimal.Decimal("0.000000696"), + decimal.Decimal("0.700000696"), + decimal.Decimal("696E-9"), + ] + ) + do_numeric_test(Numeric(precision=38, scale=9), numbers, numbers) + + +class LikeFunctionsTest(_LikeFunctionsTest): + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_autoescape_escape(self): + pass + + def test_escape_keyword_raises(self): + """Check that ESCAPE keyword causes an exception when used.""" + with pytest.raises(NotImplementedError): + col = self.tables.some_table.c.data + self._test(col.contains("b##cde", escape="#"), {7}) + + +@pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") +class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): + pass + + +class OrderByLabelTest(_OrderByLabelTest): + @pytest.mark.skip( + "Spanner requires an alias for the GROUP BY list when specifying derived " + "columns also used in SELECT" + ) + def test_group_by_composed(self): + pass + + +class CompoundSelectTest(_CompoundSelectTest): + """ + See: https://github.com/googleapis/python-spanner/issues/347 + """ + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_limit_offset_selectable_in_unions(self): + pass + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_order_by_selectable_in_unions(self): + pass + + +class TestQueryHints(fixtures.TablesTest): + """ + Compile a complex query with JOIN and check that + the table hint was set into the right place. + """ + + __backend__ = True + + def test_complex_query_table_hints(self): + EXPECTED_QUERY = ( + "SELECT users.id, users.name \nFROM users @{FORCE_INDEX=table_1_by_int_idx}" + " JOIN addresses ON users.id = addresses.user_id " + "\nWHERE users.name IN (__[POSTCOMPILE_name_1])" + ) + + Base = declarative_base() + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + + class User(Base): + __tablename__ = "users" + id = Column(Integer, primary_key=True) + name = Column(String(50)) + addresses = relation("Address", backref="user") + + class Address(Base): + __tablename__ = "addresses" + id = Column(Integer, primary_key=True) + email = Column(String(50)) + user_id = Column(Integer, ForeignKey("users.id")) + + session = Session(engine) + + query = session.query(User) + query = query.with_hint( + selectable=User, text="@{FORCE_INDEX=table_1_by_int_idx}" + ) + + query = query.filter(User.name.in_(["val1", "val2"])) + query = query.join(Address) + + assert str(query.statement.compile(session.bind)) == EXPECTED_QUERY + + +class InterleavedTablesTest(fixtures.TestBase): + """ + Check that CREATE TABLE statements for interleaved tables are correctly + generated. + """ + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData(bind=self._engine) + + def test_interleave(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) + + def test_interleave_on_delete_cascade(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team ON DELETE CASCADE\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + spanner_interleave_on_delete_cascade=True, + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) + + +class UserAgentTest(fixtures.TestBase): + """Check that SQLAlchemy dialect uses correct user agent.""" + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData(bind=self._engine) + + def test_user_agent(self): + dist = pkg_resources.get_distribution("sqlalchemy-spanner") + + with self._engine.connect() as connection: + assert ( + connection.connection.instance._client._client_info.user_agent + == "gl-" + dist.project_name + "/" + dist.version + ) + + +class SimpleUpdateDeleteTest(_SimpleUpdateDeleteTest): + """ + SPANNER OVERRIDE: + + Spanner doesn't support `rowcount` property. These + test cases overrides omit `rowcount` checks. + """ + + def test_delete(self, connection): + t = self.tables.plain_pk + r = connection.execute(t.delete().where(t.c.id == 2)) + assert not r.is_insert + assert not r.returns_rows + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (3, "d3")], + ) + + def test_update(self, connection): + t = self.tables.plain_pk + r = connection.execute(t.update().where(t.c.id == 2), dict(data="d2_new")) + assert not r.is_insert + assert not r.returns_rows + + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (2, "d2_new"), (3, "d3")], + ) + + +class HasIndexTest(_HasIndexTest): + @classmethod + def define_tables(cls, metadata): + tt = Table( + "test_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + ) + sqlalchemy.Index("my_idx", tt.c.data) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_index_schema(self): + pass + + +class HasTableTest(_HasTableTest): + @classmethod + def define_tables(cls, metadata): + Table( + "test_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + ) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_table_schema(self): + pass + + +class PostCompileParamsTest(_PostCompileParamsTest): + def test_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + table.c.x == sqlalchemy.bindparam("q", literal_execute=True) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=10)) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " "\nWHERE some_table.x = 10", + [] if config.db.dialect.positional else {}, + ) + ) + + def test_execute_expanding_plus_literal_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + table.c.x.in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[5, 6, 7])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE some_table.x IN (5, 6, 7)", + [] if config.db.dialect.positional else {}, + ) + ) + + @testing.requires.tuple_in + def test_execute_tuple_expanding_plus_literal_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + sqlalchemy.tuple_(table.c.x, table.c.y).in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[(5, 10), (12, 18)])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE (some_table.x, some_table.y) " + "IN (%s(5, 10), (12, 18))" + % ("VALUES " if config.db.dialect.tuple_in_values else ""), + () if config.db.dialect.positional else {}, + ) + ) + + @testing.requires.tuple_in + def test_execute_tuple_expanding_plus_literal_heterogeneous_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + sqlalchemy.tuple_(table.c.x, table.c.z).in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[(5, "z1"), (12, "z3")])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE (some_table.x, some_table.z) " + "IN (%s(5, 'z1'), (12, 'z3'))" + % ("VALUES " if config.db.dialect.tuple_in_values else ""), + () if config.db.dialect.positional else {}, + ) + ) + + +class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): + @classmethod + def define_tables(cls, metadata): + """SPANNER OVERRIDE: + + Avoid using default values for computed columns. + """ + Table( + "computed_default_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_col", Integer, Computed("normal + 42")), + Column("with_default", Integer), + ) + + t = Table( + "computed_column_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_no_flag", Integer, Computed("normal + 42")), + ) + + if testing.requires.computed_columns_virtual.enabled: + t.append_column( + Column( + "computed_virtual", + Integer, + Computed("normal + 2", persisted=False), + ) + ) + if testing.requires.computed_columns_stored.enabled: + t.append_column( + Column( + "computed_stored", Integer, Computed("normal - 42", persisted=True), + ) + ) + + +class ComputedReflectionTest(_ComputedReflectionTest, ComputedReflectionFixtureTest): + @testing.requires.schemas + def test_get_column_returns_persisted_with_schema(self): + insp = inspect(config.db) + + cols = insp.get_columns("computed_column_table", schema=config.test_schema) + data = {c["name"]: c for c in cols} + + self.check_column( + data, + "computed_no_flag", + "normal+42", + testing.requires.computed_columns_default_persisted.enabled, + ) + if testing.requires.computed_columns_virtual.enabled: + self.check_column( + data, "computed_virtual", "normal/2", False, + ) + if testing.requires.computed_columns_stored.enabled: + self.check_column( + data, "computed_stored", "normal-42", True, + ) + + @pytest.mark.skip("Default values are not supported.") + def test_computed_col_default_not_set(self): + pass + + def test_get_column_returns_computed(self): + """ + SPANNER OVERRIDE: + + In Spanner all the generated columns are STORED, + meaning there are no persisted and not persisted + (in the terms of the SQLAlchemy) columns. The + method override omits the persistence reflection checks. + """ + insp = inspect(config.db) + + cols = insp.get_columns("computed_default_table") + data = {c["name"]: c for c in cols} + for key in ("id", "normal", "with_default"): + is_true("computed" not in data[key]) + compData = data["computed_col"] + is_true("computed" in compData) + is_true("sqltext" in compData["computed"]) + eq_(self.normalize(compData["computed"]["sqltext"]), "normal+42") + + def test_create_not_null_computed_column(self): + """ + SPANNER TEST: + + Check that on creating a computed column with a NOT NULL + clause the clause is set in front of the computed column + statement definition and doesn't cause failures. + """ + engine = create_engine(get_db_url()) + metadata = MetaData(bind=engine) + + Table( + "Singers", + metadata, + Column("SingerId", String(36), primary_key=True, nullable=False), + Column("FirstName", String(200)), + Column("LastName", String(200), nullable=False), + Column( + "FullName", + String(400), + Computed("COALESCE(FirstName || ' ', '') || LastName"), + nullable=False, + ), + ) + + metadata.create_all(engine) + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class JSONTest(_JSONTest): + @pytest.mark.skip("Values without keys are not supported.") + def test_single_element_round_trip(self, element): + pass + + def _test_round_trip(self, data_element): + data_table = self.tables.data_table + + config.db.execute( + data_table.insert(), + {"id": random.randint(1, 100000000), "name": "row1", "data": data_element}, + ) + + row = config.db.execute(select([data_table.c.data])).first() + + eq_(row, (data_element,)) + + def test_unicode_round_trip(self): + # note we include Unicode supplementary characters as well + with config.db.connect() as conn: + conn.execute( + self.tables.data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "r1", + "data": { + util.u("rΓ©ve🐍 illΓ©"): util.u("rΓ©ve🐍 illΓ©"), + "data": {"k1": util.u("drΓ΄l🐍e")}, + }, + }, + ) + + eq_( + conn.scalar(select([self.tables.data_table.c.data])), + { + util.u("rΓ©ve🐍 illΓ©"): util.u("rΓ©ve🐍 illΓ©"), + "data": {"k1": util.u("drΓ΄l🐍e")}, + }, + ) + + @pytest.mark.skip("Parameterized types are not supported.") + def test_eval_none_flag_orm(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_index_typed_comparison(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_path_typed_comparison(self): + pass + + @pytest.mark.skip("Custom JSON de-/serializers are not supported.") + def test_round_trip_custom_json(self): + pass + + def _index_fixtures(fn): + fn = testing.combinations( + ("boolean", True), + ("boolean", False), + ("boolean", None), + ("string", "some string"), + ("string", None), + ("integer", 15), + ("integer", 1), + ("integer", 0), + ("integer", None), + ("float", 28.5), + ("float", None), + id_="sa", + )(fn) + return fn + + @_index_fixtures + def test_index_typed_access(self, datatype, value): + data_table = self.tables.data_table + data_element = {"key1": value} + with config.db.connect() as conn: + conn.execute( + data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "row1", + "data": data_element, + "nulldata": data_element, + }, + ) + + expr = data_table.c.data["key1"] + expr = getattr(expr, "as_%s" % datatype)() + + roundtrip = conn.scalar(select([expr])) + if roundtrip in ("true", "false", None): + roundtrip = str(roundtrip).capitalize() + + eq_(str(roundtrip), str(value)) + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_json_null_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_sql_null(self): + pass diff --git a/packages/sqlalchemy-spanner/test_migration_env.py b/packages/sqlalchemy-spanner/test_migration_env.py index a87e356b7654..d2ec9507d06d 100644 --- a/packages/sqlalchemy-spanner/test_migration_env.py +++ b/packages/sqlalchemy-spanner/test_migration_env.py @@ -41,7 +41,7 @@ class SpannerImpl(DefaultImpl): - __dialect__ = "spanner" + __dialect__ = "spanner+spanner" def run_migrations_offline(): From 045099eabfe5054e2b666175b3190d61676bc49b Mon Sep 17 00:00:00 2001 From: Vikash Singh <3116482+vi3k6i5@users.noreply.github.com> Date: Thu, 27 Jan 2022 15:04:39 +0530 Subject: [PATCH 141/582] fix: delete stale instance with delay of 5 seconds (#194) --- packages/sqlalchemy-spanner/create_test_database.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 91be45f8d7bc..0e5a4bf24cac 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -27,7 +27,8 @@ USE_EMULATOR = os.getenv("SPANNER_EMULATOR_HOST") is not None PROJECT = os.getenv( - "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + "GOOGLE_CLOUD_PROJECT", + os.getenv("PROJECT_ID", "emulator-test-project"), ) CLIENT = None @@ -56,6 +57,7 @@ def delete_stale_test_instances(): # therefore instance can just be deleted. try: instance.delete() + time.sleep(5) # Sleep for 5 seconds to give time for cooldown. except ResourceExhausted: print( "Unable to drop stale instance '{}'. May need manual delete.".format( From 1ab036cb92aae5f87f8a1cdcc7b6e31757995895 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 28 Jan 2022 10:47:38 +0000 Subject: [PATCH 142/582] feat: drop read_only on a connection returned back to a pool (#189) * feat: drop read_only on a connection returned back to a pool --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 3 + .../sqlalchemy-spanner/test/test_suite_13.py | 68 +++++++++++++------ 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 184e5b476174..3e3afa4ed29a 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -51,6 +51,9 @@ def reset_connection(dbapi_conn, connection_record): if getattr(dbapi_conn.connection, "staleness", None) is not None: dbapi_conn.connection.staleness = None + if getattr(dbapi_conn.connection, "read_only", None) is not None: + dbapi_conn.connection.read_only = False + # register a method to get a single value of a JSON object OPERATORS[json_getitem_op] = operator_lookup["json_getitem_op"] diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 735c0be8ea5e..b53045ac3a82 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -21,7 +21,7 @@ import pkg_resources import pytest import random -import unittest +import time from unittest import mock import sqlalchemy @@ -1579,45 +1579,32 @@ def test_user_agent(self): ) -class ExecutionOptionsTest(fixtures.TestBase, unittest.TestCase): +class ExecutionOptionsReadOnlyTest(fixtures.TestBase): """ Check that `execution_options()` method correctly sets parameters on the underlying DB API connection. """ - @classmethod - def setUpClass(cls): - cls._engine = create_engine(get_db_url(), pool_size=1) - cls._metadata = MetaData(bind=cls._engine) + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + metadata = MetaData(bind=self._engine) - cls._table = Table( + self._table = Table( "execution_options", - cls._metadata, + metadata, Column("opt_id", Integer, primary_key=True), Column("opt_name", String(16), nullable=False), ) - cls._metadata.create_all(cls._engine) + metadata.create_all(self._engine) def test_read_only(self): with self._engine.connect().execution_options(read_only=True) as connection: connection.execute(select(["*"], from_obj=self._table)).fetchall() assert connection.connection.read_only is True - def test_staleness(self): - with self._engine.connect().execution_options( - read_only=True, staleness={"exact_staleness": datetime.timedelta(seconds=5)} - ) as connection: - connection.execute(select(["*"], from_obj=self._table)).fetchall() - assert connection.connection.staleness == { - "exact_staleness": datetime.timedelta(seconds=5) - } - - with self._engine.connect() as connection: - assert connection.connection.staleness is None - with self._engine.connect() as connection: - del connection.staleness + assert connection.connection.read_only is False class LimitOffsetTest(fixtures.TestBase): @@ -1645,6 +1632,43 @@ def test_offset_only(self): list(connection.execute(self._table.select().offset(offset)).fetchall()) +class ExecutionOptionsStalenessTest(fixtures.TestBase): + """ + Check that `execution_options()` method correctly + sets parameters on the underlying DB API connection. + """ + + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + metadata = MetaData(bind=self._engine) + + self._table = Table( + "execution_options", + metadata, + Column("opt_id", Integer, primary_key=True), + Column("opt_name", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + time.sleep(1) + + def test_staleness(self): + with self._engine.connect().execution_options( + read_only=True, staleness={"exact_staleness": datetime.timedelta(seconds=1)} + ) as connection: + connection.execute(select(["*"], from_obj=self._table)).fetchall() + assert connection.connection.staleness == { + "exact_staleness": datetime.timedelta(seconds=1) + } + + with self._engine.connect() as connection: + assert connection.connection.staleness == {} + + engine = create_engine("sqlite:///database") + with engine.connect() as connection: + pass + + class TemporaryTableTest(fixtures.TestBase): """ Check that temporary tables raise an error on creation. From 0198001e3863610369e42af749f2d5fdeb5410d0 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 28 Jan 2022 11:31:21 +0000 Subject: [PATCH 143/582] feat: rollback a connection returned back to pool (#193) * feat: drop read_only on a connection returned back to a pool * feat: rollback a connection returned back to pool Co-authored-by: Vikash Singh <3116482+vi3k6i5@users.noreply.github.com> --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 3e3afa4ed29a..9a1209b23a83 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -48,6 +48,7 @@ @listens_for(Pool, "reset") def reset_connection(dbapi_conn, connection_record): """An event of returning a connection back to a pool.""" + dbapi_conn.connection.rollback() if getattr(dbapi_conn.connection, "staleness", None) is not None: dbapi_conn.connection.staleness = None From 4fb0268e65be2fb662845da8c39b0df03ff82d60 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 28 Jan 2022 20:54:16 +0530 Subject: [PATCH 144/582] chore(main): release 1.1.0 (#197) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 23 +++++++++++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index d431e1bae20d..f0a42c9b2af0 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [1.1.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.0.0...v1.1.0) (2022-01-28) + + +### Features + +* drop read_only on a connection returned back to a pool ([#189](https://github.com/googleapis/python-spanner-sqlalchemy/issues/189)) ([16388c1](https://github.com/googleapis/python-spanner-sqlalchemy/commit/16388c1c9ba7798c0c0df786f2e4a8c86b7767c2)) +* rollback a connection returned back to pool ([#193](https://github.com/googleapis/python-spanner-sqlalchemy/issues/193)) ([13ff9cb](https://github.com/googleapis/python-spanner-sqlalchemy/commit/13ff9cb73049d989bacb97fd8be3ad3bdce7023c)) +* support SQLAlchemy 1.4 ([#191](https://github.com/googleapis/python-spanner-sqlalchemy/issues/191)) ([029b181](https://github.com/googleapis/python-spanner-sqlalchemy/commit/029b18109c1ff21318c3820da5aa0945b6d6325d)) + + +### Bug Fixes + +* bump up google-cloud-spanner required version ([#171](https://github.com/googleapis/python-spanner-sqlalchemy/issues/171)) ([33c86e8](https://github.com/googleapis/python-spanner-sqlalchemy/commit/33c86e8fdeac4fd65569c438e8613dcb86e15edc)) +* connection reset fails when an additional dialect is used ([#188](https://github.com/googleapis/python-spanner-sqlalchemy/issues/188)) ([417b8b8](https://github.com/googleapis/python-spanner-sqlalchemy/commit/417b8b81911417ee3a1f826c37a9e490641944ac)) +* delete stale instance with delay of 5 seconds ([#194](https://github.com/googleapis/python-spanner-sqlalchemy/issues/194)) ([2932a02](https://github.com/googleapis/python-spanner-sqlalchemy/commit/2932a02bb58c4e2800da1e18452babcfc74617d6)) +* NOT NULL computed column creation failure ([#173](https://github.com/googleapis/python-spanner-sqlalchemy/issues/173)) ([e336735](https://github.com/googleapis/python-spanner-sqlalchemy/commit/e3367354d3b24328d7162fd2ccc778f23c630cd2)) + + +### Documentation + +* add a README section for the autoincremented ids ([#180](https://github.com/googleapis/python-spanner-sqlalchemy/issues/180)) ([4c610ea](https://github.com/googleapis/python-spanner-sqlalchemy/commit/4c610eaecd32679f23cae2f70d299d3c3d33d024)) +* explicitly recommend uuid to generate PKs ([#182](https://github.com/googleapis/python-spanner-sqlalchemy/issues/182)) ([b10f2ca](https://github.com/googleapis/python-spanner-sqlalchemy/commit/b10f2cae0eb13eb5496d08cbeae77a626b4ad6f1)), closes [#181](https://github.com/googleapis/python-spanner-sqlalchemy/issues/181) + ## [1.0.0](https://www.github.com/googleapis/python-spanner-sqlalchemy/compare/v0.1.0...v1.0.0) (2021-12-08) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 498b5ee5d7eb..8d8f602ba800 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.0.0" +__version__ = "1.1.0" From 7428dc24f1ebc8485d59f3966f325e4693553df2 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Tue, 15 Mar 2022 09:38:26 -0400 Subject: [PATCH 145/582] build(python): switch back to keystore for publication (#196) Co-authored-by: Ilya Gurov --- packages/sqlalchemy-spanner/.kokoro/release.sh | 2 +- .../sqlalchemy-spanner/.kokoro/release/common.cfg | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/release.sh b/packages/sqlalchemy-spanner/.kokoro/release.sh index c03a31f09eb0..6d767c28e79d 100755 --- a/packages/sqlalchemy-spanner/.kokoro/release.sh +++ b/packages/sqlalchemy-spanner/.kokoro/release.sh @@ -18,7 +18,7 @@ python3 -m pip install --upgrade twine wheel setuptools export PYTHONUNBUFFERED=1 # Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_GFILE_DIR}/secret_manager/google-cloud-pypi-token") +TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1") cd github/python-spanner-sqlalchemy python3 setup.py sdist bdist_wheel twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/sqlalchemy-spanner/.kokoro/release/common.cfg b/packages/sqlalchemy-spanner/.kokoro/release/common.cfg index 9a818a878c82..92607a27a9eb 100644 --- a/packages/sqlalchemy-spanner/.kokoro/release/common.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/release/common.cfg @@ -23,8 +23,18 @@ env_vars: { value: "github/python-spanner-sqlalchemy/.kokoro/release.sh" } +# Fetch PyPI password +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 73713 + keyname: "google-cloud-pypi-token-keystore-1" + } + } +} + # Tokens needed to report release status back to GitHub env_vars: { key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem,google-cloud-pypi-token" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" } From 47df176f85522652173fac4e15f04782ac66c45e Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 3 Jun 2022 01:05:21 -0700 Subject: [PATCH 146/582] feat: allow SQLAlchemy 1.4 use (#198) --- .../cloud/sqlalchemy_spanner/requirements.py | 1 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 4 +- packages/sqlalchemy-spanner/noxfile.py | 37 ++++++++++++++----- .../sqlalchemy-spanner/samples/conftest.py | 3 +- packages/sqlalchemy-spanner/setup.cfg | 2 +- packages/sqlalchemy-spanner/setup.py | 2 +- packages/sqlalchemy-spanner/test/_helpers.py | 3 +- packages/sqlalchemy-spanner/test/benchmark.py | 12 ++++-- .../sqlalchemy-spanner/test/test_suite_13.py | 21 ++++++++--- .../sqlalchemy-spanner/test/test_suite_14.py | 27 +++++++++++--- .../test/unit/test_opentelemetry_tracing.py | 7 ++-- 11 files changed, 86 insertions(+), 33 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index d552dc34b759..ce5e8d53afa6 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -29,6 +29,7 @@ def computed_columns(self): def computed_columns_stored(self): return exclusions.open() + @property def sane_rowcount(self): return exclusions.closed() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 9a1209b23a83..82eb14bddd09 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -48,7 +48,9 @@ @listens_for(Pool, "reset") def reset_connection(dbapi_conn, connection_record): """An event of returning a connection back to a pool.""" - dbapi_conn.connection.rollback() + if dbapi_conn.connection.inside_transaction: + dbapi_conn.connection.rollback() + if getattr(dbapi_conn.connection, "staleness", None) is not None: dbapi_conn.connection.staleness = None diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index fb9f923d2ee4..29d4f20c3b99 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -68,7 +68,7 @@ class = StreamHandler )""" -BLACK_VERSION = "black==19.10b0" +BLACK_VERSION = "black==22.3.0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] DEFAULT_PYTHON_VERSION = "3.8" @@ -82,10 +82,15 @@ def lint(session): """ session.install("flake8", BLACK_VERSION) session.run( - "black", "--check", *BLACK_PATHS, + "black", + "--check", + *BLACK_PATHS, ) session.run( - "flake8", "google", "test", "--max-line-length=88", + "flake8", + "google", + "test", + "--max-line-length=88", ) @@ -101,7 +106,8 @@ def blacken(session): """ session.install(BLACK_VERSION) session.run( - "black", *BLACK_PATHS, + "black", + *BLACK_PATHS, ) @@ -128,17 +134,23 @@ def compliance_test_13(session): ) session.install( - "pytest", "pytest-cov", "pytest-asyncio", + "pytest", + "pytest-cov", + "pytest-asyncio", ) session.install("mock") session.install("-e", ".[tracing]") + session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.24", "--force-reinstall") + session.run("pip", "install", "pytest==6.2.2", "--force-reinstall") + session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") + session.run("pip", "install", "opentelemetry-sdk<=1.10", "--force-reinstall") session.run("python", "create_test_database.py") session.run( "py.test", "--cov=google.cloud.sqlalchemy_spanner", - "--cov=tests", + "--cov=test", "--cov-append", "--cov-config=.coveragerc", "--cov-report=", @@ -164,7 +176,9 @@ def compliance_test_14(session): ) session.install( - "pytest", "pytest-cov", "pytest-asyncio", + "pytest", + "pytest-cov", + "pytest-asyncio", ) session.install("mock") @@ -176,7 +190,7 @@ def compliance_test_14(session): session.run( "py.test", "--cov=google.cloud.sqlalchemy_spanner", - "--cov=tests", + "--cov=test", "--cov-append", "--cov-config=.coveragerc", "--cov-report=", @@ -214,7 +228,8 @@ def migration_test(session): session.run("python", "create_test_database.py") project = os.getenv( - "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + "GOOGLE_CLOUD_PROJECT", + os.getenv("PROJECT_ID", "emulator-test-project"), ) db_url = ( f"spanner+spanner:///projects/{project}/instances/" @@ -242,7 +257,9 @@ def migration_test(session): with open(files[0], "r") as f: script_code = f.read() - script_code = script_code.replace("""def upgrade():\n pass""", UPGRADE_CODE) + script_code = script_code.replace( + """def upgrade() -> None:\n pass""", UPGRADE_CODE + ) with open(files[0], "w") as f: f.write(script_code) diff --git a/packages/sqlalchemy-spanner/samples/conftest.py b/packages/sqlalchemy-spanner/samples/conftest.py index 5a4f622e4e2e..298d81604285 100644 --- a/packages/sqlalchemy-spanner/samples/conftest.py +++ b/packages/sqlalchemy-spanner/samples/conftest.py @@ -33,7 +33,8 @@ @pytest.fixture def db_url(): project = os.getenv( - "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + "GOOGLE_CLOUD_PROJECT", + os.getenv("PROJECT_ID", "emulator-test-project"), ) db_url = ( f"spanner:///projects/{project}/instances/" diff --git a/packages/sqlalchemy-spanner/setup.cfg b/packages/sqlalchemy-spanner/setup.cfg index fd3202c407c1..4a1e77d23221 100644 --- a/packages/sqlalchemy-spanner/setup.cfg +++ b/packages/sqlalchemy-spanner/setup.cfg @@ -16,7 +16,7 @@ [tool:pytest] addopts= --tb native -v -r fxX --maxfail=25 -p no:warnings -python_files=test/*test_*.py +python_classes=*Test [sqla_testing] requirement_cls=google.cloud.sqlalchemy_spanner.requirements:Requirements diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 2f1be807c671..9f89d405591e 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -21,7 +21,7 @@ name = "sqlalchemy-spanner" description = "SQLAlchemy dialect integrated into Cloud Spanner database" dependencies = [ - "sqlalchemy>=1.1.13, <=1.3.23", + "sqlalchemy>=1.1.13", "google-cloud-spanner>=3.12.0", "alembic", ] diff --git a/packages/sqlalchemy-spanner/test/_helpers.py b/packages/sqlalchemy-spanner/test/_helpers.py index dd18a149d4b5..8ef795f23e16 100644 --- a/packages/sqlalchemy-spanner/test/_helpers.py +++ b/packages/sqlalchemy-spanner/test/_helpers.py @@ -32,7 +32,8 @@ PROJECT = os.getenv( - "GOOGLE_CLOUD_PROJECT", os.getenv("PROJECT_ID", "emulator-test-project"), + "GOOGLE_CLOUD_PROJECT", + os.getenv("PROJECT_ID", "emulator-test-project"), ) DB_URL = ( f"spanner:///projects/{PROJECT}/instances/" diff --git a/packages/sqlalchemy-spanner/test/benchmark.py b/packages/sqlalchemy-spanner/test/benchmark.py index 0ff50ae5da1a..0260ffc0592c 100644 --- a/packages/sqlalchemy-spanner/test/benchmark.py +++ b/packages/sqlalchemy-spanner/test/benchmark.py @@ -154,7 +154,7 @@ def __init__(self): self._many_rows = [] self._many_rows2 = [] birth_date = datetime.date(1998, 10, 6) - picture = base64.b64encode(u"123".encode()) + picture = base64.b64encode("123".encode()) for num in self._many_rows_ids: self._many_rows.append( { @@ -216,7 +216,9 @@ def __init__(self): super().__init__() self._engine = create_engine( "spanner:///projects/{project}/instances/{instance}/databases/{db}".format( - project=PROJECT, instance=INSTANCE, db=DATABASE, + project=PROJECT, + instance=INSTANCE, + db=DATABASE, ) ) metadata = MetaData(bind=self._engine) @@ -260,13 +262,15 @@ def insert_one_row_with_fetch_after(self): @measure_execution_time def insert_many_rows(self): self._conn.execute( - self._table.insert(), self._many_rows, + self._table.insert(), + self._many_rows, ) @measure_execution_time def insert_many_rows_with_mutations(self): self._conn.execute( - self._table.insert(), self._many_rows2, + self._table.insert(), + self._many_rows2, ) @measure_execution_time diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index b53045ac3a82..7b53b82c9650 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -793,7 +793,10 @@ def _test_get_unique_constraints(self, schema=None): reflected_metadata = MetaData() reflected = Table( - "testtbl", reflected_metadata, autoload_with=orig_meta.bind, schema=schema, + "testtbl", + reflected_metadata, + autoload_with=orig_meta.bind, + schema=schema, ) # test "deduplicates for index" logic. MySQL and Oracle @@ -1079,7 +1082,9 @@ def test_render_literal_numeric(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4), [15.7563], [decimal.Decimal("15.7563")], + Numeric(precision=8, scale=4), + [15.7563], + [decimal.Decimal("15.7563")], ) self._literal_round_trip( Numeric(precision=8, scale=4), @@ -1098,7 +1103,9 @@ def test_render_literal_numeric_asfloat(self): Overriding the test to avoid the same failure. """ self._literal_round_trip( - Numeric(precision=8, scale=4, asdecimal=False), [15.7563], [15.7563], + Numeric(precision=8, scale=4, asdecimal=False), + [15.7563], + [15.7563], ) self._literal_round_trip( Numeric(precision=8, scale=4, asdecimal=False), @@ -1193,7 +1200,9 @@ def test_float_as_decimal(self): Overriding the test to avoid the same failure. """ self._do_test( - Float(precision=8, asdecimal=True), [15.7563], [decimal.Decimal("15.7563")], + Float(precision=8, asdecimal=True), + [15.7563], + [decimal.Decimal("15.7563")], ) self._do_test( @@ -1742,7 +1751,9 @@ def define_tables(cls, metadata): if testing.requires.computed_columns_stored.enabled: t.append_column( Column( - "computed_stored", Integer, Computed("normal - 42", persisted=True), + "computed_stored", + Integer, + Computed("normal - 42", persisted=True), ) ) if testing.requires.schemas.enabled: diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 688d822ee29f..6d708f089075 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -530,7 +530,9 @@ def test_reflect_bytes_column_max_len(self): """ metadata = MetaData(self.bind) Table( - "bytes_table", metadata, Column("TestColumn", LargeBinary, nullable=False), + "bytes_table", + metadata, + Column("TestColumn", LargeBinary, nullable=False), ) metadata.create_all() @@ -600,7 +602,10 @@ def test_get_unique_constraints(self, metadata, connection, use_schema): reflected_metadata = MetaData() reflected = Table( - "testtbl", reflected_metadata, autoload_with=connection, schema=schema, + "testtbl", + reflected_metadata, + autoload_with=connection, + schema=schema, ) # test "deduplicates for index" logic. MySQL and Oracle @@ -964,7 +969,9 @@ def test_limit_render_multiple_times(self, connection): u = union(select(stmt), select(stmt)).subquery().select() self._assert_result( - connection, u, [(2,)], + connection, + u, + [(2,)], ) @@ -1939,7 +1946,9 @@ def define_tables(cls, metadata): if testing.requires.computed_columns_stored.enabled: t.append_column( Column( - "computed_stored", Integer, Computed("normal - 42", persisted=True), + "computed_stored", + Integer, + Computed("normal - 42", persisted=True), ) ) @@ -1960,11 +1969,17 @@ def test_get_column_returns_persisted_with_schema(self): ) if testing.requires.computed_columns_virtual.enabled: self.check_column( - data, "computed_virtual", "normal/2", False, + data, + "computed_virtual", + "normal/2", + False, ) if testing.requires.computed_columns_stored.enabled: self.check_column( - data, "computed_stored", "normal-42", True, + data, + "computed_stored", + "normal-42", + True, ) @pytest.mark.skip("Default values are not supported.") diff --git a/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py index e762f93d2ff3..a8af61c647e9 100644 --- a/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py @@ -32,7 +32,7 @@ def _make_rpc_error(error_cls, trailing_metadata=None): # Skip all of these tests if we don't have OpenTelemetry if HAS_OPENTELEMETRY_INSTALLED: - class TestNoTracing(OpenTelemetryBase): + class NoTracingTest(OpenTelemetryBase): def setup(self): self._temp_opentelemetry = sys.modules["opentelemetry"] @@ -47,7 +47,7 @@ def test_no_trace_call(self): with _opentelemetry_tracing.trace_call("Test") as no_span: assert no_span is None - class TestTracing(OpenTelemetryBase): + class TracingTest(OpenTelemetryBase): def test_trace_call(self): extra_attributes = { "attribute1": "value1", @@ -96,7 +96,8 @@ def test_trace_error(self): with pytest.raises(GoogleAPICallError): with _opentelemetry_tracing.trace_call( - "CloudSpannerSqlAlchemy.Test", extra_attributes, + "CloudSpannerSqlAlchemy.Test", + extra_attributes, ) as span: from google.api_core.exceptions import InvalidArgument From 5eb33731b32d7228c5247f97110ffff931e8cebd Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 18:51:47 +0530 Subject: [PATCH 147/582] chore(main): release 1.2.0 (#215) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index f0a42c9b2af0..39c469bccc74 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.2.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.1.0...v1.2.0) (2022-06-03) + + +### Features + +* allow SQLAlchemy 1.4 use ([#198](https://github.com/googleapis/python-spanner-sqlalchemy/issues/198)) ([7793b7d](https://github.com/googleapis/python-spanner-sqlalchemy/commit/7793b7ddfcbd99e966e3ef6f7ec13d7dc04d39fb)) + ## [1.1.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.0.0...v1.1.0) (2022-01-28) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 8d8f602ba800..3329f65684c8 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.1.0" +__version__ = "1.2.0" From d0bb68365e9cea0055478a43f21f1e6fbaa2c85d Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 20 Jun 2022 00:47:39 -0700 Subject: [PATCH 148/582] fix: don't reset attributes of non-Spanner connections (#222) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 82eb14bddd09..6888e8fa6aa1 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -48,14 +48,14 @@ @listens_for(Pool, "reset") def reset_connection(dbapi_conn, connection_record): """An event of returning a connection back to a pool.""" - if dbapi_conn.connection.inside_transaction: - dbapi_conn.connection.rollback() + if isinstance(dbapi_conn.connection, spanner_dbapi.Connection): + if dbapi_conn.connection.inside_transaction: + dbapi_conn.connection.rollback() - if getattr(dbapi_conn.connection, "staleness", None) is not None: dbapi_conn.connection.staleness = None - - if getattr(dbapi_conn.connection, "read_only", None) is not None: dbapi_conn.connection.read_only = False + else: + dbapi_conn.connection.rollback() # register a method to get a single value of a JSON object From a54fc717b92af6089ffdc2c624f8741bc92b4145 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 20 Jun 2022 04:27:56 -0700 Subject: [PATCH 149/582] docs: add a note about connection URL prefixes (#219) --- packages/sqlalchemy-spanner/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index a29ffdfbee16..595a36588963 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -30,6 +30,16 @@ During setup the dialect will be registered with entry points. ## A Minimal App +### Database URL +In order to connect to a database one have to use its URL on connection creation step. SQLAlchemy 1.3 and 1.4 versions have a bit of difference on this step in a dialect prefix part: +```python +# for SQLAlchemy 1.3: +spanner:///projects/project-id/instances/instance-id/databases/database-id + +# for SQLAlchemy 1.4: +spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id +``` + ### Create a table ```python from sqlalchemy import ( From 4c221bab49913b503eab595fbad8769552207c42 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 21 Jun 2022 12:00:34 -0700 Subject: [PATCH 150/582] fix: alembic migration fails in case of a sequential upgrade (#200) --- packages/sqlalchemy-spanner/README.md | 12 ++++++++++++ packages/sqlalchemy-spanner/test_migration_env.py | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md index 595a36588963..e348f597e2ca 100644 --- a/packages/sqlalchemy-spanner/README.md +++ b/packages/sqlalchemy-spanner/README.md @@ -104,9 +104,21 @@ with engine.begin() as connection: SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. +Spanner dialect doesn't provide a default migration environment, it's up to user to write it. One thing to be noted here - one should explicitly set `alembic_version` table not to use migration revision id as a primary key: +```python +with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + version_table_pk=False, # don't use primary key in the versions table + ) +``` +As Spanner restricts changing a primary key value, not setting the flag to `False` can cause migration problems. + **Warning!** A migration script can produce a lot of DDL statements. If each of the statements are executed separately, performance issues can occur. To avoid these, it's highly recommended to use the [Alembic batch context](https://alembic.sqlalchemy.org/en/latest/batch.html) feature to pack DDL statements into groups of statements. + ## Features and limitations ### Interleaved tables diff --git a/packages/sqlalchemy-spanner/test_migration_env.py b/packages/sqlalchemy-spanner/test_migration_env.py index d2ec9507d06d..1ddb4bca5fdf 100644 --- a/packages/sqlalchemy-spanner/test_migration_env.py +++ b/packages/sqlalchemy-spanner/test_migration_env.py @@ -62,6 +62,7 @@ def run_migrations_offline(): target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, + version_table_pk=False, ) with context.begin_transaction(): @@ -82,7 +83,11 @@ def run_migrations_online(): ) with connectable.connect() as connection: - context.configure(connection=connection, target_metadata=target_metadata) + context.configure( + connection=connection, + target_metadata=target_metadata, + version_table_pk=False, + ) with context.begin_transaction(): context.run_migrations() From f398639d84100e68a5b0096079d05b69bbd3e702 Mon Sep 17 00:00:00 2001 From: ansh0l Date: Tue, 12 Jul 2022 20:09:54 +0530 Subject: [PATCH 151/582] chore: change repo maintainer (#213) Co-authored-by: Ilya Gurov --- packages/sqlalchemy-spanner/.github/blunderbuss.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/blunderbuss.yml b/packages/sqlalchemy-spanner/.github/blunderbuss.yml index 8715e17dc449..fc2092ed7f76 100644 --- a/packages/sqlalchemy-spanner/.github/blunderbuss.yml +++ b/packages/sqlalchemy-spanner/.github/blunderbuss.yml @@ -1,2 +1,2 @@ assign_issues: - - vi3k6i5 + - asthamohta From b32caa4a249eb4196e8d2c14cddfc892be0e2e2e Mon Sep 17 00:00:00 2001 From: Trevor Pope Date: Mon, 1 Aug 2022 08:03:59 -0400 Subject: [PATCH 152/582] fix: incorrect DDL generated when using server_default (#209) (#220) --- packages/sqlalchemy-spanner/README.md | 340 ------------ packages/sqlalchemy-spanner/README.rst | 494 ++++++++++++++++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 8 +- packages/sqlalchemy-spanner/setup.py | 7 + 4 files changed, 505 insertions(+), 344 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/README.md create mode 100644 packages/sqlalchemy-spanner/README.rst diff --git a/packages/sqlalchemy-spanner/README.md b/packages/sqlalchemy-spanner/README.md deleted file mode 100644 index e348f597e2ca..000000000000 --- a/packages/sqlalchemy-spanner/README.md +++ /dev/null @@ -1,340 +0,0 @@ -# Spanner dialect for SQLAlchemy - -Spanner dialect for SQLAlchemy represents an interface API designed to make it possible to control Cloud Spanner databases with SQLAlchemy API. The dialect is built on top of [the Spanner DB API](https://github.com/googleapis/python-spanner/tree/master/google/cloud/spanner_dbapi), which is designed in accordance with [PEP-249](https://www.python.org/dev/peps/pep-0249/). - -Known limitations are listed [here](#features-and-limitations). All supported features have been tested and verified to work with the test configurations. There may be configurations and/or data model variations that have not yet been covered by the tests and that show unexpected behavior. Please report any problems that you might encounter by [creating a new issue](https://github.com/googleapis/python-spanner-sqlalchemy/issues/new). - -- [Cloud Spanner product documentation](https://cloud.google.com/spanner/docs) -- [SQLAlchemy product documentation](https://www.sqlalchemy.org/) - -## Quick Start - -In order to use this package, you first need to go through the following steps: - -1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) -2. [Enable billing for your project.](https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project) -3. [Enable the Google Cloud Spanner API.](https://cloud.google.com/spanner) -4. [Setup Authentication.](https://googleapis.dev/python/google-api-core/latest/auth.html) - -## Installation - -To install an in-development version of the package, clone its Git-repository: -``` -git clone https://github.com/googleapis/python-spanner-sqlalchemy.git -``` -Next install the package from the package `setup.py` file: -``` -python setup.py install -``` -During setup the dialect will be registered with entry points. - -## A Minimal App - -### Database URL -In order to connect to a database one have to use its URL on connection creation step. SQLAlchemy 1.3 and 1.4 versions have a bit of difference on this step in a dialect prefix part: -```python -# for SQLAlchemy 1.3: -spanner:///projects/project-id/instances/instance-id/databases/database-id - -# for SQLAlchemy 1.4: -spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id -``` - -### Create a table -```python -from sqlalchemy import ( - Column, - Integer, - MetaData, - String, - Table, - create_engine, -) - -engine = create_engine( - "spanner:///projects/project-id/instances/instance-id/databases/database-id" -) -metadata = MetaData(bind=engine) - -user = Table( - "users", - metadata, - Column("user_id", Integer, primary_key=True), - Column("user_name", String(16), nullable=False), -) - -metadata.create_all(engine) -``` - -### Insert a row -```python -import uuid - -from sqlalchemy import ( - MetaData, - Table, - create_engine, -) - -engine = create_engine( - "spanner:///projects/project-id/instances/instance-id/databases/database-id" -) -user = Table("users", MetaData(bind=engine), autoload=True) -user_id = uuid.uuid4().hex[:6].lower() - -with engine.begin() as connection: - connection.execute(user.insert(), {"user_id": user_id, "user_name": "Full Name"}) -``` - -### Read -```python -from sqlalchemy import MetaData, Table, create_engine, select - -engine = create_engine( - "spanner:///projects/project-id/instances/instance-id/databases/database-id" -) -table = Table("users", MetaData(bind=engine), autoload=True) - -with engine.begin() as connection: - for row in connection.execute(select(["*"], from_obj=table)).fetchall(): - print(row) -``` - -## Migration - -SQLAlchemy uses [Alembic](https://alembic.sqlalchemy.org/en/latest/#) tool to organize database migrations. - -Spanner dialect doesn't provide a default migration environment, it's up to user to write it. One thing to be noted here - one should explicitly set `alembic_version` table not to use migration revision id as a primary key: -```python -with connectable.connect() as connection: - context.configure( - connection=connection, - target_metadata=target_metadata, - version_table_pk=False, # don't use primary key in the versions table - ) -``` -As Spanner restricts changing a primary key value, not setting the flag to `False` can cause migration problems. - -**Warning!** -A migration script can produce a lot of DDL statements. If each of the statements are executed separately, performance issues can occur. To avoid these, it's highly recommended to use the [Alembic batch context](https://alembic.sqlalchemy.org/en/latest/batch.html) feature to pack DDL statements into groups of statements. - - -## Features and limitations - -### Interleaved tables -Cloud Spanner dialect includes two dialect-specific arguments for `Table` constructor, which help to define interleave relations: -`spanner_interleave_in` - a parent table name -`spanner_inverleave_on_delete_cascade` - a flag specifying if `ON DELETE CASCADE` statement must be used for the interleave relation -An example of interleave relations definition: -```python -team = Table( - "team", - metadata, - Column("team_id", Integer, primary_key=True), - Column("team_name", String(16), nullable=False), -) -team.create(engine) - -client = Table( - "client", - metadata, - Column("team_id", Integer, primary_key=True), - Column("client_id", Integer, primary_key=True), - Column("client_name", String(16), nullable=False), - spanner_interleave_in="team", - spanner_interleave_on_delete_cascade=True, -) -client.add_is_dependent_on(team) - -client.create(engine) -``` -**Note**: Interleaved tables have a dependency between them, so the parent table must be created before the child table. When creating tables with this feature, make sure to call `add_is_dependent_on()` on the child table to request SQLAlchemy to create the parent table before the child table. - -### Unique constraints -Cloud Spanner doesn't support direct UNIQUE constraints creation. In order to achieve column values uniqueness UNIQUE indexes should be used. - -Instead of direct UNIQUE constraint creation: -```python -Table( - 'table', - metadata, - Column('col1', Integer), - UniqueConstraint('col1', name='uix_1') -) -``` -Create a UNIQUE index: -```python -Table( - 'table', - metadata, - Column('col1', Integer), - Index("uix_1", "col1", unique=True), -) -``` -### Autocommit mode -Spanner dialect supports both `SERIALIZABLE` and `AUTOCOMMIT` isolation levels. `SERIALIZABLE` is the default one, where transactions need to be committed manually. `AUTOCOMMIT` mode corresponds to automatically committing of a query right in its execution time. - -Isolation level change example: -```python -from sqlalchemy import create_engine - -eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id") -autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") -``` - -### Autoincremented IDs -Cloud Spanner doesn't support autoincremented IDs mechanism due to performance reasons ([see for more details](https://cloud.google.com/spanner/docs/schema-design#primary-key-prevent-hotspots)). We recommend that you use the Python [uuid](https://docs.python.org/3/library/uuid.html) module to generate primary key fields to avoid creating monotonically increasing keys. - -Though it's not encouraged to do so, in case you *need* the feature, you can simulate it manually as follows: -```python -with engine.begin() as connection: - top_id = connection.execute( - select([user.c.user_id]).order_by(user.c.user_id.desc()).limit(1) - ).fetchone() - next_id = top_id[0] + 1 if top_id else 1 - - connection.execute(user.insert(), {"user_id": next_id}) -``` - -### Query hints -Spanner dialect supports [query hints](https://cloud.google.com/spanner/docs/query-syntax#table_hints), which give the ability to set additional query execution parameters. Usage example: -```python -session = Session(engine) - -Base = declarative_base() - -class User(Base): - """Data model.""" - - __tablename__ = "users" - id = Column(Integer, primary_key=True) - name = Column(String(50)) - - -query = session.query(User) -query = query.with_hint( - selectable=User, text="@{FORCE_INDEX=index_name}" -) -query = query.filter(User.name.in_(["val1", "val2"])) -query.statement.compile(session.bind) -``` - -### ReadOnly transactions -By default, transactions produced by a Spanner connection are in ReadWrite mode. However, some applications require an ability to grant ReadOnly access to users/methods; for these cases Spanner dialect supports the `read_only` execution option, which switches a connection into ReadOnly mode: -```python -with engine.connect().execution_options(read_only=True) as connection: - connection.execute(select(["*"], from_obj=table)).fetchall() -``` -Note that execution options are applied lazily - on the `execute()` method call, right before it. - -ReadOnly/ReadWrite mode of a connection can't be changed while a transaction is in progress - first you must commit or rollback it. - -### Stale reads -To use the Spanner [Stale Reads](https://cloud.google.com/spanner/docs/reads#perform-stale-read) with SQLAlchemy you can tweak the connection execution options with a wanted staleness value. For example: -```python -# maximum staleness -with engine.connect().execution_options( - read_only=True, - staleness={"max_staleness": datetime.timedelta(seconds=5)} -) as connection: - connection.execute(select(["*"], from_obj=table)).fetchall() -``` - -```python -# exact staleness -with engine.connect().execution_options( - read_only=True, - staleness={"exact_staleness": datetime.timedelta(seconds=5)} -) as connection: - connection.execute(select(["*"], from_obj=table)).fetchall() -``` - -```python -# min read timestamp -with engine.connect().execution_options( - read_only=True, - staleness={"min_read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} -) as connection: - connection.execute(select(["*"], from_obj=table)).fetchall() -``` - -```python -# read timestamp -with engine.connect().execution_options( - read_only=True, - staleness={"read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} -) as connection: - connection.execute(select(["*"], from_obj=table)).fetchall() -``` -Note that the set option will be dropped when the connection is returned back to the pool. - -### DDL and transactions -DDL statements are executed outside the regular transactions mechanism, which means DDL statements will not be rolled back on normal transaction rollback. - -### Dropping a table -Cloud Spanner, by default, doesn't drop tables, which have secondary indexes and/or foreign key constraints. In Spanner dialect for SQLAlchemy, however, this restriction is omitted - if a table you are trying to delete has indexes/foreign keys, they will be dropped automatically right before dropping the table. - -### Data types -Data types table mapping SQLAlchemy types to Cloud Spanner types: - -| SQLAlchemy | Spanner | -| ------------- | ------------- | -| INTEGER | INT64 | -| BIGINT | INT64 | -| DECIMAL | NUMERIC | -| FLOAT | FLOAT64 | -| TEXT | STRING | -| ARRAY | ARRAY | -| BINARY | BYTES | -| VARCHAR | STRING | -| CHAR | STRING | -| BOOLEAN | BOOL | -| DATETIME | TIMESTAMP | -| NUMERIC | NUMERIC | - - -### Other limitations -- WITH RECURSIVE statement is not supported. -- Named schemas are not supported. -- Temporary tables are not supported. -- Numeric type dimensions (scale and precision) are constant. See the [docs](https://cloud.google.com/spanner/docs/data-types#numeric_types). - -## Best practices -When a SQLAlchemy function is called, a new connection to a database is established and a Spanner session object is fetched. In case of connectionless execution these fetches are done for every `execute()` call, which can cause a significant latency. To avoid initiating a Spanner session on every `execute()` call it's recommended to write code in connection-bounded fashion. Once a `Connection()` object is explicitly initiated, it fetches a Spanner session object and uses it for all the following calls made on this `Connection()` object. - -Non-optimal connectionless use: -```python -# execute() is called on object, which is not a Connection() object -insert(user).values(user_id=1, user_name="Full Name").execute() -``` -Optimal connection-bounded use: -```python -with engine.begin() as connection: - # execute() is called on a Connection() object - connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) -``` -Connectionless way of use is also deprecated since SQLAlchemy 2.0 and soon will be removed (see in [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/connections.html#connectionless-execution-implicit-execution)). - -## Running tests - -Spanner dialect includes a compliance, migration and unit test suite. To run the tests the `nox` package commands can be used: -``` -# Run the whole suite -$ nox - -# Run a particular test session -$ nox -s migration_test -``` -### Running tests on Spanner emulator -The dialect test suite can be runned on [Spanner emulator](https://cloud.google.com/spanner/docs/emulator). Several tests, relating to `NULL` values of data types, are skipped when executed on emulator. - -## Contributing - -Contributions to this library are welcome and encouraged. Please report issues, file feature requests, and send pull requests. See [CONTRIBUTING](https://github.com/googleapis/python-spanner-sqlalchemy/blob/main/contributing.md) for more information on how to get -started. - -**Note that this project is not officially supported by Google as part of the Cloud Spanner product.** - -Please note that this project is released with a Contributor Code of Conduct. -By participating in this project you agree to abide by its terms. See the [Code -of Conduct](https://github.com/googleapis/python-spanner-sqlalchemy/blob/main/code-of-conduct.md) for more information. diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst new file mode 100644 index 000000000000..b4550cd2b0ee --- /dev/null +++ b/packages/sqlalchemy-spanner/README.rst @@ -0,0 +1,494 @@ +Spanner dialect for SQLAlchemy +============================== + +Spanner dialect for SQLAlchemy represents an interface API designed to +make it possible to control Cloud Spanner databases with SQLAlchemy API. +The dialect is built on top of `the Spanner DB +API `__, +which is designed in accordance with +`PEP-249 `__. + +Known limitations are listed `here <#features-and-limitations>`__. All +supported features have been tested and verified to work with the test +configurations. There may be configurations and/or data model variations +that have not yet been covered by the tests and that show unexpected +behavior. Please report any problems that you might encounter by +`creating a new +issue `__. + +- `Cloud Spanner product + documentation `__ +- `SQLAlchemy product documentation `__ + +Quick Start +----------- + +In order to use this package, you first need to go through the following +steps: + +1. `Select or create a Cloud Platform + project. `__ +2. `Enable billing for your + project. `__ +3. `Enable the Google Cloud Spanner + API. `__ +4. `Setup + Authentication. `__ + +Installation +------------ + +To install an in-development version of the package, clone its +Git-repository: + +:: + + git clone https://github.com/googleapis/python-spanner-sqlalchemy.git + +Next install the package from the package ``setup.py`` file: + +:: + + python setup.py install + +During setup the dialect will be registered with entry points. + +A Minimal App +------------- + +Database URL +~~~~~~~~~~~~ + +In order to connect to a database one have to use its URL on connection +creation step. SQLAlchemy 1.3 and 1.4 versions have a bit of difference +on this step in a dialect prefix part: + +.. code:: python + + # for SQLAlchemy 1.3: + spanner:///projects/project-id/instances/instance-id/databases/database-id + + # for SQLAlchemy 1.4: + spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id + +Create a table +~~~~~~~~~~~~~~ + +.. code:: python + + from sqlalchemy import ( + Column, + Integer, + MetaData, + String, + Table, + create_engine, + ) + + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + metadata = MetaData(bind=engine) + + user = Table( + "users", + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + + metadata.create_all(engine) + +Insert a row +~~~~~~~~~~~~ + +.. code:: python + + import uuid + + from sqlalchemy import ( + MetaData, + Table, + create_engine, + ) + + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + user = Table("users", MetaData(bind=engine), autoload=True) + user_id = uuid.uuid4().hex[:6].lower() + + with engine.begin() as connection: + connection.execute(user.insert(), {"user_id": user_id, "user_name": "Full Name"}) + +Read +~~~~ + +.. code:: python + + from sqlalchemy import MetaData, Table, create_engine, select + + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + table = Table("users", MetaData(bind=engine), autoload=True) + + with engine.begin() as connection: + for row in connection.execute(select(["*"], from_obj=table)).fetchall(): + print(row) + +Migration +--------- + +SQLAlchemy uses `Alembic `__ +tool to organize database migrations. + +Spanner dialect doesn't provide a default migration environment, it's up +to user to write it. One thing to be noted here - one should explicitly +set ``alembic_version`` table not to use migration revision id as a +primary key: + +.. code:: python + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + version_table_pk=False, # don't use primary key in the versions table + ) + +As Spanner restricts changing a primary key value, not setting the flag +to ``False`` can cause migration problems. + +| **Warning!** +| A migration script can produce a lot of DDL statements. If each of the + statements are executed separately, performance issues can occur. To + avoid these, it's highly recommended to use the `Alembic batch + context `__ + feature to pack DDL statements into groups of statements. + +Features and limitations +------------------------ + +Interleaved tables +~~~~~~~~~~~~~~~~~~ + +| Cloud Spanner dialect includes two dialect-specific arguments for + ``Table`` constructor, which help to define interleave relations: + ``spanner_interleave_in`` - a parent table name + ``spanner_inverleave_on_delete_cascade`` - a flag specifying if + ``ON DELETE CASCADE`` statement must be used for the interleave + relation +| An example of interleave relations definition: + +.. code:: python + + team = Table( + "team", + metadata, + Column("team_id", Integer, primary_key=True), + Column("team_name", String(16), nullable=False), + ) + team.create(engine) + + client = Table( + "client", + metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + spanner_interleave_on_delete_cascade=True, + ) + client.add_is_dependent_on(team) + + client.create(engine) + +**Note**: Interleaved tables have a dependency between them, so the +parent table must be created before the child table. When creating +tables with this feature, make sure to call ``add_is_dependent_on()`` on +the child table to request SQLAlchemy to create the parent table before +the child table. + +Unique constraints +~~~~~~~~~~~~~~~~~~ + +Cloud Spanner doesn't support direct UNIQUE constraints creation. In +order to achieve column values uniqueness UNIQUE indexes should be used. + +Instead of direct UNIQUE constraint creation: + +.. code:: python + + Table( + 'table', + metadata, + Column('col1', Integer), + UniqueConstraint('col1', name='uix_1') + ) + +Create a UNIQUE index: + +.. code:: python + + Table( + 'table', + metadata, + Column('col1', Integer), + Index("uix_1", "col1", unique=True), + ) + +Autocommit mode +~~~~~~~~~~~~~~~ + +Spanner dialect supports both ``SERIALIZABLE`` and ``AUTOCOMMIT`` +isolation levels. ``SERIALIZABLE`` is the default one, where +transactions need to be committed manually. ``AUTOCOMMIT`` mode +corresponds to automatically committing of a query right in its +execution time. + +Isolation level change example: + +.. code:: python + + from sqlalchemy import create_engine + + eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id") + autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") + +Autoincremented IDs +~~~~~~~~~~~~~~~~~~~ + +Cloud Spanner doesn't support autoincremented IDs mechanism due to +performance reasons (`see for more +details `__). +We recommend that you use the Python +`uuid `__ module to +generate primary key fields to avoid creating monotonically increasing +keys. + +Though it's not encouraged to do so, in case you *need* the feature, you +can simulate it manually as follows: + +.. code:: python + + with engine.begin() as connection: + top_id = connection.execute( + select([user.c.user_id]).order_by(user.c.user_id.desc()).limit(1) + ).fetchone() + next_id = top_id[0] + 1 if top_id else 1 + + connection.execute(user.insert(), {"user_id": next_id}) + +Query hints +~~~~~~~~~~~ + +Spanner dialect supports `query +hints `__, +which give the ability to set additional query execution parameters. +Usage example: + +.. code:: python + + session = Session(engine) + + Base = declarative_base() + + class User(Base): + """Data model.""" + + __tablename__ = "users" + id = Column(Integer, primary_key=True) + name = Column(String(50)) + + + query = session.query(User) + query = query.with_hint( + selectable=User, text="@{FORCE_INDEX=index_name}" + ) + query = query.filter(User.name.in_(["val1", "val2"])) + query.statement.compile(session.bind) + +ReadOnly transactions +~~~~~~~~~~~~~~~~~~~~~ + +By default, transactions produced by a Spanner connection are in +ReadWrite mode. However, some applications require an ability to grant +ReadOnly access to users/methods; for these cases Spanner dialect +supports the ``read_only`` execution option, which switches a connection +into ReadOnly mode: + +.. code:: python + + with engine.connect().execution_options(read_only=True) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + +Note that execution options are applied lazily - on the ``execute()`` +method call, right before it. + +ReadOnly/ReadWrite mode of a connection can't be changed while a +transaction is in progress - first you must commit or rollback it. + +Stale reads +~~~~~~~~~~~ + +To use the Spanner `Stale +Reads `__ +with SQLAlchemy you can tweak the connection execution options with a +wanted staleness value. For example: + +.. code:: python + + # maximum staleness + with engine.connect().execution_options( + read_only=True, + staleness={"max_staleness": datetime.timedelta(seconds=5)} + ) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + +.. code:: python + + # exact staleness + with engine.connect().execution_options( + read_only=True, + staleness={"exact_staleness": datetime.timedelta(seconds=5)} + ) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + +.. code:: python + + # min read timestamp + with engine.connect().execution_options( + read_only=True, + staleness={"min_read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} + ) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + +.. code:: python + + # read timestamp + with engine.connect().execution_options( + read_only=True, + staleness={"read_timestamp": datetime.datetime(2021, 11, 17, 12, 55, 30)} + ) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + +Note that the set option will be dropped when the connection is returned +back to the pool. + +DDL and transactions +~~~~~~~~~~~~~~~~~~~~ + +DDL statements are executed outside the regular transactions mechanism, +which means DDL statements will not be rolled back on normal transaction +rollback. + +Dropping a table +~~~~~~~~~~~~~~~~ + +Cloud Spanner, by default, doesn't drop tables, which have secondary +indexes and/or foreign key constraints. In Spanner dialect for +SQLAlchemy, however, this restriction is omitted - if a table you are +trying to delete has indexes/foreign keys, they will be dropped +automatically right before dropping the table. + +Data types +~~~~~~~~~~ + +Data types table mapping SQLAlchemy types to Cloud Spanner types: + +========== ========= +SQLAlchemy Spanner +========== ========= +INTEGER INT64 +BIGINT INT64 +DECIMAL NUMERIC +FLOAT FLOAT64 +TEXT STRING +ARRAY ARRAY +BINARY BYTES +VARCHAR STRING +CHAR STRING +BOOLEAN BOOL +DATETIME TIMESTAMP +NUMERIC NUMERIC +========== ========= + +Other limitations +~~~~~~~~~~~~~~~~~ + +- WITH RECURSIVE statement is not supported. +- Named schemas are not supported. +- Temporary tables are not supported. +- Numeric type dimensions (scale and precision) are constant. See the + `docs `__. + +Best practices +-------------- + +When a SQLAlchemy function is called, a new connection to a database is +established and a Spanner session object is fetched. In case of +connectionless execution these fetches are done for every ``execute()`` +call, which can cause a significant latency. To avoid initiating a +Spanner session on every ``execute()`` call it's recommended to write +code in connection-bounded fashion. Once a ``Connection()`` object is +explicitly initiated, it fetches a Spanner session object and uses it +for all the following calls made on this ``Connection()`` object. + +Non-optimal connectionless use: + +.. code:: python + + # execute() is called on object, which is not a Connection() object + insert(user).values(user_id=1, user_name="Full Name").execute() + +Optimal connection-bounded use: + +.. code:: python + + with engine.begin() as connection: + # execute() is called on a Connection() object + connection.execute(user.insert(), {"user_id": 1, "user_name": "Full Name"}) + +Connectionless way of use is also deprecated since SQLAlchemy 2.0 and +soon will be removed (see in `SQLAlchemy +docs `__). + +Running tests +------------- + +Spanner dialect includes a compliance, migration and unit test suite. To +run the tests the ``nox`` package commands can be used: + +:: + + # Run the whole suite + $ nox + + # Run a particular test session + $ nox -s migration_test + +Running tests on Spanner emulator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The dialect test suite can be runned on `Spanner +emulator `__. Several +tests, relating to ``NULL`` values of data types, are skipped when +executed on emulator. + +Contributing +------------ + +Contributions to this library are welcome and encouraged. Please report +issues, file feature requests, and send pull requests. See +`CONTRIBUTING `__ +for more information on how to get started. + +**Note that this project is not officially supported by Google as part +of the Cloud Spanner product.** + +Please note that this project is released with a Contributor Code of +Conduct. By participating in this project you agree to abide by its +terms. See the `Code of +Conduct `__ +for more information. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 6888e8fa6aa1..515056561714 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -342,13 +342,13 @@ def get_column_specification(self, column, **kwargs): + " " + self.dialect.type_compiler.process(column.type, type_expression=column) ) - default = self.get_column_default_string(column) - if default is not None: - colspec += " DEFAULT " + default - if not column.nullable: colspec += " NOT NULL" + default = self.get_column_default_string(column) + if default is not None: + colspec += " DEFAULT (" + default + ")" + if column.computed is not None: colspec += " " + self.process(column.computed) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 9f89d405591e..72fa56532f5b 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import os import setuptools @@ -40,6 +41,11 @@ exec(f.read(), PACKAGE_INFO) version = PACKAGE_INFO["__version__"] +package_root = os.path.abspath(os.path.dirname(__file__)) +readme_filename = os.path.join(package_root, "README.rst") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. packages = [ @@ -58,6 +64,7 @@ author_email="cloud-spanner-developers@googlegroups.com", classifiers=["Intended Audience :: Developers"], description=description, + long_description=readme, entry_points={ "sqlalchemy.dialects": [ "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" From 313b651717ae6375f5b4ddeb7600f3fe5d003436 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 9 Aug 2022 03:19:50 -0700 Subject: [PATCH 153/582] test: unskip default column value test (#226) --- packages/sqlalchemy-spanner/test/test_suite_13.py | 4 ---- packages/sqlalchemy-spanner/test/test_suite_14.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 7b53b82c9650..55d471d33b00 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -999,10 +999,6 @@ def test_empty_insert(self): def test_insert_from_select_autoinc(self): pass - @pytest.mark.skip("Spanner doesn't support default column values") - def test_insert_from_select_with_defaults(self): - pass - def test_autoclose_on_insert(self): """ SPANNER OVERRIDE: diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 6d708f089075..42ca3d967094 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -1252,10 +1252,6 @@ def test_empty_insert_multiple(self): def test_insert_from_select_autoinc(self): pass - @pytest.mark.skip("Spanner doesn't support default column values") - def test_insert_from_select_with_defaults(self): - pass - def test_autoclose_on_insert(self): """ SPANNER OVERRIDE: From 15d2fbb6cd8b95a44ef35363ffb82f592a7dc885 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 11 Aug 2022 12:47:25 +0530 Subject: [PATCH 154/582] chore(main): release 1.2.1 (#224) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 14 ++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 39c469bccc74..d5bb4f003c81 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [1.2.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.0...v1.2.1) (2022-08-09) + + +### Bug Fixes + +* alembic migration fails in case of a sequential upgrade ([#200](https://github.com/googleapis/python-spanner-sqlalchemy/issues/200)) ([f62f664](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f62f664f31ec052068e241729344aec5f605c4f8)) +* don't reset attributes of non-Spanner connections ([#222](https://github.com/googleapis/python-spanner-sqlalchemy/issues/222)) ([072415e](https://github.com/googleapis/python-spanner-sqlalchemy/commit/072415eb9ea0bf701be2a35c4cc3dc80854ca831)) +* incorrect DDL generated when using server_default ([#209](https://github.com/googleapis/python-spanner-sqlalchemy/issues/209)) ([#220](https://github.com/googleapis/python-spanner-sqlalchemy/issues/220)) ([7ab1742](https://github.com/googleapis/python-spanner-sqlalchemy/commit/7ab174233dc75fd34d4127cb06dd49c216d92abc)) + + +### Documentation + +* add a note about connection URL prefixes ([#219](https://github.com/googleapis/python-spanner-sqlalchemy/issues/219)) ([a986949](https://github.com/googleapis/python-spanner-sqlalchemy/commit/a9869498f220a529a1dcc51c89d53af54311074c)) + ## [1.2.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.1.0...v1.2.0) (2022-06-03) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 3329f65684c8..2f4e6ea6df57 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.2.0" +__version__ = "1.2.1" From 3265d87f87ff9469bf249e4b6bedf6bc3ca37e6a Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 11 Aug 2022 18:26:12 +0200 Subject: [PATCH 155/582] chore(deps): update actions/setup-python action to v4 (#223) Co-authored-by: Anthonios Partheniou Co-authored-by: Ilya Gurov Co-authored-by: Astha Mohta <35952883+asthamohta@users.noreply.github.com> --- .../.github/workflows/test_suite.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 9ae088cac137..918e4fbe7cb7 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install nox @@ -27,7 +27,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install nox @@ -51,7 +51,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install nox @@ -75,7 +75,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install nox @@ -99,7 +99,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 - name: Install nox From 8525692327653a4ff102c2aaec0790366a064b70 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 18 Aug 2022 02:47:50 -0700 Subject: [PATCH 156/582] Update README.rst (#233) Closes #230 --- packages/sqlalchemy-spanner/README.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index b4550cd2b0ee..1a0707a7c500 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -158,12 +158,14 @@ primary key: ) As Spanner restricts changing a primary key value, not setting the flag -to ``False`` can cause migration problems. +to ``False`` can cause migration problems. + +Also notice that DDL statements in Spanner are not transactional and will not be automatically reverted in case of a migration fail. | **Warning!** | A migration script can produce a lot of DDL statements. If each of the - statements are executed separately, performance issues can occur. To - avoid these, it's highly recommended to use the `Alembic batch + statements is executed separately, performance issues can occur. To + avoid it, it's highly recommended to use the `Alembic batch context `__ feature to pack DDL statements into groups of statements. From bcdaccd52f5f39f2157c0f90128b556fb7a88e03 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 26 Aug 2022 01:21:19 -0700 Subject: [PATCH 157/582] fix: update dialect name for ALTER operation overrides (#234) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 4 ++-- packages/sqlalchemy-spanner/noxfile.py | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 515056561714..758d6c6df311 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1015,7 +1015,7 @@ def do_execute_no_params(self, cursor, statement, context=None): # Alembic ALTER operation override -@compiles(ColumnNullable, "spanner") +@compiles(ColumnNullable, "spanner+spanner") def visit_column_nullable( element: "ColumnNullable", compiler: "SpannerDDLCompiler", **kw ) -> str: @@ -1028,7 +1028,7 @@ def visit_column_nullable( # Alembic ALTER operation override -@compiles(ColumnType, "spanner") +@compiles(ColumnType, "spanner+spanner") def visit_column_type( element: "ColumnType", compiler: "SpannerDDLCompiler", **kw ) -> str: diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 29d4f20c3b99..693754b61abc 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -65,7 +65,14 @@ class = StreamHandler 'account', 'name', existing_type=sa.String(70), - )""" + ) + op.alter_column( + 'account', + 'description', + existing_type=sa.Unicode(200), + nullable=False, + ) + """ BLACK_VERSION = "black==22.3.0" @@ -254,14 +261,14 @@ def migration_test(session): files = glob.glob("test_migration/versions/*.py") # updating the upgrade-script code - with open(files[0], "r") as f: - script_code = f.read() + with open(files[0], "rb") as f: + script_code = f.read().decode() script_code = script_code.replace( """def upgrade() -> None:\n pass""", UPGRADE_CODE ) - with open(files[0], "w") as f: - f.write(script_code) + with open(files[0], "wb") as f: + f.write(script_code.encode()) os.remove("test_migration/env.py") shutil.copyfile("test_migration_env.py", "test_migration/env.py") From bb31c3ee34b4da5a4ebfecf581374e1f4d16d754 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 29 Aug 2022 00:13:34 -0700 Subject: [PATCH 158/582] Update README.rst (#237) See for more details: https://github.com/googleapis/python-spanner-sqlalchemy/issues/229#issuecomment-1228224509 --- packages/sqlalchemy-spanner/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 1a0707a7c500..5965c3e12dc7 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -157,8 +157,8 @@ primary key: version_table_pk=False, # don't use primary key in the versions table ) -As Spanner restricts changing a primary key value, not setting the flag -to ``False`` can cause migration problems. +As Spanner restricts changing a primary key value, not setting the ``version_table_pk`` flag +to ``False`` can cause migration problems. If ``alembic_versions`` table was already created with a primary key, setting the flag to ``False`` will not work, because the flag is only applied on table creation. Also notice that DDL statements in Spanner are not transactional and will not be automatically reverted in case of a migration fail. From 5092508c2dd70bcbd79ed1149c9b3722af70b4c7 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 30 Aug 2022 00:00:16 -0700 Subject: [PATCH 159/582] =?UTF-8?q?docs:=20mention=20autocommit=5Fblock=20?= =?UTF-8?q?as=20a=20solution=20for=20Aborted=20transaction=20=E2=80=A6=20(?= =?UTF-8?q?#239)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …error during migration Closes #229 --- packages/sqlalchemy-spanner/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 5965c3e12dc7..4812a45bef6e 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -160,7 +160,7 @@ primary key: As Spanner restricts changing a primary key value, not setting the ``version_table_pk`` flag to ``False`` can cause migration problems. If ``alembic_versions`` table was already created with a primary key, setting the flag to ``False`` will not work, because the flag is only applied on table creation. -Also notice that DDL statements in Spanner are not transactional and will not be automatically reverted in case of a migration fail. +Notice that DDL statements in Spanner are not transactional. They will not be automatically reverted in case of a migration fail. Also Spanner encourage use of the `autocommit_block() `__ for migrations in order to prevent DDLs from aborting migration transactions with schema modifications. | **Warning!** | A migration script can produce a lot of DDL statements. If each of the From 91141e590eb9440bce8d00459edbfb24a18f75da Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Fri, 2 Sep 2022 00:03:36 -0700 Subject: [PATCH 160/582] fix: Spanner auto managed indexes should not be introspected (#241) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 ++ packages/sqlalchemy-spanner/test/test_suite_13.py | 7 +++++++ packages/sqlalchemy-spanner/test/test_suite_14.py | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 758d6c6df311..012e6d61eaa4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -689,7 +689,9 @@ def get_indexes(self, connection, table_name, schema=None, **kw): WHERE i.table_name="{table_name}" AND i.index_type != 'PRIMARY_KEY' + AND i.spanner_is_managed = FALSE GROUP BY i.index_name, i.is_unique +ORDER BY i.index_name """.format( table_name=table_name ) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 55d471d33b00..c31cce82aad3 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -939,6 +939,13 @@ def test_array_reflection(self): tab.drop() + def _assert_insp_indexes(self, indexes, expected_indexes): + expected_indexes.sort(key=lambda item: item["name"]) + + index_names = [d["name"] for d in indexes] + exp_index_names = [d["name"] for d in expected_indexes] + assert sorted(index_names) == sorted(exp_index_names) + class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): @testing.requires.foreign_key_constraint_reflection diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 42ca3d967094..5563169e5aa0 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -701,6 +701,13 @@ def test_get_temp_table_unique_constraints(self): def test_get_temp_table_columns(self): pass + def _assert_insp_indexes(self, indexes, expected_indexes): + expected_indexes.sort(key=lambda item: item["name"]) + + index_names = [d["name"] for d in indexes] + exp_index_names = [d["name"] for d in expected_indexes] + assert sorted(index_names) == sorted(exp_index_names) + class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): @testing.requires.foreign_key_constraint_reflection From 432efe47ed5491e30a46ec1ef7a7b928751d4fa5 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Sun, 18 Sep 2022 23:35:47 -0700 Subject: [PATCH 161/582] fix: don't introspect internal UNIQUE constraints (#244) --- packages/sqlalchemy-spanner/create_test_database.py | 2 +- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 0e5a4bf24cac..d5d5978bb849 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -70,7 +70,7 @@ def create_test_instance(): configs = list(CLIENT.list_instance_configs()) if not USE_EMULATOR: # Filter out non "us" locations - configs = [config for config in configs if "-us-" in config.name] + configs = [config for config in configs if "europe-north1" in config.name] instance_config = configs[0].name create_time = str(int(time.time())) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 012e6d61eaa4..bd57daab76b4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -873,7 +873,12 @@ def get_unique_constraints(self, connection, table_name, schema=None, **kw): FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME -WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "UNIQUE" +LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc + on tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME +WHERE + tc.TABLE_NAME="{table_name}" + AND tc.CONSTRAINT_TYPE = "UNIQUE" + AND rc.CONSTRAINT_NAME IS NOT NULL """.format( table_name=table_name ) From e1f870318b45d646c7ce146ce8dacde6b258ea82 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 19 Sep 2022 00:23:06 -0700 Subject: [PATCH 162/582] docs: mention package install with pip (#245) --- packages/sqlalchemy-spanner/README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 4812a45bef6e..c2255664a097 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -37,6 +37,11 @@ steps: Installation ------------ +Stable released version of the package is available on PyPi: + +:: + + pip install sqlalchemy-spanner To install an in-development version of the package, clone its Git-repository: From 90a88d6054988fb1da07478d44ea6fd7637e08c6 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 19 Sep 2022 01:20:23 -0700 Subject: [PATCH 163/582] docs: add auto retry mechanism explanation (#243) --- packages/sqlalchemy-spanner/README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index c2255664a097..8147871cf082 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -263,6 +263,14 @@ Isolation level change example: eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id") autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") +Automatic transactions retry +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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. + +This, however, may require to manually repeat a long list of operations, executed in the failed transaction. To simplify it, Spanner Connection API tracks all the operations, executed inside current transaction, and their result checksums. If the transaction failed with ``Aborted`` exception, the Connection API will automatically start a new transaction and will re-run all the tracked operations, checking if their results are the same as they were in the original transaction. In case data changed, and results differ, the transaction is dropped, as there is no way to automatically retry it. + +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. + Autoincremented IDs ~~~~~~~~~~~~~~~~~~~ From 21300fe441b8d532700fdea8ae3442e68ee63eb8 Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Thu, 29 Sep 2022 21:14:15 +0530 Subject: [PATCH 164/582] fix: adding requirements (#250) * fix:adding requirements * fix: adding requirements to kokoro * fix: adding requirements * update .kokoro/requirements.txt Co-authored-by: Anthonios Partheniou --- packages/sqlalchemy-spanner/.kokoro/build.sh | 1 + .../.kokoro/publish-docs.sh | 1 + .../sqlalchemy-spanner/.kokoro/release.sh | 1 + .../.kokoro/requirements.in | 8 + .../.kokoro/requirements.txt | 499 ++++++++++++++++++ packages/sqlalchemy-spanner/requirements.in | 13 + packages/sqlalchemy-spanner/requirements.txt | 476 +++++++++++++++++ 7 files changed, 999 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.kokoro/requirements.in create mode 100644 packages/sqlalchemy-spanner/.kokoro/requirements.txt create mode 100644 packages/sqlalchemy-spanner/requirements.in create mode 100644 packages/sqlalchemy-spanner/requirements.txt diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index 6f33e29811c8..da86aa22a93c 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -25,6 +25,7 @@ export GOOGLE_CLOUD_PROJECT=$(cat "${KOKORO_GFILE_DIR}/project-id.json") python3 -m pip uninstall --yes --quiet nox-automation # Install nox +python3 -m pip install --require-hashes -r .kokoro/requirements.txt python3 -m pip install --upgrade --quiet nox python3 -m nox --version diff --git a/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh b/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh index 41e4460df98a..e504a188ca65 100755 --- a/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh +++ b/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh @@ -13,6 +13,7 @@ export PYTHONUNBUFFERED=1 export PATH="${HOME}/.local/bin:${PATH}" # Install nox +python3 -m pip install --require-hashes -r requirements.txt python3 -m pip install --user --upgrade --quiet nox python3 -m nox --version diff --git a/packages/sqlalchemy-spanner/.kokoro/release.sh b/packages/sqlalchemy-spanner/.kokoro/release.sh index 6d767c28e79d..2d0cee72b9de 100755 --- a/packages/sqlalchemy-spanner/.kokoro/release.sh +++ b/packages/sqlalchemy-spanner/.kokoro/release.sh @@ -8,6 +8,7 @@ set -eo pipefail # Start the releasetool reporter +python3 -m pip install --require-hashes -r github/python-spanner-sqlalchemy/.kokoro/requirements.txt python3 -m pip install gcp-releasetool python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in new file mode 100644 index 000000000000..689b5ee187f8 --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.in @@ -0,0 +1,8 @@ +gcp-docuploader +gcp-releasetool +importlib-metadata +typing-extensions +twine +wheel +setuptools +nox diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt new file mode 100644 index 000000000000..ab2b6d5e83ac --- /dev/null +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -0,0 +1,499 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --generate-hashes requirements.in +# +argcomplete==2.0.0 \ + --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ + --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e + # via nox +attrs==22.1.0 \ + --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ + --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c + # via gcp-releasetool +bleach==5.0.1 \ + --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ + --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c + # via readme-renderer +cachetools==5.2.0 \ + --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ + --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db + # via google-auth +certifi==2022.9.24 \ + --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \ + --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382 + # via requests +cffi==1.15.1 \ + --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ + --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ + --hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \ + --hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \ + --hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \ + --hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \ + --hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \ + --hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \ + --hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \ + --hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \ + --hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \ + --hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \ + --hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \ + --hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \ + --hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \ + --hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \ + --hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \ + --hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \ + --hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \ + --hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \ + --hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \ + --hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \ + --hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \ + --hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \ + --hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \ + --hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \ + --hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \ + --hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \ + --hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \ + --hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \ + --hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \ + --hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \ + --hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \ + --hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \ + --hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \ + --hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \ + --hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \ + --hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \ + --hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \ + --hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \ + --hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \ + --hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \ + --hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \ + --hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \ + --hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \ + --hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \ + --hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \ + --hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \ + --hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \ + --hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \ + --hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \ + --hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \ + --hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \ + --hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \ + --hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \ + --hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \ + --hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \ + --hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \ + --hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \ + --hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \ + --hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \ + --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ + --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ + --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 + # via cryptography +charset-normalizer==2.1.1 \ + --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ + --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f + # via requests +click==8.0.4 \ + --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ + --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb + # via + # gcp-docuploader + # gcp-releasetool +colorlog==6.7.0 \ + --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ + --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 + # via + # gcp-docuploader + # nox +commonmark==0.9.1 \ + --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ + --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 + # via rich +cryptography==38.0.1 \ + --hash=sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a \ + --hash=sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f \ + --hash=sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0 \ + --hash=sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407 \ + --hash=sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7 \ + --hash=sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6 \ + --hash=sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153 \ + --hash=sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750 \ + --hash=sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad \ + --hash=sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6 \ + --hash=sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b \ + --hash=sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5 \ + --hash=sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a \ + --hash=sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d \ + --hash=sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d \ + --hash=sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294 \ + --hash=sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0 \ + --hash=sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a \ + --hash=sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac \ + --hash=sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61 \ + --hash=sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013 \ + --hash=sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e \ + --hash=sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb \ + --hash=sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9 \ + --hash=sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd \ + --hash=sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818 + # via + # gcp-releasetool + # secretstorage +distlib==0.3.6 \ + --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ + --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e + # via virtualenv +docutils==0.19 \ + --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ + --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc + # via readme-renderer +filelock==3.8.0 \ + --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ + --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 + # via virtualenv +gcp-docuploader==0.6.3 \ + --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ + --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b + # via -r requirements.in +gcp-releasetool==1.8.8 \ + --hash=sha256:0e235a63b290e94554eac9906283275859816e8201bacb06c88870608f91515c \ + --hash=sha256:2e6ea4407a64bb4903b037a9fc63e01d09225a88be1097439535f5eda21aeea9 + # via -r requirements.in +google-api-core==2.10.1 \ + --hash=sha256:92d17123cfe399b5ef7e026c63babf978d8475e1ac877919eb7933e25dea2273 \ + --hash=sha256:e16c15a11789bc5a3457afb2818a3540a03f341e6e710d7f9bbf6cde2ef4a7c8 + # via + # google-cloud-core + # google-cloud-storage +google-auth==2.11.1 \ + --hash=sha256:516e6623038b81430dd062a1a25ecd24f173d7c15cdf4e48a9e78bc87e97aeec \ + --hash=sha256:53bdc0c2b4e25895575779caef4cfb3a6bdff1b7b32dc38a654d71aba35bb5f8 + # via + # gcp-releasetool + # google-api-core + # google-cloud-core + # google-cloud-storage +google-cloud-core==2.3.2 \ + --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ + --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a + # via google-cloud-storage +google-cloud-storage==2.5.0 \ + --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ + --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 + # via gcp-docuploader +google-crc32c==1.5.0 \ + --hash=sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a \ + --hash=sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876 \ + --hash=sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c \ + --hash=sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289 \ + --hash=sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298 \ + --hash=sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02 \ + --hash=sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f \ + --hash=sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2 \ + --hash=sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a \ + --hash=sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb \ + --hash=sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210 \ + --hash=sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5 \ + --hash=sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee \ + --hash=sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c \ + --hash=sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a \ + --hash=sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314 \ + --hash=sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd \ + --hash=sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65 \ + --hash=sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37 \ + --hash=sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4 \ + --hash=sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13 \ + --hash=sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894 \ + --hash=sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31 \ + --hash=sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e \ + --hash=sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709 \ + --hash=sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740 \ + --hash=sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc \ + --hash=sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d \ + --hash=sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c \ + --hash=sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c \ + --hash=sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d \ + --hash=sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906 \ + --hash=sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61 \ + --hash=sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57 \ + --hash=sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c \ + --hash=sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a \ + --hash=sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438 \ + --hash=sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946 \ + --hash=sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7 \ + --hash=sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96 \ + --hash=sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091 \ + --hash=sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae \ + --hash=sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d \ + --hash=sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88 \ + --hash=sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2 \ + --hash=sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd \ + --hash=sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541 \ + --hash=sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728 \ + --hash=sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178 \ + --hash=sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968 \ + --hash=sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346 \ + --hash=sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8 \ + --hash=sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93 \ + --hash=sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7 \ + --hash=sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273 \ + --hash=sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462 \ + --hash=sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94 \ + --hash=sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd \ + --hash=sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e \ + --hash=sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57 \ + --hash=sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b \ + --hash=sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9 \ + --hash=sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a \ + --hash=sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100 \ + --hash=sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325 \ + --hash=sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183 \ + --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ + --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 + # via google-resumable-media +google-resumable-media==2.3.3 \ + --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ + --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 + # via google-cloud-storage +googleapis-common-protos==1.56.4 \ + --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ + --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 + # via google-api-core +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via requests +importlib-metadata==4.12.0 \ + --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ + --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 + # via + # -r requirements.in + # twine +jaraco-classes==3.2.3 \ + --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ + --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a + # via keyring +jeepney==0.8.0 \ + --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ + --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via + # keyring + # secretstorage +jinja2==3.1.2 \ + --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ + --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 + # via gcp-releasetool +keyring==23.9.3 \ + --hash=sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0 \ + --hash=sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5 + # via + # gcp-releasetool + # twine +markupsafe==2.1.1 \ + --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ + --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ + --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ + --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ + --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ + --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ + --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ + --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ + --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ + --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ + --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ + --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ + --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ + --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ + --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ + --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ + --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ + --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ + --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ + --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ + --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ + --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ + --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ + --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ + --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ + --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ + --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ + --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ + --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ + --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ + --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ + --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ + --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ + --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ + --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ + --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ + --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ + --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ + --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ + --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 + # via jinja2 +more-itertools==8.14.0 \ + --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ + --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 + # via jaraco-classes +nox==2022.8.7 \ + --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ + --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c + # via -r requirements.in +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 + # via + # gcp-releasetool + # nox +pkginfo==1.8.3 \ + --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ + --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c + # via twine +platformdirs==2.5.2 \ + --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ + --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 + # via virtualenv +protobuf==3.20.2 \ + --hash=sha256:03d76b7bd42ac4a6e109742a4edf81ffe26ffd87c5993126d894fe48a120396a \ + --hash=sha256:09e25909c4297d71d97612f04f41cea8fa8510096864f2835ad2f3b3df5a5559 \ + --hash=sha256:18e34a10ae10d458b027d7638a599c964b030c1739ebd035a1dfc0e22baa3bfe \ + --hash=sha256:291fb4307094bf5ccc29f424b42268640e00d5240bf0d9b86bf3079f7576474d \ + --hash=sha256:2c0b040d0b5d5d207936ca2d02f00f765906622c07d3fa19c23a16a8ca71873f \ + --hash=sha256:384164994727f274cc34b8abd41a9e7e0562801361ee77437099ff6dfedd024b \ + --hash=sha256:3cb608e5a0eb61b8e00fe641d9f0282cd0eedb603be372f91f163cbfbca0ded0 \ + --hash=sha256:5d9402bf27d11e37801d1743eada54372f986a372ec9679673bfcc5c60441151 \ + --hash=sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750 \ + --hash=sha256:7a5037af4e76c975b88c3becdf53922b5ffa3f2cddf657574a4920a3b33b80f3 \ + --hash=sha256:8228e56a865c27163d5d1d1771d94b98194aa6917bcfb6ce139cbfa8e3c27334 \ + --hash=sha256:84a1544252a933ef07bb0b5ef13afe7c36232a774affa673fc3636f7cee1db6c \ + --hash=sha256:84fe5953b18a383fd4495d375fe16e1e55e0a3afe7b4f7b4d01a3a0649fcda9d \ + --hash=sha256:9c673c8bfdf52f903081816b9e0e612186684f4eb4c17eeb729133022d6032e3 \ + --hash=sha256:9f876a69ca55aed879b43c295a328970306e8e80a263ec91cf6e9189243c613b \ + --hash=sha256:a9e5ae5a8e8985c67e8944c23035a0dff2c26b0f5070b2f55b217a1c33bbe8b1 \ + --hash=sha256:b4fdb29c5a7406e3f7ef176b2a7079baa68b5b854f364c21abe327bbeec01cdb \ + --hash=sha256:c184485e0dfba4dfd451c3bd348c2e685d6523543a0f91b9fd4ae90eb09e8422 \ + --hash=sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019 \ + --hash=sha256:e39cf61bb8582bda88cdfebc0db163b774e7e03364bbf9ce1ead13863e81e359 \ + --hash=sha256:e8fbc522303e09036c752a0afcc5c0603e917222d8bedc02813fd73b4b4ed804 \ + --hash=sha256:f34464ab1207114e73bba0794d1257c150a2b89b7a9faf504e00af7c9fd58978 \ + --hash=sha256:f52dabc96ca99ebd2169dadbe018824ebda08a795c7684a0b7d203a290f3adb0 + # via + # gcp-docuploader + # gcp-releasetool + # google-api-core + # googleapis-common-protos +py==1.11.0 \ + --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ + --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 + # via nox +pyasn1==0.4.8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 + # via google-auth +pycparser==2.21 \ + --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ + --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 + # via cffi +pygments==2.13.0 \ + --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ + --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 + # via + # readme-renderer + # rich +pyjwt==2.5.0 \ + --hash=sha256:8d82e7087868e94dd8d7d418e5088ce64f7daab4b36db654cbaedb46f9d1ca80 \ + --hash=sha256:e77ab89480905d86998442ac5788f35333fa85f65047a534adc38edf3c88fc3b + # via gcp-releasetool +pyparsing==3.0.9 \ + --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ + --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc + # via packaging +pyperclip==1.8.2 \ + --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 + # via gcp-releasetool +python-dateutil==2.8.2 \ + --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ + --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 + # via gcp-releasetool +readme-renderer==37.2 \ + --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ + --hash=sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923 + # via twine +requests==2.28.1 \ + --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ + --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 + # via + # gcp-releasetool + # google-api-core + # google-cloud-storage + # requests-toolbelt + # twine +requests-toolbelt==0.9.1 \ + --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ + --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 + # via twine +rfc3986==2.0.0 \ + --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ + --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c + # via twine +rich==12.5.1 \ + --hash=sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb \ + --hash=sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca + # via twine +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via google-auth +secretstorage==3.3.3 \ + --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ + --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 + # via keyring +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # bleach + # gcp-docuploader + # google-auth + # python-dateutil +twine==4.0.1 \ + --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ + --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 + # via -r requirements.in +typing-extensions==4.3.0 \ + --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ + --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 + # via -r requirements.in +urllib3==1.26.12 \ + --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ + --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via + # requests + # twine +virtualenv==20.16.5 \ + --hash=sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da \ + --hash=sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27 + # via nox +webencodings==0.5.1 \ + --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ + --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 + # via bleach +wheel==0.37.1 \ + --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ + --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 + # via -r requirements.in +zipp==3.8.1 \ + --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ + --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 + # via importlib-metadata + +# WARNING: The following packages were not pinned, but pip requires them to be +# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# setuptools diff --git a/packages/sqlalchemy-spanner/requirements.in b/packages/sqlalchemy-spanner/requirements.in new file mode 100644 index 000000000000..fad90d0391be --- /dev/null +++ b/packages/sqlalchemy-spanner/requirements.in @@ -0,0 +1,13 @@ +build +click +packaging +pep517 +pip-tools +pyparsing +tomli +sqlalchemy +google-cloud-spanner +alembic +opentelemetry-api +opentelemetry-sdk +opentelemetry-instrumentation diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt new file mode 100644 index 000000000000..3d92e70bfb5d --- /dev/null +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -0,0 +1,476 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile --generate-hashes +# +alembic==1.8.1 \ + --hash=sha256:0a024d7f2de88d738d7395ff866997314c837be6104e90c5724350313dee4da4 \ + --hash=sha256:cd0b5e45b14b706426b833f06369b9a6d5ee03f826ec3238723ce8caaf6e5ffa + # via -r requirements.in +build==0.8.0 \ + --hash=sha256:19b0ed489f92ace6947698c3ca8436cb0556a66e2aa2d34cd70e2a5d27cd0437 \ + --hash=sha256:887a6d471c901b1a6e6574ebaeeebb45e5269a79d095fe9a8f88d6614ed2e5f0 + # via + # -r requirements.in + # pip-tools +cachetools==5.2.0 \ + --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ + --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db + # via google-auth +certifi==2022.9.24 \ + --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \ + --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382 + # via requests +charset-normalizer==2.1.1 \ + --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ + --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f + # via requests +click==8.1.3 \ + --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ + --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 + # via + # -r requirements.in + # pip-tools +deprecated==1.2.13 \ + --hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \ + --hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d + # via opentelemetry-api +google-api-core[grpc]==2.10.1 \ + --hash=sha256:92d17123cfe399b5ef7e026c63babf978d8475e1ac877919eb7933e25dea2273 \ + --hash=sha256:e16c15a11789bc5a3457afb2818a3540a03f341e6e710d7f9bbf6cde2ef4a7c8 + # via + # google-cloud-core + # google-cloud-spanner +google-auth==2.11.1 \ + --hash=sha256:516e6623038b81430dd062a1a25ecd24f173d7c15cdf4e48a9e78bc87e97aeec \ + --hash=sha256:53bdc0c2b4e25895575779caef4cfb3a6bdff1b7b32dc38a654d71aba35bb5f8 + # via + # google-api-core + # google-cloud-core +google-cloud-core==2.3.2 \ + --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ + --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a + # via google-cloud-spanner +google-cloud-spanner==3.22.0 \ + --hash=sha256:2a57d163521503b6cd41ae558a29ecea2d5e707dfaf6fe9c5530926194b0992f \ + --hash=sha256:dc464c53217d49ef830f710ad3fb2b60e0d1268f0e42402be518a54db3131c8a + # via -r requirements.in +googleapis-common-protos[grpc]==1.56.4 \ + --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ + --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 + # via + # google-api-core + # grpc-google-iam-v1 + # grpcio-status +greenlet==1.1.3 \ + --hash=sha256:0118817c9341ef2b0f75f5af79ac377e4da6ff637e5ee4ac91802c0e379dadb4 \ + --hash=sha256:048d2bed76c2aa6de7af500ae0ea51dd2267aec0e0f2a436981159053d0bc7cc \ + --hash=sha256:07c58e169bbe1e87b8bbf15a5c1b779a7616df9fd3e61cadc9d691740015b4f8 \ + --hash=sha256:095a980288fe05adf3d002fbb180c99bdcf0f930e220aa66fcd56e7914a38202 \ + --hash=sha256:0b181e9aa6cb2f5ec0cacc8cee6e5a3093416c841ba32c185c30c160487f0380 \ + --hash=sha256:1626185d938d7381631e48e6f7713e8d4b964be246073e1a1d15c2f061ac9f08 \ + --hash=sha256:184416e481295832350a4bf731ba619a92f5689bf5d0fa4341e98b98b1265bd7 \ + --hash=sha256:1dd51d2650e70c6c4af37f454737bf4a11e568945b27f74b471e8e2a9fd21268 \ + --hash=sha256:1ec2779774d8e42ed0440cf8bc55540175187e8e934f2be25199bf4ed948cd9e \ + --hash=sha256:2cf45e339cabea16c07586306a31cfcc5a3b5e1626d365714d283732afed6809 \ + --hash=sha256:2fb0aa7f6996879551fd67461d5d3ab0c3c0245da98be90c89fcb7a18d437403 \ + --hash=sha256:44b4817c34c9272c65550b788913620f1fdc80362b209bc9d7dd2f40d8793080 \ + --hash=sha256:466ce0928e33421ee84ae04c4ac6f253a3a3e6b8d600a79bd43fd4403e0a7a76 \ + --hash=sha256:4f166b4aca8d7d489e82d74627a7069ab34211ef5ebb57c300ec4b9337b60fc0 \ + --hash=sha256:510c3b15587afce9800198b4b142202b323bf4b4b5f9d6c79cb9a35e5e3c30d2 \ + --hash=sha256:5b756e6730ea59b2745072e28ad27f4c837084688e6a6b3633c8b1e509e6ae0e \ + --hash=sha256:5fbe1ab72b998ca77ceabbae63a9b2e2dc2d963f4299b9b278252ddba142d3f1 \ + --hash=sha256:6200a11f003ec26815f7e3d2ded01b43a3810be3528dd760d2f1fa777490c3cd \ + --hash=sha256:65ad1a7a463a2a6f863661329a944a5802c7129f7ad33583dcc11069c17e622c \ + --hash=sha256:694ffa7144fa5cc526c8f4512665003a39fa09ef00d19bbca5c8d3406db72fbe \ + --hash=sha256:6f5d4b2280ceea76c55c893827961ed0a6eadd5a584a7c4e6e6dd7bc10dfdd96 \ + --hash=sha256:7532a46505470be30cbf1dbadb20379fb481244f1ca54207d7df3bf0bbab6a20 \ + --hash=sha256:76a53bfa10b367ee734b95988bd82a9a5f0038a25030f9f23bbbc005010ca600 \ + --hash=sha256:77e41db75f9958f2083e03e9dd39da12247b3430c92267df3af77c83d8ff9eed \ + --hash=sha256:7a43bbfa9b6cfdfaeefbd91038dde65ea2c421dc387ed171613df340650874f2 \ + --hash=sha256:7b41d19c0cfe5c259fe6c539fd75051cd39a5d33d05482f885faf43f7f5e7d26 \ + --hash=sha256:7c5227963409551ae4a6938beb70d56bf1918c554a287d3da6853526212fbe0a \ + --hash=sha256:870a48007872d12e95a996fca3c03a64290d3ea2e61076aa35d3b253cf34cd32 \ + --hash=sha256:88b04e12c9b041a1e0bcb886fec709c488192638a9a7a3677513ac6ba81d8e79 \ + --hash=sha256:8c287ae7ac921dfde88b1c125bd9590b7ec3c900c2d3db5197f1286e144e712b \ + --hash=sha256:903fa5716b8fbb21019268b44f73f3748c41d1a30d71b4a49c84b642c2fed5fa \ + --hash=sha256:9537e4baf0db67f382eb29255a03154fcd4984638303ff9baaa738b10371fa57 \ + --hash=sha256:9951dcbd37850da32b2cb6e391f621c1ee456191c6ae5528af4a34afe357c30e \ + --hash=sha256:9b2f7d0408ddeb8ea1fd43d3db79a8cefaccadd2a812f021333b338ed6b10aba \ + --hash=sha256:9c88e134d51d5e82315a7c32b914a58751b7353eb5268dbd02eabf020b4c4700 \ + --hash=sha256:9fae214f6c43cd47f7bef98c56919b9222481e833be2915f6857a1e9e8a15318 \ + --hash=sha256:a3a669f11289a8995d24fbfc0e63f8289dd03c9aaa0cc8f1eab31d18ca61a382 \ + --hash=sha256:aa741c1a8a8cc25eb3a3a01a62bdb5095a773d8c6a86470bde7f607a447e7905 \ + --hash=sha256:b0877a9a2129a2c56a2eae2da016743db7d9d6a05d5e1c198f1b7808c602a30e \ + --hash=sha256:bcb6c6dd1d6be6d38d6db283747d07fda089ff8c559a835236560a4410340455 \ + --hash=sha256:caff52cb5cd7626872d9696aee5b794abe172804beb7db52eed1fd5824b63910 \ + --hash=sha256:cbc1eb55342cbac8f7ec159088d54e2cfdd5ddf61c87b8bbe682d113789331b2 \ + --hash=sha256:cd16a89efe3a003029c87ff19e9fba635864e064da646bc749fc1908a4af18f3 \ + --hash=sha256:ce5b64dfe8d0cca407d88b0ee619d80d4215a2612c1af8c98a92180e7109f4b5 \ + --hash=sha256:d58a5a71c4c37354f9e0c24c9c8321f0185f6945ef027460b809f4bb474bfe41 \ + --hash=sha256:db41f3845eb579b544c962864cce2c2a0257fe30f0f1e18e51b1e8cbb4e0ac6d \ + --hash=sha256:db5b25265010a1b3dca6a174a443a0ed4c4ab12d5e2883a11c97d6e6d59b12f9 \ + --hash=sha256:dd0404d154084a371e6d2bafc787201612a1359c2dee688ae334f9118aa0bf47 \ + --hash=sha256:de431765bd5fe62119e0bc6bc6e7b17ac53017ae1782acf88fcf6b7eae475a49 \ + --hash=sha256:df02fdec0c533301497acb0bc0f27f479a3a63dcdc3a099ae33a902857f07477 \ + --hash=sha256:e8533f5111704d75de3139bf0b8136d3a6c1642c55c067866fa0a51c2155ee33 \ + --hash=sha256:f2f908239b7098799b8845e5936c2ccb91d8c2323be02e82f8dcb4a80dcf4a25 \ + --hash=sha256:f8bfd36f368efe0ab2a6aa3db7f14598aac454b06849fb633b762ddbede1db90 \ + --hash=sha256:ffe73f9e7aea404722058405ff24041e59d31ca23d1da0895af48050a07b6932 + # via sqlalchemy +grpc-google-iam-v1==0.12.4 \ + --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ + --hash=sha256:3f0ac2c940b9a855d7ce7e31fde28bddb0d9ac362d32d07c67148306931a0e30 + # via google-cloud-spanner +grpcio==1.49.1 \ + --hash=sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f \ + --hash=sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394 \ + --hash=sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad \ + --hash=sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3 \ + --hash=sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b \ + --hash=sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62 \ + --hash=sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df \ + --hash=sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed \ + --hash=sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede \ + --hash=sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af \ + --hash=sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492 \ + --hash=sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f \ + --hash=sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c \ + --hash=sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705 \ + --hash=sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8 \ + --hash=sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146 \ + --hash=sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201 \ + --hash=sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811 \ + --hash=sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf \ + --hash=sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68 \ + --hash=sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc \ + --hash=sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568 \ + --hash=sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e \ + --hash=sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2 \ + --hash=sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d \ + --hash=sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7 \ + --hash=sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62 \ + --hash=sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd \ + --hash=sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a \ + --hash=sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b \ + --hash=sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c \ + --hash=sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62 \ + --hash=sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd \ + --hash=sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534 \ + --hash=sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f \ + --hash=sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b \ + --hash=sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d \ + --hash=sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f \ + --hash=sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f \ + --hash=sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2 \ + --hash=sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3 \ + --hash=sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788 \ + --hash=sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde \ + --hash=sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20 \ + --hash=sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f + # via + # google-api-core + # googleapis-common-protos + # grpc-google-iam-v1 + # grpcio-status +grpcio-status==1.49.1 \ + --hash=sha256:658f48dc146ee0c7b6eebd302d74e0d45c00727c20035ff51d68750dbaccf5d9 \ + --hash=sha256:fe4ae9f624f03e50ccf6f6ead60727ab20b17735bb3d0dd506ef355349282378 + # via google-api-core +idna==3.4 \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 + # via requests +importlib-metadata==4.12.0 \ + --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ + --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 + # via alembic +importlib-resources==5.9.0 \ + --hash=sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681 \ + --hash=sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7 + # via alembic +mako==1.2.3 \ + --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ + --hash=sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f + # via alembic +markupsafe==2.1.1 \ + --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ + --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ + --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ + --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ + --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ + --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ + --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ + --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ + --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ + --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ + --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ + --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ + --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ + --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ + --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ + --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ + --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ + --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ + --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ + --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ + --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ + --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ + --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ + --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ + --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ + --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ + --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ + --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ + --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ + --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ + --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ + --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ + --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ + --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ + --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ + --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ + --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ + --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ + --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ + --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 + # via mako +opentelemetry-api==1.13.0 \ + --hash=sha256:2db1e8713f48a119bae457cd22304a7919d5e57190a380485c442c4f731a46dd \ + --hash=sha256:e683e869471b99e77238c8739d6ee2f368803329f3b808dfa86a02d0b519c682 + # via + # -r requirements.in + # opentelemetry-instrumentation + # opentelemetry-sdk +opentelemetry-instrumentation==0.33b0 \ + --hash=sha256:763eb288b1c0fff9f6baa5494752cc9997f1f03ae3b03dd1fe0d667b1a04eecf \ + --hash=sha256:90f1eff6e134ad6c1fc2cbd8e0b652c5057deed7b567bfcb40150d8001742161 + # via -r requirements.in +opentelemetry-sdk==1.13.0 \ + --hash=sha256:0eddcacd5a484fe2918116b9a4e31867e3d10322ff8392b1c7b0dae1ac724d48 \ + --hash=sha256:c7b88e06ebedd22c226b374c207792d30b3f34074a6b8ad8c6dad04a8d16326b + # via -r requirements.in +opentelemetry-semantic-conventions==0.34b0 \ + --hash=sha256:0c88a5d1f45b820272e0c421fd52ff2188b74582b1bab7ba0f57891dc2f31edf \ + --hash=sha256:b236bd027d2d470c5f7f7a466676182c7e02f486db8296caca25fae0649c3fa3 + # via opentelemetry-sdk +packaging==21.3 \ + --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ + --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 + # via + # -r requirements.in + # build + # google-cloud-spanner +pep517==0.13.0 \ + --hash=sha256:4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b \ + --hash=sha256:ae69927c5c172be1add9203726d4b84cf3ebad1edcd5f71fcdc746e66e829f59 + # via + # -r requirements.in + # build +pip-tools==6.8.0 \ + --hash=sha256:39e8aee465446e02278d80dbebd4325d1dd8633248f43213c73a25f58e7d8a55 \ + --hash=sha256:3e5cd4acbf383d19bdfdeab04738b6313ebf4ad22ce49bf529c729061eabfab8 + # via -r requirements.in +proto-plus==1.22.1 \ + --hash=sha256:6c7dfd122dfef8019ff654746be4f5b1d9c80bba787fe9611b508dd88be3a2fa \ + --hash=sha256:ea8982669a23c379f74495bc48e3dcb47c822c484ce8ee1d1d7beb339d4e34c5 + # via google-cloud-spanner +protobuf==4.21.6 \ + --hash=sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9 \ + --hash=sha256:308173d3e5a3528787bb8c93abea81d5a950bdce62840d9760effc84127fb39c \ + --hash=sha256:4143513c766db85b9d7c18dbf8339673c8a290131b2a0fe73855ab20770f72b0 \ + --hash=sha256:49f88d56a9180dbb7f6199c920f5bb5c1dd0172f672983bb281298d57c2ac8eb \ + --hash=sha256:6b1040a5661cd5f6e610cbca9cfaa2a17d60e2bb545309bc1b278bb05be44bdd \ + --hash=sha256:77b355c8604fe285536155286b28b0c4cbc57cf81b08d8357bf34829ea982860 \ + --hash=sha256:7a6cc8842257265bdfd6b74d088b829e44bcac3cca234c5fdd6052730017b9ea \ + --hash=sha256:80e6540381080715fddac12690ee42d087d0d17395f8d0078dfd6f1181e7be4c \ + --hash=sha256:8f9e60f7d44592c66e7b332b6a7b4b6e8d8b889393c79dbc3a91f815118f8eac \ + --hash=sha256:9666da97129138585b26afcb63ad4887f602e169cafe754a8258541c553b8b5d \ + --hash=sha256:aa29113ec901281f29d9d27b01193407a98aa9658b8a777b0325e6d97149f5ce \ + --hash=sha256:b6cea204865595a92a7b240e4b65bcaaca3ad5d2ce25d9db3756eba06041138e \ + --hash=sha256:ba596b9ffb85c909fcfe1b1a23136224ed678af3faf9912d3fa483d5f9813c4e \ + --hash=sha256:c7c864148a237f058c739ae7a05a2b403c0dfa4ce7d1f3e5213f352ad52d57c6 + # via + # google-api-core + # google-cloud-spanner + # googleapis-common-protos + # grpcio-status + # proto-plus +pyasn1==0.4.8 \ + --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ + --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 \ + --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ + --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 + # via google-auth +pyparsing==3.0.9 \ + --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ + --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc + # via + # -r requirements.in + # packaging +requests==2.28.1 \ + --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ + --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 + # via google-api-core +rsa==4.9 \ + --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ + --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 + # via google-auth +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # google-auth + # grpcio +sqlalchemy==1.4.41 \ + --hash=sha256:0002e829142b2af00b4eaa26c51728f3ea68235f232a2e72a9508a3116bd6ed0 \ + --hash=sha256:0005bd73026cd239fc1e8ccdf54db58b6193be9a02b3f0c5983808f84862c767 \ + --hash=sha256:0292f70d1797e3c54e862e6f30ae474014648bc9c723e14a2fda730adb0a9791 \ + --hash=sha256:036d8472356e1d5f096c5e0e1a7e0f9182140ada3602f8fff6b7329e9e7cfbcd \ + --hash=sha256:05f0de3a1dc3810a776275763764bb0015a02ae0f698a794646ebc5fb06fad33 \ + --hash=sha256:0990932f7cca97fece8017414f57fdd80db506a045869d7ddf2dda1d7cf69ecc \ + --hash=sha256:13e397a9371ecd25573a7b90bd037db604331cf403f5318038c46ee44908c44d \ + --hash=sha256:14576238a5f89bcf504c5f0a388d0ca78df61fb42cb2af0efe239dc965d4f5c9 \ + --hash=sha256:199a73c31ac8ea59937cc0bf3dfc04392e81afe2ec8a74f26f489d268867846c \ + --hash=sha256:2082a2d2fca363a3ce21cfa3d068c5a1ce4bf720cf6497fb3a9fc643a8ee4ddd \ + --hash=sha256:22ff16cedab5b16a0db79f1bc99e46a6ddececb60c396562e50aab58ddb2871c \ + --hash=sha256:2307495d9e0ea00d0c726be97a5b96615035854972cc538f6e7eaed23a35886c \ + --hash=sha256:2ad2b727fc41c7f8757098903f85fafb4bf587ca6605f82d9bf5604bd9c7cded \ + --hash=sha256:2d6495f84c4fd11584f34e62f9feec81bf373787b3942270487074e35cbe5330 \ + --hash=sha256:361f6b5e3f659e3c56ea3518cf85fbdae1b9e788ade0219a67eeaaea8a4e4d2a \ + --hash=sha256:3e2ef592ac3693c65210f8b53d0edcf9f4405925adcfc031ff495e8d18169682 \ + --hash=sha256:4676d51c9f6f6226ae8f26dc83ec291c088fe7633269757d333978df78d931ab \ + --hash=sha256:4ba7e122510bbc07258dc42be6ed45997efdf38129bde3e3f12649be70683546 \ + --hash=sha256:5102fb9ee2c258a2218281adcb3e1918b793c51d6c2b4666ce38c35101bb940e \ + --hash=sha256:5323252be2bd261e0aa3f33cb3a64c45d76829989fa3ce90652838397d84197d \ + --hash=sha256:58bb65b3274b0c8a02cea9f91d6f44d0da79abc993b33bdedbfec98c8440175a \ + --hash=sha256:59bdc291165b6119fc6cdbc287c36f7f2859e6051dd923bdf47b4c55fd2f8bd0 \ + --hash=sha256:5facb7fd6fa8a7353bbe88b95695e555338fb038ad19ceb29c82d94f62775a05 \ + --hash=sha256:639e1ae8d48b3c86ffe59c0daa9a02e2bfe17ca3d2b41611b30a0073937d4497 \ + --hash=sha256:8eb8897367a21b578b26f5713833836f886817ee2ffba1177d446fa3f77e67c8 \ + --hash=sha256:90484a2b00baedad361402c257895b13faa3f01780f18f4a104a2f5c413e4536 \ + --hash=sha256:9c56e19780cd1344fcd362fd6265a15f48aa8d365996a37fab1495cae8fcd97d \ + --hash=sha256:b67fc780cfe2b306180e56daaa411dd3186bf979d50a6a7c2a5b5036575cbdbb \ + --hash=sha256:c0dcf127bb99458a9d211e6e1f0f3edb96c874dd12f2503d4d8e4f1fd103790b \ + --hash=sha256:c23d64a0b28fc78c96289ffbd0d9d1abd48d267269b27f2d34e430ea73ce4b26 \ + --hash=sha256:ccfd238f766a5bb5ee5545a62dd03f316ac67966a6a658efb63eeff8158a4bbf \ + --hash=sha256:cd767cf5d7252b1c88fcfb58426a32d7bd14a7e4942497e15b68ff5d822b41ad \ + --hash=sha256:ce8feaa52c1640de9541eeaaa8b5fb632d9d66249c947bb0d89dd01f87c7c288 \ + --hash=sha256:d2e054aed4645f9b755db85bc69fc4ed2c9020c19c8027976f66576b906a74f1 \ + --hash=sha256:e16c2be5cb19e2c08da7bd3a87fed2a0d4e90065ee553a940c4fc1a0fb1ab72b \ + --hash=sha256:e4b12e3d88a8fffd0b4ca559f6d4957ed91bd4c0613a4e13846ab8729dc5c251 \ + --hash=sha256:e570cfc40a29d6ad46c9aeaddbdcee687880940a3a327f2c668dd0e4ef0a441d \ + --hash=sha256:eb30cf008850c0a26b72bd1b9be6730830165ce049d239cfdccd906f2685f892 \ + --hash=sha256:f37fa70d95658763254941ddd30ecb23fc4ec0c5a788a7c21034fc2305dab7cc \ + --hash=sha256:f5ebeeec5c14533221eb30bad716bc1fd32f509196318fb9caa7002c4a364e4c \ + --hash=sha256:f5fa526d027d804b1f85cdda1eb091f70bde6fb7d87892f6dd5a48925bc88898 + # via + # -r requirements.in + # alembic +sqlparse==0.4.3 \ + --hash=sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34 \ + --hash=sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268 + # via google-cloud-spanner +tomli==2.0.1 \ + --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ + --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f + # via + # -r requirements.in + # build + # pep517 +typing-extensions==4.3.0 \ + --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ + --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 + # via opentelemetry-sdk +urllib3==1.26.12 \ + --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ + --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via requests +wheel==0.37.1 \ + --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ + --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 + # via pip-tools +wrapt==1.14.1 \ + --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ + --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \ + --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \ + --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \ + --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \ + --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \ + --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \ + --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \ + --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \ + --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \ + --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \ + --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \ + --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \ + --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \ + --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \ + --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \ + --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \ + --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \ + --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \ + --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \ + --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \ + --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \ + --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \ + --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \ + --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \ + --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \ + --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \ + --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \ + --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \ + --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \ + --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \ + --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \ + --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \ + --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \ + --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \ + --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \ + --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \ + --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \ + --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \ + --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \ + --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \ + --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \ + --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \ + --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \ + --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \ + --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \ + --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \ + --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \ + --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \ + --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \ + --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \ + --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \ + --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \ + --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \ + --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \ + --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \ + --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \ + --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \ + --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \ + --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \ + --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \ + --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \ + --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \ + --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af + # via + # deprecated + # opentelemetry-instrumentation +zipp==3.8.1 \ + --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ + --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 + # via + # importlib-metadata + # importlib-resources + +# WARNING: The following packages were not pinned, but pip requires them to be +# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# pip +# setuptools From 1e592fa6147b2705622f428f9a5e65042e2727f9 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 3 Oct 2022 07:04:10 +0200 Subject: [PATCH 165/582] chore(deps): update dependency rich to v12.6.0 (#259) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ab2b6d5e83ac..69e987011b00 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -443,9 +443,9 @@ rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==12.5.1 \ - --hash=sha256:2eb4e6894cde1e017976d2975ac210ef515d7548bc595ba20e195fb9628acdeb \ - --hash=sha256:63a5c5ce3673d3d5fbbf23cd87e11ab84b6b451436f1b7f19ec54b6bc36ed7ca +rich==12.6.0 \ + --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ + --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 # via twine rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ From 90a759b67f3e56907c173c4d375abd149b347ae4 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 3 Oct 2022 07:56:16 +0200 Subject: [PATCH 166/582] chore(deps): update dependency importlib-metadata to v5 (#257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [importlib-metadata](https://togithub.com/python/importlib_metadata) | `==4.12.0` -> `==5.0.0` | [![age](https://badges.renovateapi.com/packages/pypi/importlib-metadata/5.0.0/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/importlib-metadata/5.0.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/importlib-metadata/5.0.0/compatibility-slim/4.12.0)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/importlib-metadata/5.0.0/confidence-slim/4.12.0)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
python/importlib_metadata ### [`v5.0.0`](https://togithub.com/python/importlib_metadata/blob/HEAD/CHANGES.rst#v500) [Compare Source](https://togithub.com/python/importlib_metadata/compare/v4.13.0...v5.0.0) \====== - [#​97](https://togithub.com/python/importlib_metadata/issues/97), [#​284](https://togithub.com/python/importlib_metadata/issues/284), [#​300](https://togithub.com/python/importlib_metadata/issues/300): Removed compatibility shims for deprecated entry point interfaces. ### [`v4.13.0`](https://togithub.com/python/importlib_metadata/blob/HEAD/CHANGES.rst#v4130) [Compare Source](https://togithub.com/python/importlib_metadata/compare/v4.12.0...v4.13.0) \======= - [#​396](https://togithub.com/python/importlib_metadata/issues/396): Added compatibility for `PathDistributions` originating from Python 3.8 and 3.9.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 69e987011b00..b15ba8d186ba 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -264,9 +264,9 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==4.12.0 \ - --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ - --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 +importlib-metadata==5.0.0 \ + --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ + --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via # -r requirements.in # twine diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 3d92e70bfb5d..ba257bba4c9f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -182,9 +182,9 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==4.12.0 \ - --hash=sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670 \ - --hash=sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23 +importlib-metadata==5.0.0 \ + --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ + --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via alembic importlib-resources==5.9.0 \ --hash=sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681 \ From a5442a1454041e17a2bf3a01dbcebc0898129ac7 Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Tue, 4 Oct 2022 15:55:47 +0530 Subject: [PATCH 167/582] chore: auto-release (#261) --- packages/sqlalchemy-spanner/.github/release-please.yml | 1 + packages/sqlalchemy-spanner/.github/release-trigger.yml | 1 + 2 files changed, 2 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.github/release-trigger.yml diff --git a/packages/sqlalchemy-spanner/.github/release-please.yml b/packages/sqlalchemy-spanner/.github/release-please.yml index 4507ad0598a5..466597e5b196 100644 --- a/packages/sqlalchemy-spanner/.github/release-please.yml +++ b/packages/sqlalchemy-spanner/.github/release-please.yml @@ -1 +1,2 @@ releaseType: python +handleGHRelease: true diff --git a/packages/sqlalchemy-spanner/.github/release-trigger.yml b/packages/sqlalchemy-spanner/.github/release-trigger.yml new file mode 100644 index 000000000000..d4ca94189e16 --- /dev/null +++ b/packages/sqlalchemy-spanner/.github/release-trigger.yml @@ -0,0 +1 @@ +enabled: true From b37932a6bae40b18491a8b4ae65972cc69e5df43 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 20:39:13 +0530 Subject: [PATCH 168/582] chore(main): release 1.2.2 (#262) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 17 +++++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index d5bb4f003c81..c048f84a87e4 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [1.2.2](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.1...v1.2.2) (2022-10-04) + + +### Bug Fixes + +* Adding requirements ([#250](https://github.com/googleapis/python-spanner-sqlalchemy/issues/250)) ([61a13d4](https://github.com/googleapis/python-spanner-sqlalchemy/commit/61a13d4ba152a24d5fa6083594aa86f46d5395de)) +* Don't introspect internal UNIQUE constraints ([#244](https://github.com/googleapis/python-spanner-sqlalchemy/issues/244)) ([51cdc53](https://github.com/googleapis/python-spanner-sqlalchemy/commit/51cdc534856b5ab933213803257679faa33be41c)) +* Spanner auto managed indexes should not be introspected ([#241](https://github.com/googleapis/python-spanner-sqlalchemy/issues/241)) ([c3b5907](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c3b59077ff8d6d8916007bf204f90e1d1ed41c00)) +* Update dialect name for ALTER operation overrides ([#234](https://github.com/googleapis/python-spanner-sqlalchemy/issues/234)) ([f9e8ebe](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f9e8ebedc863b2b84b2decffc1831125001785c8)) + + +### Documentation + +* Add auto retry mechanism explanation ([#243](https://github.com/googleapis/python-spanner-sqlalchemy/issues/243)) ([68b9bc8](https://github.com/googleapis/python-spanner-sqlalchemy/commit/68b9bc8b389c29451317cf78989578e0a7369dad)) +* Mention autocommit_block as a solution for Aborted transaction … ([#239](https://github.com/googleapis/python-spanner-sqlalchemy/issues/239)) ([f23e599](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f23e599ef6a9d8f198c41f32a586e42af840280d)), closes [#229](https://github.com/googleapis/python-spanner-sqlalchemy/issues/229) +* Mention package install with pip ([#245](https://github.com/googleapis/python-spanner-sqlalchemy/issues/245)) ([528a9b0](https://github.com/googleapis/python-spanner-sqlalchemy/commit/528a9b0ba1bb9f0b96e35c809faa923f292684a0)) + ## [1.2.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.0...v1.2.1) (2022-08-09) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 2f4e6ea6df57..4cbbb51645f9 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.2.1" +__version__ = "1.2.2" From 5fa72b276fd0c90fd041d3e9a81b4cd3194c2099 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 4 Oct 2022 19:18:14 +0200 Subject: [PATCH 169/582] chore(deps): update dependency google-cloud-spanner to v3.22.1 (#260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-cloud-spanner](https://togithub.com/googleapis/python-spanner) | `==3.22.0` -> `==3.22.1` | [![age](https://badges.renovateapi.com/packages/pypi/google-cloud-spanner/3.22.1/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/pypi/google-cloud-spanner/3.22.1/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/pypi/google-cloud-spanner/3.22.1/compatibility-slim/3.22.0)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/pypi/google-cloud-spanner/3.22.1/confidence-slim/3.22.0)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-spanner ### [`v3.22.1`](https://togithub.com/googleapis/python-spanner/blob/HEAD/CHANGELOG.md#​3221-httpsgithubcomgoogleapispython-spannercomparev3220v3221-2022-10-04) [Compare Source](https://togithub.com/googleapis/python-spanner/compare/v3.22.0...v3.22.1) ##### Bug Fixes - **deps:** Require protobuf >= 3.20.2 ([#​830](https://togithub.com/googleapis/python-spanner/issues/830)) ([4d71563](https://togithub.com/googleapis/python-spanner/commit/4d7156376f4633de6c1a2bfd25ba97126386ebd0)) ##### Documentation - **samples:** add samples for CMMR phase 2 ([4282340](https://togithub.com/googleapis/python-spanner/commit/4282340bc2c3a34496c59c33f5c64ff76dceda4c))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, click this checkbox. --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ba257bba4c9f..2385c337c021 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -52,9 +52,9 @@ google-cloud-core==2.3.2 \ --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a # via google-cloud-spanner -google-cloud-spanner==3.22.0 \ - --hash=sha256:2a57d163521503b6cd41ae558a29ecea2d5e707dfaf6fe9c5530926194b0992f \ - --hash=sha256:dc464c53217d49ef830f710ad3fb2b60e0d1268f0e42402be518a54db3131c8a +google-cloud-spanner==3.22.1 \ + --hash=sha256:87c950d18f8dcb49892ac24c28ea86d97c6ee2993e583383aee026f50323cbfe \ + --hash=sha256:9499f5c7bec2d68898159a93450182a29ff50d0f0eb2ba911f8d9b9f127b5e2a # via -r requirements.in googleapis-common-protos[grpc]==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ From 7828ae3865e53bbb5f690be1341c637bcd3f9fde Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 18 Oct 2022 08:11:43 +0200 Subject: [PATCH 170/582] chore(deps): update dependency google-auth to v2.13.0 (#252) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b15ba8d186ba..8c1655296c88 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -166,9 +166,9 @@ google-api-core==2.10.1 \ # via # google-cloud-core # google-cloud-storage -google-auth==2.11.1 \ - --hash=sha256:516e6623038b81430dd062a1a25ecd24f173d7c15cdf4e48a9e78bc87e97aeec \ - --hash=sha256:53bdc0c2b4e25895575779caef4cfb3a6bdff1b7b32dc38a654d71aba35bb5f8 +google-auth==2.13.0 \ + --hash=sha256:9352dd6394093169157e6971526bab9a2799244d68a94a4a609f0dd751ef6f5e \ + --hash=sha256:99510e664155f1a3c0396a076b5deb6367c52ea04d280152c85ac7f51f50eb42 # via # gcp-releasetool # google-api-core diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2385c337c021..89ceadba5173 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -42,9 +42,9 @@ google-api-core[grpc]==2.10.1 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.11.1 \ - --hash=sha256:516e6623038b81430dd062a1a25ecd24f173d7c15cdf4e48a9e78bc87e97aeec \ - --hash=sha256:53bdc0c2b4e25895575779caef4cfb3a6bdff1b7b32dc38a654d71aba35bb5f8 +google-auth==2.13.0 \ + --hash=sha256:9352dd6394093169157e6971526bab9a2799244d68a94a4a609f0dd751ef6f5e \ + --hash=sha256:99510e664155f1a3c0396a076b5deb6367c52ea04d280152c85ac7f51f50eb42 # via # google-api-core # google-cloud-core From ff5d833fe17bc228ceac1775f9caa8ba3f2eeae5 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 18 Oct 2022 09:01:50 +0200 Subject: [PATCH 171/582] chore(deps): update dependency google-resumable-media to v2.4.0 (#255) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 8c1655296c88..c1d09d1a5c12 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -252,9 +252,9 @@ google-crc32c==1.5.0 \ --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 # via google-resumable-media -google-resumable-media==2.3.3 \ - --hash=sha256:27c52620bd364d1c8116eaac4ea2afcbfb81ae9139fb3199652fcac1724bfb6c \ - --hash=sha256:5b52774ea7a829a8cdaa8bd2d4c3d4bc660c91b30857ab2668d0eb830f4ea8c5 +google-resumable-media==2.4.0 \ + --hash=sha256:2aa004c16d295c8f6c33b2b4788ba59d366677c0a25ae7382436cb30f776deaa \ + --hash=sha256:8d5518502f92b9ecc84ac46779bd4f09694ecb3ba38a3e7ca737a86d15cbca1f # via google-cloud-storage googleapis-common-protos==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ From fb9fd89993c5e29680365aec05fd2fe1786c9d09 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 19 Oct 2022 08:24:41 +0200 Subject: [PATCH 172/582] chore(deps): update dependency google-api-core to v2.10.2 (#268) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c1d09d1a5c12..801cbca159a4 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -160,9 +160,9 @@ gcp-releasetool==1.8.8 \ --hash=sha256:0e235a63b290e94554eac9906283275859816e8201bacb06c88870608f91515c \ --hash=sha256:2e6ea4407a64bb4903b037a9fc63e01d09225a88be1097439535f5eda21aeea9 # via -r requirements.in -google-api-core==2.10.1 \ - --hash=sha256:92d17123cfe399b5ef7e026c63babf978d8475e1ac877919eb7933e25dea2273 \ - --hash=sha256:e16c15a11789bc5a3457afb2818a3540a03f341e6e710d7f9bbf6cde2ef4a7c8 +google-api-core==2.10.2 \ + --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ + --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e # via # google-cloud-core # google-cloud-storage diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 89ceadba5173..6bac4e754c75 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -36,9 +36,9 @@ deprecated==1.2.13 \ --hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \ --hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d # via opentelemetry-api -google-api-core[grpc]==2.10.1 \ - --hash=sha256:92d17123cfe399b5ef7e026c63babf978d8475e1ac877919eb7933e25dea2273 \ - --hash=sha256:e16c15a11789bc5a3457afb2818a3540a03f341e6e710d7f9bbf6cde2ef4a7c8 +google-api-core[grpc]==2.10.2 \ + --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ + --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e # via # google-cloud-core # google-cloud-spanner From a7ecaf4121772067d88f1c52ab9d3a4f58b85e1b Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 19 Oct 2022 09:12:17 +0200 Subject: [PATCH 173/582] chore(deps): update dependency typing-extensions to v4.4.0 (#266) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 801cbca159a4..091de56a9cee 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -467,9 +467,9 @@ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 # via -r requirements.in -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via -r requirements.in urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6bac4e754c75..4fd812fa3a6c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -383,9 +383,9 @@ tomli==2.0.1 \ # -r requirements.in # build # pep517 -typing-extensions==4.3.0 \ - --hash=sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02 \ - --hash=sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6 +typing-extensions==4.4.0 \ + --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ + --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via opentelemetry-sdk urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ From 0c5a30d7ce1176b2e444e948b779be87b7a76617 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 19 Oct 2022 10:02:33 +0200 Subject: [PATCH 174/582] chore(deps): update dependency gcp-docuploader to v0.6.4 (#274) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 091de56a9cee..06fb2e990671 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -152,9 +152,9 @@ filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 # via virtualenv -gcp-docuploader==0.6.3 \ - --hash=sha256:ba8c9d76b3bbac54b0311c503a373b00edc2dc02d6d54ea9507045adb8e870f7 \ - --hash=sha256:c0f5aaa82ce1854a386197e4e359b120ad6d4e57ae2c812fce42219a3288026b +gcp-docuploader==0.6.4 \ + --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ + --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in gcp-releasetool==1.8.8 \ --hash=sha256:0e235a63b290e94554eac9906283275859816e8201bacb06c88870608f91515c \ From bd925e45af54bd7d12195fe856a029909e369433 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 19 Oct 2022 14:06:48 +0200 Subject: [PATCH 175/582] chore(deps): update dependency google-cloud-spanner to v3.22.2 (#273) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4fd812fa3a6c..3cbab20a137f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -52,9 +52,9 @@ google-cloud-core==2.3.2 \ --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a # via google-cloud-spanner -google-cloud-spanner==3.22.1 \ - --hash=sha256:87c950d18f8dcb49892ac24c28ea86d97c6ee2993e583383aee026f50323cbfe \ - --hash=sha256:9499f5c7bec2d68898159a93450182a29ff50d0f0eb2ba911f8d9b9f127b5e2a +google-cloud-spanner==3.22.2 \ + --hash=sha256:97c1c1d207d63340011e2204e448fa3ccbd9ecc45102e9943a3e65992a136e62 \ + --hash=sha256:e045f8c94d190c5d480cb149239fbb9d49153276cc30b967693f532c75bc1757 # via -r requirements.in googleapis-common-protos[grpc]==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ From 02e4e2c5b5edb3c1df525a03a81a84a74de83540 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 20 Oct 2022 08:08:57 +0200 Subject: [PATCH 176/582] chore(deps): update dependency sqlalchemy to v1.4.42 (#276) --- packages/sqlalchemy-spanner/requirements.txt | 84 ++++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 3cbab20a137f..651df27751d6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -327,48 +327,48 @@ six==1.16.0 \ # via # google-auth # grpcio -sqlalchemy==1.4.41 \ - --hash=sha256:0002e829142b2af00b4eaa26c51728f3ea68235f232a2e72a9508a3116bd6ed0 \ - --hash=sha256:0005bd73026cd239fc1e8ccdf54db58b6193be9a02b3f0c5983808f84862c767 \ - --hash=sha256:0292f70d1797e3c54e862e6f30ae474014648bc9c723e14a2fda730adb0a9791 \ - --hash=sha256:036d8472356e1d5f096c5e0e1a7e0f9182140ada3602f8fff6b7329e9e7cfbcd \ - --hash=sha256:05f0de3a1dc3810a776275763764bb0015a02ae0f698a794646ebc5fb06fad33 \ - --hash=sha256:0990932f7cca97fece8017414f57fdd80db506a045869d7ddf2dda1d7cf69ecc \ - --hash=sha256:13e397a9371ecd25573a7b90bd037db604331cf403f5318038c46ee44908c44d \ - --hash=sha256:14576238a5f89bcf504c5f0a388d0ca78df61fb42cb2af0efe239dc965d4f5c9 \ - --hash=sha256:199a73c31ac8ea59937cc0bf3dfc04392e81afe2ec8a74f26f489d268867846c \ - --hash=sha256:2082a2d2fca363a3ce21cfa3d068c5a1ce4bf720cf6497fb3a9fc643a8ee4ddd \ - --hash=sha256:22ff16cedab5b16a0db79f1bc99e46a6ddececb60c396562e50aab58ddb2871c \ - --hash=sha256:2307495d9e0ea00d0c726be97a5b96615035854972cc538f6e7eaed23a35886c \ - --hash=sha256:2ad2b727fc41c7f8757098903f85fafb4bf587ca6605f82d9bf5604bd9c7cded \ - --hash=sha256:2d6495f84c4fd11584f34e62f9feec81bf373787b3942270487074e35cbe5330 \ - --hash=sha256:361f6b5e3f659e3c56ea3518cf85fbdae1b9e788ade0219a67eeaaea8a4e4d2a \ - --hash=sha256:3e2ef592ac3693c65210f8b53d0edcf9f4405925adcfc031ff495e8d18169682 \ - --hash=sha256:4676d51c9f6f6226ae8f26dc83ec291c088fe7633269757d333978df78d931ab \ - --hash=sha256:4ba7e122510bbc07258dc42be6ed45997efdf38129bde3e3f12649be70683546 \ - --hash=sha256:5102fb9ee2c258a2218281adcb3e1918b793c51d6c2b4666ce38c35101bb940e \ - --hash=sha256:5323252be2bd261e0aa3f33cb3a64c45d76829989fa3ce90652838397d84197d \ - --hash=sha256:58bb65b3274b0c8a02cea9f91d6f44d0da79abc993b33bdedbfec98c8440175a \ - --hash=sha256:59bdc291165b6119fc6cdbc287c36f7f2859e6051dd923bdf47b4c55fd2f8bd0 \ - --hash=sha256:5facb7fd6fa8a7353bbe88b95695e555338fb038ad19ceb29c82d94f62775a05 \ - --hash=sha256:639e1ae8d48b3c86ffe59c0daa9a02e2bfe17ca3d2b41611b30a0073937d4497 \ - --hash=sha256:8eb8897367a21b578b26f5713833836f886817ee2ffba1177d446fa3f77e67c8 \ - --hash=sha256:90484a2b00baedad361402c257895b13faa3f01780f18f4a104a2f5c413e4536 \ - --hash=sha256:9c56e19780cd1344fcd362fd6265a15f48aa8d365996a37fab1495cae8fcd97d \ - --hash=sha256:b67fc780cfe2b306180e56daaa411dd3186bf979d50a6a7c2a5b5036575cbdbb \ - --hash=sha256:c0dcf127bb99458a9d211e6e1f0f3edb96c874dd12f2503d4d8e4f1fd103790b \ - --hash=sha256:c23d64a0b28fc78c96289ffbd0d9d1abd48d267269b27f2d34e430ea73ce4b26 \ - --hash=sha256:ccfd238f766a5bb5ee5545a62dd03f316ac67966a6a658efb63eeff8158a4bbf \ - --hash=sha256:cd767cf5d7252b1c88fcfb58426a32d7bd14a7e4942497e15b68ff5d822b41ad \ - --hash=sha256:ce8feaa52c1640de9541eeaaa8b5fb632d9d66249c947bb0d89dd01f87c7c288 \ - --hash=sha256:d2e054aed4645f9b755db85bc69fc4ed2c9020c19c8027976f66576b906a74f1 \ - --hash=sha256:e16c2be5cb19e2c08da7bd3a87fed2a0d4e90065ee553a940c4fc1a0fb1ab72b \ - --hash=sha256:e4b12e3d88a8fffd0b4ca559f6d4957ed91bd4c0613a4e13846ab8729dc5c251 \ - --hash=sha256:e570cfc40a29d6ad46c9aeaddbdcee687880940a3a327f2c668dd0e4ef0a441d \ - --hash=sha256:eb30cf008850c0a26b72bd1b9be6730830165ce049d239cfdccd906f2685f892 \ - --hash=sha256:f37fa70d95658763254941ddd30ecb23fc4ec0c5a788a7c21034fc2305dab7cc \ - --hash=sha256:f5ebeeec5c14533221eb30bad716bc1fd32f509196318fb9caa7002c4a364e4c \ - --hash=sha256:f5fa526d027d804b1f85cdda1eb091f70bde6fb7d87892f6dd5a48925bc88898 +SQLAlchemy==1.4.42 \ + --hash=sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9 \ + --hash=sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049 \ + --hash=sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80 \ + --hash=sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d \ + --hash=sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628 \ + --hash=sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363 \ + --hash=sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0 \ + --hash=sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6 \ + --hash=sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2 \ + --hash=sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124 \ + --hash=sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2 \ + --hash=sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd \ + --hash=sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3 \ + --hash=sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb \ + --hash=sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5 \ + --hash=sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e \ + --hash=sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b \ + --hash=sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934 \ + --hash=sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516 \ + --hash=sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc \ + --hash=sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a \ + --hash=sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738 \ + --hash=sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908 \ + --hash=sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0 \ + --hash=sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1 \ + --hash=sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272 \ + --hash=sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d \ + --hash=sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95 \ + --hash=sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde \ + --hash=sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798 \ + --hash=sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525 \ + --hash=sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565 \ + --hash=sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88 \ + --hash=sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545 \ + --hash=sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775 \ + --hash=sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a \ + --hash=sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565 \ + --hash=sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71 \ + --hash=sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471 \ + --hash=sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257 \ + --hash=sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a # via # -r requirements.in # alembic From 20d7e7592afde8ce409ff12da65f40ba85c0bd9e Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 20 Oct 2022 09:03:27 +0200 Subject: [PATCH 177/582] chore(deps): update dependency grpcio to v1.50.0 (#277) --- packages/sqlalchemy-spanner/requirements.txt | 92 ++++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 651df27751d6..95cc076fb491 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -123,52 +123,52 @@ grpc-google-iam-v1==0.12.4 \ --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ --hash=sha256:3f0ac2c940b9a855d7ce7e31fde28bddb0d9ac362d32d07c67148306931a0e30 # via google-cloud-spanner -grpcio==1.49.1 \ - --hash=sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f \ - --hash=sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394 \ - --hash=sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad \ - --hash=sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3 \ - --hash=sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b \ - --hash=sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62 \ - --hash=sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df \ - --hash=sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed \ - --hash=sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede \ - --hash=sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af \ - --hash=sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492 \ - --hash=sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f \ - --hash=sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c \ - --hash=sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705 \ - --hash=sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8 \ - --hash=sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146 \ - --hash=sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201 \ - --hash=sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811 \ - --hash=sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf \ - --hash=sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68 \ - --hash=sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc \ - --hash=sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568 \ - --hash=sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e \ - --hash=sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2 \ - --hash=sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d \ - --hash=sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7 \ - --hash=sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62 \ - --hash=sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd \ - --hash=sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a \ - --hash=sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b \ - --hash=sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c \ - --hash=sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62 \ - --hash=sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd \ - --hash=sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534 \ - --hash=sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f \ - --hash=sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b \ - --hash=sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d \ - --hash=sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f \ - --hash=sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f \ - --hash=sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2 \ - --hash=sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3 \ - --hash=sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788 \ - --hash=sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde \ - --hash=sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20 \ - --hash=sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f +grpcio==1.50.0 \ + --hash=sha256:05f7c248e440f538aaad13eee78ef35f0541e73498dd6f832fe284542ac4b298 \ + --hash=sha256:080b66253f29e1646ac53ef288c12944b131a2829488ac3bac8f52abb4413c0d \ + --hash=sha256:12b479839a5e753580b5e6053571de14006157f2ef9b71f38c56dc9b23b95ad6 \ + --hash=sha256:156f8009e36780fab48c979c5605eda646065d4695deea4cfcbcfdd06627ddb6 \ + --hash=sha256:15f9e6d7f564e8f0776770e6ef32dac172c6f9960c478616c366862933fa08b4 \ + --hash=sha256:177afaa7dba3ab5bfc211a71b90da1b887d441df33732e94e26860b3321434d9 \ + --hash=sha256:1a4cd8cb09d1bc70b3ea37802be484c5ae5a576108bad14728f2516279165dd7 \ + --hash=sha256:1d8d02dbb616c0a9260ce587eb751c9c7dc689bc39efa6a88cc4fa3e9c138a7b \ + --hash=sha256:2b71916fa8f9eb2abd93151fafe12e18cebb302686b924bd4ec39266211da525 \ + --hash=sha256:2d9fd6e38b16c4d286a01e1776fdf6c7a4123d99ae8d6b3f0b4a03a34bf6ce45 \ + --hash=sha256:3b611b3de3dfd2c47549ca01abfa9bbb95937eb0ea546ea1d762a335739887be \ + --hash=sha256:3e4244c09cc1b65c286d709658c061f12c61c814be0b7030a2d9966ff02611e0 \ + --hash=sha256:40838061e24f960b853d7bce85086c8e1b81c6342b1f4c47ff0edd44bbae2722 \ + --hash=sha256:4b123fbb7a777a2fedec684ca0b723d85e1d2379b6032a9a9b7851829ed3ca9a \ + --hash=sha256:531f8b46f3d3db91d9ef285191825d108090856b3bc86a75b7c3930f16ce432f \ + --hash=sha256:67dd41a31f6fc5c7db097a5c14a3fa588af54736ffc174af4411d34c4f306f68 \ + --hash=sha256:7489dbb901f4fdf7aec8d3753eadd40839c9085967737606d2c35b43074eea24 \ + --hash=sha256:8d4c8e73bf20fb53fe5a7318e768b9734cf122fe671fcce75654b98ba12dfb75 \ + --hash=sha256:8e69aa4e9b7f065f01d3fdcecbe0397895a772d99954bb82eefbb1682d274518 \ + --hash=sha256:8e8999a097ad89b30d584c034929f7c0be280cd7851ac23e9067111167dcbf55 \ + --hash=sha256:906f4d1beb83b3496be91684c47a5d870ee628715227d5d7c54b04a8de802974 \ + --hash=sha256:92d7635d1059d40d2ec29c8bf5ec58900120b3ce5150ef7414119430a4b2dd5c \ + --hash=sha256:931e746d0f75b2a5cff0a1197d21827a3a2f400c06bace036762110f19d3d507 \ + --hash=sha256:95ce51f7a09491fb3da8cf3935005bff19983b77c4e9437ef77235d787b06842 \ + --hash=sha256:9eea18a878cffc804506d39c6682d71f6b42ec1c151d21865a95fae743fda500 \ + --hash=sha256:a23d47f2fc7111869f0ff547f771733661ff2818562b04b9ed674fa208e261f4 \ + --hash=sha256:a4c23e54f58e016761b576976da6a34d876420b993f45f66a2bfb00363ecc1f9 \ + --hash=sha256:a50a1be449b9e238b9bd43d3857d40edf65df9416dea988929891d92a9f8a778 \ + --hash=sha256:ab5d0e3590f0a16cb88de4a3fa78d10eb66a84ca80901eb2c17c1d2c308c230f \ + --hash=sha256:ae23daa7eda93c1c49a9ecc316e027ceb99adbad750fbd3a56fa9e4a2ffd5ae0 \ + --hash=sha256:af98d49e56605a2912cf330b4627e5286243242706c3a9fa0bcec6e6f68646fc \ + --hash=sha256:b2f77a90ba7b85bfb31329f8eab9d9540da2cf8a302128fb1241d7ea239a5469 \ + --hash=sha256:baab51dcc4f2aecabf4ed1e2f57bceab240987c8b03533f1cef90890e6502067 \ + --hash=sha256:ca8a2254ab88482936ce941485c1c20cdeaef0efa71a61dbad171ab6758ec998 \ + --hash=sha256:cb11464f480e6103c59d558a3875bd84eed6723f0921290325ebe97262ae1347 \ + --hash=sha256:ce8513aee0af9c159319692bfbf488b718d1793d764798c3d5cff827a09e25ef \ + --hash=sha256:cf151f97f5f381163912e8952eb5b3afe89dec9ed723d1561d59cabf1e219a35 \ + --hash=sha256:d144ad10eeca4c1d1ce930faa105899f86f5d99cecfe0d7224f3c4c76265c15e \ + --hash=sha256:d534d169673dd5e6e12fb57cc67664c2641361e1a0885545495e65a7b761b0f4 \ + --hash=sha256:d75061367a69808ab2e84c960e9dce54749bcc1e44ad3f85deee3a6c75b4ede9 \ + --hash=sha256:d84d04dec64cc4ed726d07c5d17b73c343c8ddcd6b59c7199c801d6bbb9d9ed1 \ + --hash=sha256:de411d2b030134b642c092e986d21aefb9d26a28bf5a18c47dd08ded411a3bc5 \ + --hash=sha256:e07fe0d7ae395897981d16be61f0db9791f482f03fee7d1851fe20ddb4f69c03 \ + --hash=sha256:ea8ccf95e4c7e20419b7827aa5b6da6f02720270686ac63bd3493a651830235c \ + --hash=sha256:f7025930039a011ed7d7e7ef95a1cb5f516e23c5a6ecc7947259b67bea8e06ca # via # google-api-core # googleapis-common-protos From a3b39c3af81fb71888efaa75a068f6040b2d8c05 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 21 Oct 2022 09:27:53 +0200 Subject: [PATCH 178/582] chore(deps): update dependency requests-toolbelt to v0.10.0 (#267) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 06fb2e990671..64a1b10f6e43 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -435,9 +435,9 @@ requests==2.28.1 \ # google-cloud-storage # requests-toolbelt # twine -requests-toolbelt==0.9.1 \ - --hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f \ - --hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 +requests-toolbelt==0.10.0 \ + --hash=sha256:64c6b8c51b515d123f9f708a29743f44eb70c4479440641ed2df8c4dea56d985 \ + --hash=sha256:f695d6207931200b46c8ef6addbc8a921fb5d77cc4cd209c2e7d39293fcd2b30 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ From 54046ec93484bef70202204076831bc27e5545b2 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 21 Oct 2022 10:20:55 +0200 Subject: [PATCH 179/582] chore(deps): update dependency grpcio-status to v1.50.0 (#278) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 95cc076fb491..219347e1ab03 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -174,9 +174,9 @@ grpcio==1.50.0 \ # googleapis-common-protos # grpc-google-iam-v1 # grpcio-status -grpcio-status==1.49.1 \ - --hash=sha256:658f48dc146ee0c7b6eebd302d74e0d45c00727c20035ff51d68750dbaccf5d9 \ - --hash=sha256:fe4ae9f624f03e50ccf6f6ead60727ab20b17735bb3d0dd506ef355349282378 +grpcio-status==1.50.0 \ + --hash=sha256:69be81c4317ec77983fb0eab80221a01e86e833e0fcf2f6acea0a62597c84b93 \ + --hash=sha256:6bcf86b1cb1a8929c9cb75c8593ea001a667f5167cf692627f4b3fc1ae0eded4 # via google-api-core idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ From 715a96c2282252b29b2128f5f991a16d509726b6 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 21 Oct 2022 11:17:38 +0200 Subject: [PATCH 180/582] chore(deps): update dependency greenlet to v1.1.3.post0 (#275) --- packages/sqlalchemy-spanner/requirements.txt | 122 ++++++++++--------- 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 219347e1ab03..e0c4ddfa4652 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -63,61 +63,73 @@ googleapis-common-protos[grpc]==1.56.4 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -greenlet==1.1.3 \ - --hash=sha256:0118817c9341ef2b0f75f5af79ac377e4da6ff637e5ee4ac91802c0e379dadb4 \ - --hash=sha256:048d2bed76c2aa6de7af500ae0ea51dd2267aec0e0f2a436981159053d0bc7cc \ - --hash=sha256:07c58e169bbe1e87b8bbf15a5c1b779a7616df9fd3e61cadc9d691740015b4f8 \ - --hash=sha256:095a980288fe05adf3d002fbb180c99bdcf0f930e220aa66fcd56e7914a38202 \ - --hash=sha256:0b181e9aa6cb2f5ec0cacc8cee6e5a3093416c841ba32c185c30c160487f0380 \ - --hash=sha256:1626185d938d7381631e48e6f7713e8d4b964be246073e1a1d15c2f061ac9f08 \ - --hash=sha256:184416e481295832350a4bf731ba619a92f5689bf5d0fa4341e98b98b1265bd7 \ - --hash=sha256:1dd51d2650e70c6c4af37f454737bf4a11e568945b27f74b471e8e2a9fd21268 \ - --hash=sha256:1ec2779774d8e42ed0440cf8bc55540175187e8e934f2be25199bf4ed948cd9e \ - --hash=sha256:2cf45e339cabea16c07586306a31cfcc5a3b5e1626d365714d283732afed6809 \ - --hash=sha256:2fb0aa7f6996879551fd67461d5d3ab0c3c0245da98be90c89fcb7a18d437403 \ - --hash=sha256:44b4817c34c9272c65550b788913620f1fdc80362b209bc9d7dd2f40d8793080 \ - --hash=sha256:466ce0928e33421ee84ae04c4ac6f253a3a3e6b8d600a79bd43fd4403e0a7a76 \ - --hash=sha256:4f166b4aca8d7d489e82d74627a7069ab34211ef5ebb57c300ec4b9337b60fc0 \ - --hash=sha256:510c3b15587afce9800198b4b142202b323bf4b4b5f9d6c79cb9a35e5e3c30d2 \ - --hash=sha256:5b756e6730ea59b2745072e28ad27f4c837084688e6a6b3633c8b1e509e6ae0e \ - --hash=sha256:5fbe1ab72b998ca77ceabbae63a9b2e2dc2d963f4299b9b278252ddba142d3f1 \ - --hash=sha256:6200a11f003ec26815f7e3d2ded01b43a3810be3528dd760d2f1fa777490c3cd \ - --hash=sha256:65ad1a7a463a2a6f863661329a944a5802c7129f7ad33583dcc11069c17e622c \ - --hash=sha256:694ffa7144fa5cc526c8f4512665003a39fa09ef00d19bbca5c8d3406db72fbe \ - --hash=sha256:6f5d4b2280ceea76c55c893827961ed0a6eadd5a584a7c4e6e6dd7bc10dfdd96 \ - --hash=sha256:7532a46505470be30cbf1dbadb20379fb481244f1ca54207d7df3bf0bbab6a20 \ - --hash=sha256:76a53bfa10b367ee734b95988bd82a9a5f0038a25030f9f23bbbc005010ca600 \ - --hash=sha256:77e41db75f9958f2083e03e9dd39da12247b3430c92267df3af77c83d8ff9eed \ - --hash=sha256:7a43bbfa9b6cfdfaeefbd91038dde65ea2c421dc387ed171613df340650874f2 \ - --hash=sha256:7b41d19c0cfe5c259fe6c539fd75051cd39a5d33d05482f885faf43f7f5e7d26 \ - --hash=sha256:7c5227963409551ae4a6938beb70d56bf1918c554a287d3da6853526212fbe0a \ - --hash=sha256:870a48007872d12e95a996fca3c03a64290d3ea2e61076aa35d3b253cf34cd32 \ - --hash=sha256:88b04e12c9b041a1e0bcb886fec709c488192638a9a7a3677513ac6ba81d8e79 \ - --hash=sha256:8c287ae7ac921dfde88b1c125bd9590b7ec3c900c2d3db5197f1286e144e712b \ - --hash=sha256:903fa5716b8fbb21019268b44f73f3748c41d1a30d71b4a49c84b642c2fed5fa \ - --hash=sha256:9537e4baf0db67f382eb29255a03154fcd4984638303ff9baaa738b10371fa57 \ - --hash=sha256:9951dcbd37850da32b2cb6e391f621c1ee456191c6ae5528af4a34afe357c30e \ - --hash=sha256:9b2f7d0408ddeb8ea1fd43d3db79a8cefaccadd2a812f021333b338ed6b10aba \ - --hash=sha256:9c88e134d51d5e82315a7c32b914a58751b7353eb5268dbd02eabf020b4c4700 \ - --hash=sha256:9fae214f6c43cd47f7bef98c56919b9222481e833be2915f6857a1e9e8a15318 \ - --hash=sha256:a3a669f11289a8995d24fbfc0e63f8289dd03c9aaa0cc8f1eab31d18ca61a382 \ - --hash=sha256:aa741c1a8a8cc25eb3a3a01a62bdb5095a773d8c6a86470bde7f607a447e7905 \ - --hash=sha256:b0877a9a2129a2c56a2eae2da016743db7d9d6a05d5e1c198f1b7808c602a30e \ - --hash=sha256:bcb6c6dd1d6be6d38d6db283747d07fda089ff8c559a835236560a4410340455 \ - --hash=sha256:caff52cb5cd7626872d9696aee5b794abe172804beb7db52eed1fd5824b63910 \ - --hash=sha256:cbc1eb55342cbac8f7ec159088d54e2cfdd5ddf61c87b8bbe682d113789331b2 \ - --hash=sha256:cd16a89efe3a003029c87ff19e9fba635864e064da646bc749fc1908a4af18f3 \ - --hash=sha256:ce5b64dfe8d0cca407d88b0ee619d80d4215a2612c1af8c98a92180e7109f4b5 \ - --hash=sha256:d58a5a71c4c37354f9e0c24c9c8321f0185f6945ef027460b809f4bb474bfe41 \ - --hash=sha256:db41f3845eb579b544c962864cce2c2a0257fe30f0f1e18e51b1e8cbb4e0ac6d \ - --hash=sha256:db5b25265010a1b3dca6a174a443a0ed4c4ab12d5e2883a11c97d6e6d59b12f9 \ - --hash=sha256:dd0404d154084a371e6d2bafc787201612a1359c2dee688ae334f9118aa0bf47 \ - --hash=sha256:de431765bd5fe62119e0bc6bc6e7b17ac53017ae1782acf88fcf6b7eae475a49 \ - --hash=sha256:df02fdec0c533301497acb0bc0f27f479a3a63dcdc3a099ae33a902857f07477 \ - --hash=sha256:e8533f5111704d75de3139bf0b8136d3a6c1642c55c067866fa0a51c2155ee33 \ - --hash=sha256:f2f908239b7098799b8845e5936c2ccb91d8c2323be02e82f8dcb4a80dcf4a25 \ - --hash=sha256:f8bfd36f368efe0ab2a6aa3db7f14598aac454b06849fb633b762ddbede1db90 \ - --hash=sha256:ffe73f9e7aea404722058405ff24041e59d31ca23d1da0895af48050a07b6932 +greenlet==1.1.3.post0 \ + --hash=sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754 \ + --hash=sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136 \ + --hash=sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519 \ + --hash=sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403 \ + --hash=sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9 \ + --hash=sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809 \ + --hash=sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e \ + --hash=sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb \ + --hash=sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05 \ + --hash=sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80 \ + --hash=sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b \ + --hash=sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8 \ + --hash=sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2 \ + --hash=sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d \ + --hash=sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8 \ + --hash=sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3 \ + --hash=sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194 \ + --hash=sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e \ + --hash=sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8 \ + --hash=sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9 \ + --hash=sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519 \ + --hash=sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269 \ + --hash=sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5 \ + --hash=sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b \ + --hash=sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5 \ + --hash=sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21 \ + --hash=sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd \ + --hash=sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05 \ + --hash=sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57 \ + --hash=sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f \ + --hash=sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f \ + --hash=sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea \ + --hash=sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a \ + --hash=sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba \ + --hash=sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5 \ + --hash=sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa \ + --hash=sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012 \ + --hash=sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a \ + --hash=sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10 \ + --hash=sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3 \ + --hash=sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743 \ + --hash=sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6 \ + --hash=sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7 \ + --hash=sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad \ + --hash=sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3 \ + --hash=sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854 \ + --hash=sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d \ + --hash=sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be \ + --hash=sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67 \ + --hash=sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427 \ + --hash=sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8 \ + --hash=sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51 \ + --hash=sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132 \ + --hash=sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870 \ + --hash=sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128 \ + --hash=sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f \ + --hash=sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392 \ + --hash=sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b \ + --hash=sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c \ + --hash=sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589 \ + --hash=sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54 \ + --hash=sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9 \ + --hash=sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c \ + --hash=sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9 \ + --hash=sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b \ + --hash=sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04 # via sqlalchemy grpc-google-iam-v1==0.12.4 \ --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ From ed4e0a2df4ea7c5e56772366c9e4026053b3a9e4 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 21 Oct 2022 12:43:45 +0200 Subject: [PATCH 181/582] chore(deps): update dependency importlib-resources to v5.10.0 (#279) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e0c4ddfa4652..2e9990057c7c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -198,9 +198,9 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via alembic -importlib-resources==5.9.0 \ - --hash=sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681 \ - --hash=sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7 +importlib-resources==5.10.0 \ + --hash=sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668 \ + --hash=sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437 # via alembic mako==1.2.3 \ --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ From 049b37ef1b24af95da6830a32ba93f267acb4448 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Tue, 22 Nov 2022 03:20:40 -0800 Subject: [PATCH 182/582] feat: support request priorities (#286) * feat: support request priorities * use priority constants * Update README.rst * add the test into 1.4 test suite * add missing time module * Update create_test_database.py * fix typo * fix typo * fix tests --- packages/sqlalchemy-spanner/README.rst | 13 ++++++++ .../create_test_database.py | 2 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 8 +++-- .../sqlalchemy-spanner/test/test_suite_13.py | 18 +++++++++- .../sqlalchemy-spanner/test/test_suite_14.py | 33 +++++++++++++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 8147871cf082..464402e2eb2d 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -391,6 +391,19 @@ wanted staleness value. For example: Note that the set option will be dropped when the connection is returned back to the pool. +Request priority +~~~~~~~~~~~~~~~~~~~~~ +In order to use Request Priorities feature in Cloud Spanner, SQLAlchemy provides an ``execution_options`` parameter: + +.. code:: python + + from google.cloud.spanner_v1 import RequestOptions + + with engine.connect().execution_options( + request_priority=RequestOptions.Priority.PRIORITY_MEDIUM + ) as connection: + connection.execute(select(["*"], from_obj=table)).fetchall() + DDL and transactions ~~~~~~~~~~~~~~~~~~~~ diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index d5d5978bb849..30bbb22fbeb0 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -70,7 +70,7 @@ def create_test_instance(): configs = list(CLIENT.list_instance_configs()) if not USE_EMULATOR: # Filter out non "us" locations - configs = [config for config in configs if "europe-north1" in config.name] + configs = [config for config in configs if "us-south1" in config.name] instance_config = configs[0].name create_time = str(int(time.time())) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index bd57daab76b4..5bf40eb1d701 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -150,14 +150,18 @@ def pre_exec(self): """ super(SpannerExecutionContext, self).pre_exec() - read_only = self.execution_options.get("read_only", None) + read_only = self.execution_options.get("read_only") if read_only is not None: self._dbapi_connection.connection.read_only = read_only - staleness = self.execution_options.get("staleness", None) + staleness = self.execution_options.get("staleness") if staleness is not None: self._dbapi_connection.connection.staleness = staleness + priority = self.execution_options.get("request_priority") + if priority is not None: + self._dbapi_connection.connection.request_priority = priority + class SpannerIdentifierPreparer(IdentifierPreparer): """Identifiers compiler. diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index c31cce82aad3..879e7964c65e 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -24,6 +24,8 @@ import time from unittest import mock +from google.cloud.spanner_v1 import RequestOptions + import sqlalchemy from sqlalchemy import create_engine from sqlalchemy import inspect @@ -1644,7 +1646,7 @@ def test_offset_only(self): list(connection.execute(self._table.select().offset(offset)).fetchall()) -class ExecutionOptionsStalenessTest(fixtures.TestBase): +class ExecutionOptionsTest(fixtures.TestBase): """ Check that `execution_options()` method correctly sets parameters on the underlying DB API connection. @@ -1680,6 +1682,20 @@ def test_staleness(self): with engine.connect() as connection: pass + def test_request_priority(self): + PRIORITY = RequestOptions.Priority.PRIORITY_MEDIUM + with self._engine.connect().execution_options( + request_priority=PRIORITY + ) as connection: + connection.execute(select(["*"], from_obj=self._table)).fetchall() + + with self._engine.connect() as connection: + assert connection.connection.request_priority is None + + engine = create_engine("sqlite:///database") + with engine.connect() as connection: + pass + class TemporaryTableTest(fixtures.TestBase): """ diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 5563169e5aa0..8965eebca5bb 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -21,8 +21,11 @@ import pkg_resources import pytest import random +import time from unittest import mock +from google.cloud.spanner_v1 import RequestOptions + import sqlalchemy from sqlalchemy import create_engine from sqlalchemy import inspect @@ -2160,3 +2163,33 @@ def test_round_trip_none_as_json_null(self): ) def test_round_trip_none_as_sql_null(self): pass + + +class ExecutionOptionsRequestPriorotyTest(fixtures.TestBase): + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + metadata = MetaData(bind=self._engine) + + self._table = Table( + "execution_options2", + metadata, + Column("opt_id", Integer, primary_key=True), + Column("opt_name", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + time.sleep(1) + + def test_request_priority(self): + PRIORITY = RequestOptions.Priority.PRIORITY_MEDIUM + with self._engine.connect().execution_options( + request_priority=PRIORITY + ) as connection: + connection.execute(select(["*"], from_obj=self._table)).fetchall() + + with self._engine.connect() as connection: + assert connection.connection.request_priority is None + + engine = create_engine("sqlite:///database") + with engine.connect() as connection: + pass From 05cc7a17bec0330e4a562cc4574ca7d4cc8f02a4 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Wed, 23 Nov 2022 22:52:53 -0800 Subject: [PATCH 183/582] fix: introspect constraints, keeping their order (#289) --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 5bf40eb1d701..c655bfb52c88 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -794,7 +794,13 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): ctu.table_name, ctu.table_schema, ARRAY_AGG(DISTINCT ccu.column_name), - ARRAY_AGG(kcu.column_name) + ARRAY_AGG( + DISTINCT CONCAT( + CAST(kcu.ordinal_position AS STRING), + '_____', + kcu.column_name + ) + ) FROM information_schema.table_constraints AS tc JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name @@ -815,6 +821,21 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): rows = snap.execute_sql(sql) for row in rows: + # Due to Spanner limitations, arrays order is not guaranteed during + # aggregation. Still, for constraints it's vital to keep the order + # of the referred columns, otherwise SQLAlchemy and Alembic may start + # to occasionally drop and recreate constraints. To avoid this, the + # method uses prefixes with the `key_column_usage.ordinal_position` + # values to ensure the columns are aggregated into an array in the + # correct order. Prefixes are only used under the hood. For more details + # see the issue: + # https://github.com/googleapis/python-spanner-sqlalchemy/issues/271 + # + # The solution seem a bit clumsy, and should be improved as soon as a + # better approach found. + for index, value in enumerate(sorted(row[4])): + row[4][index] = value.split("_____")[1] + keys.append( { "name": row[0], @@ -824,6 +845,7 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): "constrained_columns": row[4], } ) + return keys @engine_to_connection From 27a22214a6b9a89ba64d359a0d05c724d959dd88 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Thu, 1 Dec 2022 02:11:07 -0800 Subject: [PATCH 184/582] fix: alembic incompatibility with sqlalchemy < 1.3.11 (#290) --- .../cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- packages/sqlalchemy-spanner/noxfile.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index c655bfb52c88..f72d95a11563 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -353,7 +353,7 @@ def get_column_specification(self, column, **kwargs): if default is not None: colspec += " DEFAULT (" + default + ")" - if column.computed is not None: + if hasattr(column, "computed") and column.computed is not None: colspec += " " + self.process(column.computed) return colspec diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 693754b61abc..acc9c1ba8a19 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -223,6 +223,20 @@ def unit(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def migration_test(session): + """Test migrations with SQLAlchemy v1.3.11+ and Alembic""" + session.run("pip", "install", "sqlalchemy>=1.3.11", "--force-reinstall") + _migration_test(session) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def migration_test_1310(session): + """Test migrations with SQLAlchemy 1.3.10 or lower and Alembic""" + session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.10", "--force-reinstall") + _migration_test(session) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def _migration_test(session): """Migrate with SQLAlchemy and Alembic and check the result.""" import glob import os From c0d23bfcb2b7522302a9372cde3cf117478b3a16 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 8 Dec 2022 09:36:04 +0100 Subject: [PATCH 185/582] chore(deps): update dependency pyjwt to v2.6.0 (#280) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 64a1b10f6e43..0a7a07b5a7f6 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -407,9 +407,9 @@ pygments==2.13.0 \ # via # readme-renderer # rich -pyjwt==2.5.0 \ - --hash=sha256:8d82e7087868e94dd8d7d418e5088ce64f7daab4b36db654cbaedb46f9d1ca80 \ - --hash=sha256:e77ab89480905d86998442ac5788f35333fa85f65047a534adc38edf3c88fc3b +PyJWT==2.6.0 \ + --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ + --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 # via gcp-releasetool pyparsing==3.0.9 \ --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ From d9b7d05ebe543ef4dee2cf8feedb6716c0609c2d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 8 Dec 2022 10:21:34 +0100 Subject: [PATCH 186/582] chore(deps): update dependency requests-toolbelt to v0.10.1 (#284) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 0a7a07b5a7f6..ffaff00a3427 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -435,9 +435,9 @@ requests==2.28.1 \ # google-cloud-storage # requests-toolbelt # twine -requests-toolbelt==0.10.0 \ - --hash=sha256:64c6b8c51b515d123f9f708a29743f44eb70c4479440641ed2df8c4dea56d985 \ - --hash=sha256:f695d6207931200b46c8ef6addbc8a921fb5d77cc4cd209c2e7d39293fcd2b30 +requests-toolbelt==0.10.1 \ + --hash=sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7 \ + --hash=sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ From 03b79b7ebb2d1a12161a9b70c9fbb04d483f51fd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 14 Dec 2022 09:44:22 +0100 Subject: [PATCH 187/582] chore(deps): update dependency certifi to v2022.12.7 [security] (#295) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ffaff00a3427..c2991ac1e730 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.9.24 \ - --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \ - --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382 +certifi==2022.12.7 \ + --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ + --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2e9990057c7c..2437c6c79282 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.9.24 \ - --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \ - --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382 +certifi==2022.12.7 \ + --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ + --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 # via requests charset-normalizer==2.1.1 \ --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ From 765d50ae46366c9ac7a18dda3ff04573d683fae0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 15 Dec 2022 08:01:12 +0100 Subject: [PATCH 188/582] chore(deps): update dependency pip-tools to v6.12.0 (#264) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2437c6c79282..607ac4951e2b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -280,9 +280,9 @@ pep517==0.13.0 \ # via # -r requirements.in # build -pip-tools==6.8.0 \ - --hash=sha256:39e8aee465446e02278d80dbebd4325d1dd8633248f43213c73a25f58e7d8a55 \ - --hash=sha256:3e5cd4acbf383d19bdfdeab04738b6313ebf4ad22ce49bf529c729061eabfab8 +pip-tools==6.12.0 \ + --hash=sha256:8e22fbc84ede7ca522ba4b033c4fcf6a6419adabc75d24747be3d8262504489a \ + --hash=sha256:f441603c63b16f4af0dd5026f7522a49eddec2bc8a4a4979af44e1f6b0a1c13e # via -r requirements.in proto-plus==1.22.1 \ --hash=sha256:6c7dfd122dfef8019ff654746be4f5b1d9c80bba787fe9611b508dd88be3a2fa \ From 46bbe24c5b24d910f8d1f2022fda82d485800a70 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 15 Dec 2022 19:51:50 +0100 Subject: [PATCH 189/582] chore(deps): update dependency importlib-resources to v5.10.1 (#294) Co-authored-by: Astha Mohta <35952883+asthamohta@users.noreply.github.com> --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 607ac4951e2b..ac9e53d48a31 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -198,9 +198,9 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via alembic -importlib-resources==5.10.0 \ - --hash=sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668 \ - --hash=sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437 +importlib-resources==5.10.1 \ + --hash=sha256:32bb095bda29741f6ef0e5278c42df98d135391bee5f932841efc0041f748dc3 \ + --hash=sha256:c09b067d82e72c66f4f8eb12332f5efbebc9b007c0b6c40818108c9870adc363 # via alembic mako==1.2.3 \ --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ From 08f67c59dfa0f336db70788a35d764cfe3cddccc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 15 Dec 2022 20:48:01 +0100 Subject: [PATCH 190/582] chore(deps): update dependency gcp-releasetool to v1.10.1 (#258) Co-authored-by: Anthonios Partheniou --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c2991ac1e730..e17ea09e2ea3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -156,9 +156,9 @@ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in -gcp-releasetool==1.8.8 \ - --hash=sha256:0e235a63b290e94554eac9906283275859816e8201bacb06c88870608f91515c \ - --hash=sha256:2e6ea4407a64bb4903b037a9fc63e01d09225a88be1097439535f5eda21aeea9 +gcp-releasetool==1.10.1 \ + --hash=sha256:137b7e2e3fb7d94cb08fb4fe867a5e17d64a1e31dc262d3fd02ec17f49b75843 \ + --hash=sha256:728f8bae63d45032aaf32412c5526bcf9f18bd30efed406ab8171943e117292e # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ From 645b197bdb2b1ad42e6a1f4ee50d1b4ed0ecad8e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 7 Feb 2023 05:37:43 +0000 Subject: [PATCH 191/582] chore(deps): update dependency wheel to v0.38.1 [security] (#299) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e17ea09e2ea3..aba408a84677 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -485,9 +485,9 @@ webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach -wheel==0.37.1 \ - --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ - --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 +wheel==0.38.1 \ + --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ + --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 # via -r requirements.in zipp==3.8.1 \ --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ac9e53d48a31..395cbffc1998 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -403,9 +403,9 @@ urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 # via requests -wheel==0.37.1 \ - --hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a \ - --hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 +wheel==0.38.1 \ + --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ + --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 # via pip-tools wrapt==1.14.1 \ --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ From 92378c6ec370b66396cfdd3b69c92995ecac9fe3 Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Mon, 20 Mar 2023 11:10:25 +0530 Subject: [PATCH 192/582] fix: test fix (#310) * chore: auto-release * changes * changes * changes * changes * changes * Without changes * Update noxfile.py * changes * changes --------- Co-authored-by: surbhigarg92 --- .../.github/workflows/test_suite.yml | 1 + packages/sqlalchemy-spanner/noxfile.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 918e4fbe7cb7..dff7941fb463 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -85,6 +85,7 @@ jobs: env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + SQLALCHEMY_SILENCE_UBER_WARNING: 1 migration_tests: runs-on: ubuntu-latest diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index acc9c1ba8a19..5474fcb65660 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -190,10 +190,9 @@ def compliance_test_14(session): session.install("mock") session.install("-e", ".[tracing]") + session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") session.run("python", "create_test_database.py") - session.install("sqlalchemy>=1.4") - session.run( "py.test", "--cov=google.cloud.sqlalchemy_spanner", @@ -224,7 +223,7 @@ def unit(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def migration_test(session): """Test migrations with SQLAlchemy v1.3.11+ and Alembic""" - session.run("pip", "install", "sqlalchemy>=1.3.11", "--force-reinstall") + session.run("pip", "install", "sqlalchemy>=1.3.11,<2.0", "--force-reinstall") _migration_test(session) @@ -242,6 +241,11 @@ def _migration_test(session): import os import shutil + try: + import sqlalchemy + except: + session.run("pip", "install", "sqlalchemy>=1.3.11,<2.0", "--force-reinstall") + session.install("pytest") session.install("-e", ".") session.install("alembic") @@ -307,7 +311,7 @@ def snippets(session): session.skip("Credentials must be set via environment variable.") session.install("pytest") - session.install("sqlalchemy") + session.install("sqlalchemy>=1.4,<2.0") session.install( "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" ) From 3ce15c6f6c7e6f971203e0f824dcf0ead9013a24 Mon Sep 17 00:00:00 2001 From: Ilya Gurov Date: Mon, 20 Mar 2023 15:50:13 -0700 Subject: [PATCH 193/582] feat: implement get_view_names() method (#306) Closes #303 --- .../sqlalchemy-spanner/create_test_database.py | 2 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 18 ++++++++++++++++++ packages/sqlalchemy-spanner/noxfile.py | 7 ++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 30bbb22fbeb0..4d740ddfdb2f 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -70,7 +70,7 @@ def create_test_instance(): configs = list(CLIENT.list_instance_configs()) if not USE_EMULATOR: # Filter out non "us" locations - configs = [config for config in configs if "us-south1" in config.name] + configs = [config for config in configs if "us-west1" in config.name] instance_config = configs[0].name create_time = str(int(time.time())) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index f72d95a11563..12b0e7bd853b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -587,6 +587,24 @@ def create_connect_args(self, url): {"user_agent": f"gl-{dist.project_name}/{dist.version}"}, ) + @engine_to_connection + def get_view_names(self, connection, schema=None, **kw): + sql = """ + SELECT table_name + FROM information_schema.views + WHERE TABLE_SCHEMA='{}' + """.format( + schema or "" + ) + + all_views = [] + with connection.connection.database.snapshot() as snap: + rows = list(snap.execute_sql(sql)) + for view in rows: + all_views.append(view[0]) + + return all_views + @engine_to_connection def get_columns(self, connection, table_name, schema=None, **kw): """Get the table columns description. diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 5474fcb65660..7405974492b4 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -141,18 +141,19 @@ def compliance_test_13(session): ) session.install( - "pytest", "pytest-cov", - "pytest-asyncio", ) session.install("mock") session.install("-e", ".[tracing]") session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.24", "--force-reinstall") - session.run("pip", "install", "pytest==6.2.2", "--force-reinstall") session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") session.run("pip", "install", "opentelemetry-sdk<=1.10", "--force-reinstall") session.run("python", "create_test_database.py") + session.run("pip", "install", "pytest==6.2.2", "--force-reinstall") + session.run( + "pip", "install", "pytest-asyncio<0.21.0", "--force-reinstall", "--no-deps" + ) session.run( "py.test", From 8a49e77a37a38db29450504712019f380f8bb995 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:50:23 +0530 Subject: [PATCH 194/582] chore(main): release 1.3.0 (#292) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 15 +++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index c048f84a87e4..6eebf3d12642 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.3.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.2...v1.3.0) (2023-03-20) + + +### Features + +* Implement get_view_names() method ([#306](https://github.com/googleapis/python-spanner-sqlalchemy/issues/306)) ([63461e6](https://github.com/googleapis/python-spanner-sqlalchemy/commit/63461e67364b5214e7ea8a2d89c0fda4d9ced72d)), closes [#303](https://github.com/googleapis/python-spanner-sqlalchemy/issues/303) +* Support request priorities ([#286](https://github.com/googleapis/python-spanner-sqlalchemy/issues/286)) ([3aecf2d](https://github.com/googleapis/python-spanner-sqlalchemy/commit/3aecf2d651e6eb9f3af72a3ed3599aa51b4158a9)) + + +### Bug Fixes + +* Alembic incompatibility with sqlalchemy < 1.3.11 ([#290](https://github.com/googleapis/python-spanner-sqlalchemy/issues/290)) ([f99f3a7](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f99f3a78477aecc71af70deba41b861e12d51c28)) +* Introspect constraints, keeping their order ([#289](https://github.com/googleapis/python-spanner-sqlalchemy/issues/289)) ([7f65972](https://github.com/googleapis/python-spanner-sqlalchemy/commit/7f659729e15848c1493cb271e832b6968d7ab031)) +* Test fix ([#310](https://github.com/googleapis/python-spanner-sqlalchemy/issues/310)) ([c376d42](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c376d422ab455ee88bb94e2cd136aa9ef865e375)) + ## [1.2.2](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.1...v1.2.2) (2022-10-04) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 4cbbb51645f9..75fcf6b359d2 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.2.2" +__version__ = "1.3.0" From a30311fd1e5ba89ef7264a8030fe7bbc76ebbafe Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Thu, 6 Apr 2023 15:42:50 +0530 Subject: [PATCH 195/582] feat: User provided client (#311) * chore: auto-release * feat:pass client object direcrly * read me * read me * read me * changes --- packages/sqlalchemy-spanner/README.rst | 9 ++++++ packages/sqlalchemy-spanner/test/_helpers.py | 4 +++ .../sqlalchemy-spanner/test/test_suite_13.py | 31 +++++++++++++++++-- .../sqlalchemy-spanner/test/test_suite_14.py | 31 +++++++++++++++++-- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 464402e2eb2d..85fecf20d97c 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -76,6 +76,15 @@ on this step in a dialect prefix part: # for SQLAlchemy 1.4: spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id +To pass your custom client object directly to be be used, create engine as following: + +.. code:: python + + engine = create_engine( + "spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id", + connect_args={'client': spanner.Client(project="project-id")} + ) + Create a table ~~~~~~~~~~~~~~ diff --git a/packages/sqlalchemy-spanner/test/_helpers.py b/packages/sqlalchemy-spanner/test/_helpers.py index 8ef795f23e16..2aae11c7b697 100644 --- a/packages/sqlalchemy-spanner/test/_helpers.py +++ b/packages/sqlalchemy-spanner/test/_helpers.py @@ -71,6 +71,10 @@ def use_test_ot_exporter(): _TEST_OT_PROVIDER_INITIALIZED = True +def get_project(): + return PROJECT + + class OpenTelemetryBase(fixtures.TestBase): @classmethod def setup_class(cls): diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 879e7964c65e..e519dd4ba5fc 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -24,7 +24,7 @@ import time from unittest import mock -from google.cloud.spanner_v1 import RequestOptions +from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy from sqlalchemy import create_engine @@ -120,7 +120,7 @@ UnicodeVarcharTest as _UnicodeVarcharTest, UnicodeTextTest as _UnicodeTextTest, ) -from test._helpers import get_db_url +from test._helpers import get_db_url, get_project config.test_schema = "" @@ -1961,3 +1961,30 @@ def test_round_trip_none_as_json_null(self): ) def test_round_trip_none_as_sql_null(self): pass + + +class CreateEngineWithClientObjectTest(fixtures.TestBase): + def test_create_engine_w_valid_client_object(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + by passing custom Client object. + """ + client = Client(project=get_project()) + engine = create_engine(get_db_url(), connect_args={"client": client}) + with engine.connect() as connection: + assert connection.connection.instance._client == client + + def test_create_engine_w_invalid_client_object(self): + """ + SPANNER TEST: + + Check that if project id in url and custom Client + Object passed to enginer mismatch, error is thrown. + """ + client = Client(project="project_id") + engine = create_engine(get_db_url(), connect_args={"client": client}) + + with pytest.raises(ValueError): + engine.connect() diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 8965eebca5bb..bd77a63f9d53 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -24,7 +24,7 @@ import time from unittest import mock -from google.cloud.spanner_v1 import RequestOptions +from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy from sqlalchemy import create_engine @@ -134,7 +134,7 @@ UnicodeTextTest as _UnicodeTextTest, _UnicodeFixture as __UnicodeFixture, ) -from test._helpers import get_db_url +from test._helpers import get_db_url, get_project config.test_schema = "" @@ -2193,3 +2193,30 @@ def test_request_priority(self): engine = create_engine("sqlite:///database") with engine.connect() as connection: pass + + +class CreateEngineWithClientObjectTest(fixtures.TestBase): + def test_create_engine_w_valid_client_object(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + by passing custom Client object. + """ + client = Client(project=get_project()) + engine = create_engine(get_db_url(), connect_args={"client": client}) + with engine.connect() as connection: + assert connection.connection.instance._client == client + + def test_create_engine_w_invalid_client_object(self): + """ + SPANNER TEST: + + Check that if project id in url and custom Client + Object passed to enginer mismatch, error is thrown. + """ + client = Client(project="project_id") + engine = create_engine(get_db_url(), connect_args={"client": client}) + + with pytest.raises(ValueError): + engine.connect() From b91c50452935b26bdbb4cf579523f7ebeeab23a5 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 11:06:47 +0530 Subject: [PATCH 196/582] chore(main): release 1.4.0 (#313) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 6eebf3d12642..11b0136cf2e0 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.4.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.3.0...v1.4.0) (2023-04-06) + + +### Features + +* User provided client ([#311](https://github.com/googleapis/python-spanner-sqlalchemy/issues/311)) ([5b07111](https://github.com/googleapis/python-spanner-sqlalchemy/commit/5b0711102bb45f5775addbda61cb4da5231c96d7)) + ## [1.3.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.2.2...v1.3.0) (2023-03-20) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 75fcf6b359d2..108c5d32bed2 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.3.0" +__version__ = "1.4.0" From 409ffadc88d5bc8b47396031f2dd270f0d641214 Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Wed, 19 Apr 2023 10:26:58 +0530 Subject: [PATCH 197/582] feat: feat: SQLAlchemy 2.0 support (#314) * feat: SQLAlchemy 2.0 support * sqlalchemy 2.0 support changes * more change for SQLAlchemy 2.0 support * more change for SQLAlchemy 2.0 support * github workflow * fixing reset * fix * changes * changes * skipping test * changes * changes * changes * changes * changes * changes * changes * changes * changes * changes * multi indexes * fix: sqlalchemy 2.0 test cases * temp removing test_has_index * changes * changes * changes * multi_index * multi_index * multi_index * multi_index * changes * changes * changes * multi_index * changes * changes * Changes * Changes * Changes * multi fk * changes * changes * multi_index * changes * changes * changes * changes * changes * changes * changes * changes * fix: test_has_index * changes * changes * changes * fix: test_has_index * fix * fix * changes * changes * changes * fix * changes * changes * changes * fix * adding kokoro test * changes * view test cases * changes * changes * changes * test changes * test changes * lint * docs * review comments * view testing * view testing * view testing * review fixes --------- Co-authored-by: IlyaFaer Co-authored-by: surbhigarg92 --- .../.github/workflows/test_suite.yml | 24 + .../cloud/sqlalchemy_spanner/requirements.py | 15 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 592 +++- packages/sqlalchemy-spanner/noxfile.py | 41 +- .../sqlalchemy-spanner/test/test_suite_13.py | 65 +- .../sqlalchemy-spanner/test/test_suite_14.py | 166 +- .../sqlalchemy-spanner/test/test_suite_20.py | 3002 +++++++++++++++++ 7 files changed, 3761 insertions(+), 144 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/test_suite_20.py diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index dff7941fb463..5d4e2c3020a7 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -87,6 +87,30 @@ jobs: GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging SQLALCHEMY_SILENCE_UBER_WARNING: 1 + compliance_tests_20: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Compliance Tests + run: nox -s compliance_test_20 + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + migration_tests: runs-on: ubuntu-latest diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index ce5e8d53afa6..791a6b10edbd 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -14,6 +14,7 @@ from sqlalchemy.testing import exclusions from sqlalchemy.testing.requirements import SuiteRequirements +from sqlalchemy.testing.exclusions import against, only_on class Requirements(SuiteRequirements): # pragma: no cover @@ -45,6 +46,15 @@ def foreign_key_constraint_name_reflection(self): def schema_reflection(self): return exclusions.open() + @property + def array_type(self): + return only_on([lambda config: against(config, "postgresql")]) + + @property + def uuid_data_type(self): + """Return databases that support the UUID datatype.""" + return only_on(("postgresql >= 8.3", "mariadb >= 10.7.0")) + @property def implicitly_named_constraints(self): return exclusions.open() @@ -99,3 +109,8 @@ def precision_numerics_enotation_large(self): """target backend supports Decimal() objects using E notation to represent very large values.""" return exclusions.open() + + @property + def views(self): + """Target database must support VIEWs.""" + return exclusions.open() diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 12b0e7bd853b..e7a2ba17daa3 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -22,7 +22,8 @@ alter_table, format_type, ) -from sqlalchemy import ForeignKeyConstraint, types, util +from sqlalchemy.exc import NoSuchTableError +from sqlalchemy import ForeignKeyConstraint, types from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect, DefaultExecutionContext from sqlalchemy.event import listens_for @@ -43,19 +44,29 @@ from google.cloud.spanner_v1.data_types import JsonObject from google.cloud import spanner_dbapi from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call +import sqlalchemy + +USING_SQLACLCHEMY_20 = False +if sqlalchemy.__version__.split(".")[0] == "2": + USING_SQLACLCHEMY_20 = True + +if USING_SQLACLCHEMY_20: + from sqlalchemy.engine.reflection import ObjectKind @listens_for(Pool, "reset") -def reset_connection(dbapi_conn, connection_record): +def reset_connection(dbapi_conn, connection_record, reset_state=None): """An event of returning a connection back to a pool.""" - if isinstance(dbapi_conn.connection, spanner_dbapi.Connection): - if dbapi_conn.connection.inside_transaction: - dbapi_conn.connection.rollback() - - dbapi_conn.connection.staleness = None - dbapi_conn.connection.read_only = False + if hasattr(dbapi_conn, "connection"): + dbapi_conn = dbapi_conn.connection + if isinstance(dbapi_conn, spanner_dbapi.Connection): + if dbapi_conn.inside_transaction: + dbapi_conn.rollback() + + dbapi_conn.staleness = None + dbapi_conn.read_only = False else: - dbapi_conn.connection.rollback() + dbapi_conn.rollback() # register a method to get a single value of a JSON object @@ -186,7 +197,7 @@ def _requires_quotes(self, value): return ( lc_value in self.reserved_words or value[0] in self.illegal_initial_characters - or not self.legal_characters.match(util.text_type(value)) + or not self.legal_characters.match(str(value)) or (lc_value != value) ) @@ -206,7 +217,7 @@ def get_from_hint_text(self, _, text): """ return text - def visit_empty_set_expr(self, type_): + def visit_empty_set_expr(self, type_, **kw): """Return an empty set expression of the given type. Args: @@ -365,7 +376,7 @@ def visit_computed_column(self, generated, **kw): ) return text - def visit_drop_table(self, drop_table): + def visit_drop_table(self, drop_table, **kw): """ Cloud Spanner doesn't drop tables which have indexes or foreign key constraints. This method builds several DDL @@ -396,7 +407,7 @@ def visit_drop_table(self, drop_table): return indexes + constrs + str(drop_table) - def visit_primary_key_constraint(self, constraint): + def visit_primary_key_constraint(self, constraint, **kw): """Build primary key definition. Primary key in Spanner is defined outside of a table columns definition, see: @@ -406,7 +417,7 @@ def visit_primary_key_constraint(self, constraint): """ return None - def visit_unique_constraint(self, constraint): + def visit_unique_constraint(self, constraint, **kw): """Unique constraints in Spanner are defined with indexes: https://cloud.google.com/spanner/docs/secondary-indexes#unique-indexes @@ -510,7 +521,8 @@ class SpannerDialect(DefaultDialect): positional = False paramstyle = "format" encoding = "utf-8" - max_identifier_length = 128 + max_identifier_length = 256 + _legacy_binary_type_literal_encoding = "utf-8" execute_sequence_format = list @@ -540,6 +552,14 @@ def dbapi(cls): """ return spanner_dbapi + @classmethod + def import_dbapi(cls): + """A pointer to the Cloud Spanner DB API package. + + Used to initiate connections to the Cloud Spanner databases. + """ + return spanner_dbapi + @property def default_isolation_level(self): """Default isolation level name. @@ -566,6 +586,58 @@ def _get_default_schema_name(self, _): """ return "" + def _get_table_type_query(self, kind, append_query): + """ + Generates WHERE condition for Kind of Object. + Spanner supports Table and View. + """ + if not USING_SQLACLCHEMY_20: + return "" + + kind = ObjectKind.TABLE if kind is None else kind + if kind == ObjectKind.MATERIALIZED_VIEW: + raise NotImplementedError("Spanner does not support MATERIALIZED VIEWS") + switch_case = { + ObjectKind.ANY: ["BASE TABLE", "VIEW"], + ObjectKind.TABLE: ["BASE TABLE"], + ObjectKind.VIEW: ["VIEW"], + ObjectKind.ANY_VIEW: ["VIEW"], + } + + table_type_query = "" + for table_type in switch_case[kind]: + query = f"t.table_type = '{table_type}'" + if table_type_query != "": + table_type_query = table_type_query + " OR " + query + else: + table_type_query = query + + table_type_query = "(" + table_type_query + ") " + if append_query: + table_type_query = table_type_query + " AND " + return table_type_query + + def _get_table_filter_query( + self, filter_names, info_schema_table, append_query=False + ): + """ + Generates WHERE query for tables or views for which + information is reflected. + """ + table_filter_query = "" + if filter_names is not None: + for table_name in filter_names: + query = f"{info_schema_table}.table_name = '{table_name}'" + if table_filter_query != "": + table_filter_query = table_filter_query + " OR " + query + else: + table_filter_query = query + table_filter_query = "(" + table_filter_query + ") " + if append_query: + table_filter_query = table_filter_query + " AND " + + return table_filter_query + def create_connect_args(self, url): """Parse connection args from the given URL. @@ -589,6 +661,19 @@ def create_connect_args(self, url): @engine_to_connection def get_view_names(self, connection, schema=None, **kw): + """ + Gets a list of view names. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name + + Returns: + list: List of view names. + """ sql = """ SELECT table_name FROM information_schema.views @@ -606,56 +691,137 @@ def get_view_names(self, connection, schema=None, **kw): return all_views @engine_to_connection - def get_columns(self, connection, table_name, schema=None, **kw): - """Get the table columns description. + def get_view_definition(self, connection, view_name, schema=None, **kw): + """ + Gets definition of a particular view. The method is used by SQLAlchemy introspection systems. Args: connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. - table_name (str): Name of the table to introspect. + view_name (str): Name of the view. schema (str): Optional. Schema name Returns: - list: The table every column dict-like description. + str: Definition of view. """ sql = """ -SELECT column_name, spanner_type, is_nullable, generation_expression -FROM information_schema.columns -WHERE - table_catalog = '' - AND table_schema = '' - AND table_name = '{}' -ORDER BY - table_catalog, - table_schema, - table_name, - ordinal_position -""".format( - table_name + SELECT view_definition + FROM information_schema.views + WHERE TABLE_SCHEMA='{schema_name}' AND TABLE_NAME='{view_name}' + """.format( + schema_name=schema or "", view_name=view_name + ) + + with connection.connection.database.snapshot() as snap: + rows = list(snap.execute_sql(sql)) + if rows == []: + raise NoSuchTableError(f"{schema if schema else ''}.{view_name}") + result = rows[0][0] + + return result + + @engine_to_connection + def get_multi_columns( + self, connection, schema=None, filter_names=None, scope=None, kind=None, **kw + ): + """ + Return information about columns in all objects in the given + schema. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name + filter_names (Sequence[str]): Optional. Optionally return information + only for the objects listed here. + scope (sqlalchemy.engine.reflection.ObjectScope): Optional. Specifies + if columns of default, temporary or any tables + should be reflected. Spanner does not support temporary. + kind (sqlalchemy.engine.reflection.ObjectKind): Optional. Specifies the + type of objects to reflect. + + Returns: + dictionary: a dictionary where the keys are two-tuple schema,table-name + and the values are list of dictionaries, each representing the + definition of a database column. + The schema is ``None`` if no schema is provided. + """ + table_filter_query = self._get_table_filter_query(filter_names, "col", True) + schema_filter_query = " col.table_schema = '{schema}' AND ".format( + schema=schema or "" ) + table_type_query = self._get_table_type_query(kind, True) - cols_desc = [] + sql = """ + SELECT col.table_schema, col.table_name, col.column_name, + col.spanner_type, col.is_nullable, col.generation_expression + FROM information_schema.columns as col + JOIN information_schema.tables AS t + ON col.table_name = t.table_name + WHERE + {table_filter_query} + {table_type_query} + {schema_filter_query} + col.table_catalog = '' + ORDER BY + col.table_catalog, + col.table_schema, + col.table_name, + col.ordinal_position + """.format( + table_filter_query=table_filter_query, + table_type_query=table_type_query, + schema_filter_query=schema_filter_query, + ) with connection.connection.database.snapshot() as snap: - columns = snap.execute_sql(sql) + columns = list(snap.execute_sql(sql)) + result_dict = {} for col in columns: - col_desc = { - "name": col[0], - "type": self._designate_type(col[1]), - "nullable": col[2] == "YES", + column_info = { + "name": col[2], + "type": self._designate_type(col[3]), + "nullable": col[4] == "YES", "default": None, } - if col[3] is not None: - col_desc["computed"] = { + if col[5] is not None: + column_info["computed"] = { "persisted": True, - "sqltext": col[3], + "sqltext": col[5], } - cols_desc.append(col_desc) + col[0] = col[0] or None + table_info = result_dict.get((col[0], col[1]), []) + table_info.append(column_info) + result_dict[(col[0], col[1])] = table_info + + return result_dict + + @engine_to_connection + def get_columns(self, connection, table_name, schema=None, **kw): + """Get the table columns description. + + The method is used by SQLAlchemy introspection systems. - return cols_desc + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + list: The table every column dict-like description. + """ + kind = None if not USING_SQLACLCHEMY_20 else ObjectKind.ANY + dict = self.get_multi_columns( + connection, schema=schema, filter_names=[table_name], kind=kind + ) + schema = schema or None + return dict.get((schema, table_name), []) def _designate_type(self, str_repr): """ @@ -684,6 +850,87 @@ def _designate_type(self, str_repr): else: return _type_map[str_repr] + @engine_to_connection + def get_multi_indexes( + self, connection, schema=None, filter_names=None, scope=None, kind=None, **kw + ): + """ + Return information about indexes in all objects + in the given schema. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name. + filter_names (Sequence[str]): Optional. Optionally return information + only for the objects listed here. + scope (sqlalchemy.engine.reflection.ObjectScope): Optional. Specifies + if columns of default, temporary or any tables + should be reflected. Spanner does not support temporary. + kind (sqlalchemy.engine.reflection.ObjectKind): Optional. Specifies the + type of objects to reflect. + + Returns: + dictionary: a dictionary where the keys are two-tuple schema,table-name + and the values are list of dictionaries, each representing the + definition of an index. + The schema is ``None`` if no schema is provided. + """ + table_filter_query = self._get_table_filter_query(filter_names, "i", True) + schema_filter_query = " i.table_schema = '{schema}' AND ".format( + schema=schema or "" + ) + table_type_query = self._get_table_type_query(kind, True) + + sql = """ + SELECT + i.table_schema, + i.table_name, + i.index_name, + ARRAY_AGG(ic.column_name), + i.is_unique, + ARRAY_AGG(ic.column_ordering) + FROM information_schema.indexes as i + JOIN information_schema.index_columns AS ic + ON ic.index_name = i.index_name AND ic.table_name = i.table_name + JOIN information_schema.tables AS t + ON i.table_name = t.table_name + WHERE + {table_filter_query} + {table_type_query} + {schema_filter_query} + i.index_type != 'PRIMARY_KEY' + AND i.spanner_is_managed = FALSE + GROUP BY i.table_schema, i.table_name, i.index_name, i.is_unique + ORDER BY i.index_name + """.format( + table_filter_query=table_filter_query, + table_type_query=table_type_query, + schema_filter_query=schema_filter_query, + ) + + with connection.connection.database.snapshot() as snap: + rows = list(snap.execute_sql(sql)) + result_dict = {} + + for row in rows: + index_info = { + "name": row[2], + "column_names": row[3], + "unique": row[4], + "column_sorting": { + col: order for col, order in zip(row[3], row[5]) + }, + } + row[0] = row[0] or None + table_info = result_dict.get((row[0], row[1]), []) + table_info.append(index_info) + result_dict[(row[0], row[1])] = table_info + + return result_dict + @engine_to_connection def get_indexes(self, connection, table_name, schema=None, **kw): """Get the table indexes. @@ -699,41 +946,75 @@ def get_indexes(self, connection, table_name, schema=None, **kw): Returns: list: List with indexes description. """ + kind = None if not USING_SQLACLCHEMY_20 else ObjectKind.ANY + dict = self.get_multi_indexes( + connection, schema=schema, filter_names=[table_name], kind=kind + ) + schema = schema or None + return dict.get((schema, table_name), []) + + @engine_to_connection + def get_multi_pk_constraint( + self, connection, schema=None, filter_names=None, scope=None, kind=None, **kw + ): + """ + Return information about primary key constraints in + all tables in the given schema. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name + filter_names (Sequence[str]): Optional. Optionally return information + only for the objects listed here. + scope (sqlalchemy.engine.reflection.ObjectScope): Optional. Specifies + if columns of default, temporary or any tables + should be reflected. Spanner does not support temporary. + kind (sqlalchemy.engine.reflection.ObjectKind): Optional. Specifies the + type of objects to reflect. + + Returns: + dictionary: a dictionary where the keys are two-tuple schema,table-name + and the values are list of dictionaries, each representing the + definition of a primary key constraint. + The schema is ``None`` if no schema is provided. + """ + table_filter_query = self._get_table_filter_query(filter_names, "tc", True) + schema_filter_query = " tc.table_schema = '{schema}' AND ".format( + schema=schema or "" + ) + table_type_query = self._get_table_type_query(kind, True) + sql = """ -SELECT - i.index_name, - ARRAY_AGG(ic.column_name), - i.is_unique, - ARRAY_AGG(ic.column_ordering) -FROM information_schema.indexes as i -JOIN information_schema.index_columns AS ic - ON ic.index_name = i.index_name AND ic.table_name = i.table_name -WHERE - i.table_name="{table_name}" - AND i.index_type != 'PRIMARY_KEY' - AND i.spanner_is_managed = FALSE -GROUP BY i.index_name, i.is_unique -ORDER BY i.index_name -""".format( - table_name=table_name + SELECT tc.table_schema, tc.table_name, ccu.COLUMN_NAME + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc + JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu + ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + JOIN information_schema.tables AS t + ON tc.table_name = t.table_name + WHERE {table_filter_query} {table_type_query} + {schema_filter_query} tc.CONSTRAINT_TYPE = "PRIMARY KEY" + """.format( + table_filter_query=table_filter_query, + table_type_query=table_type_query, + schema_filter_query=schema_filter_query, ) - ind_desc = [] with connection.connection.database.snapshot() as snap: - rows = snap.execute_sql(sql) + rows = list(snap.execute_sql(sql)) + result_dict = {} for row in rows: - ind_desc.append( - { - "name": row[0], - "column_names": row[1], - "unique": row[2], - "column_sorting": { - col: order for col, order in zip(row[1], row[3]) - }, - } + row[0] = row[0] or None + table_info = result_dict.get( + (row[0], row[1]), {"constrained_columns": []} ) - return ind_desc + table_info["constrained_columns"].append(row[2]) + result_dict[(row[0], row[1])] = table_info + + return result_dict @engine_to_connection def get_pk_constraint(self, connection, table_name, schema=None, **kw): @@ -750,24 +1031,12 @@ def get_pk_constraint(self, connection, table_name, schema=None, **kw): Returns: dict: Dict with the primary key constraint description. """ - sql = """ -SELECT ccu.COLUMN_NAME -FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc -JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu - ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME -WHERE tc.TABLE_NAME="{table_name}" AND tc.CONSTRAINT_TYPE = "PRIMARY KEY" -""".format( - table_name=table_name + kind = None if not USING_SQLACLCHEMY_20 else ObjectKind.ANY + dict = self.get_multi_pk_constraint( + connection, schema=schema, filter_names=[table_name], kind=kind ) - - cols = [] - with connection.connection.database.snapshot() as snap: - rows = snap.execute_sql(sql) - - for row in rows: - cols.append(row[0]) - - return {"constrained_columns": cols} + schema = schema or None + return dict.get((schema, table_name), []) @engine_to_connection def get_schema_names(self, connection, **kw): @@ -792,51 +1061,79 @@ def get_schema_names(self, connection, **kw): return schemas @engine_to_connection - def get_foreign_keys(self, connection, table_name, schema=None, **kw): - """Get the table foreign key constraints. + def get_multi_foreign_keys( + self, connection, schema=None, filter_names=None, scope=None, kind=None, **kw + ): + """ + Return information about foreign_keys in all tables + in the given schema. The method is used by SQLAlchemy introspection systems. Args: connection (sqlalchemy.engine.base.Connection): SQLAlchemy connection or engine object. - table_name (str): Name of the table to introspect. schema (str): Optional. Schema name + filter_names (Sequence[str]): Optional. Optionally return information + only for the objects listed here. + scope (sqlalchemy.engine.reflection.ObjectScope): Optional. Specifies + if columns of default, temporary or any tables + should be reflected. Spanner does not support temporary. + kind (sqlalchemy.engine.reflection.ObjectKind): Optional. Specifies the + type of objects to reflect. Returns: - list: Dicts, each of which describes a foreign key constraint. + dictionary: a dictionary where the keys are two-tuple schema,table-name + and the values are list of dictionaries, each representing + a foreign key definition. + The schema is ``None`` if no schema is provided. """ - sql = """ -SELECT - tc.constraint_name, - ctu.table_name, - ctu.table_schema, - ARRAY_AGG(DISTINCT ccu.column_name), - ARRAY_AGG( - DISTINCT CONCAT( - CAST(kcu.ordinal_position AS STRING), - '_____', - kcu.column_name + table_filter_query = self._get_table_filter_query(filter_names, "tc", True) + schema_filter_query = " tc.table_schema = '{schema}' AND".format( + schema=schema or "" ) - ) -FROM information_schema.table_constraints AS tc -JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name -JOIN information_schema.constraint_table_usage AS ctu - ON ctu.constraint_name = tc.constraint_name -JOIN information_schema.key_column_usage AS kcu - ON kcu.constraint_name = tc.constraint_name -WHERE - tc.table_name="{table_name}" - AND tc.constraint_type = "FOREIGN KEY" -GROUP BY tc.constraint_name, ctu.table_name, ctu.table_schema -""".format( - table_name=table_name + table_type_query = self._get_table_type_query(kind, True) + + sql = """ + SELECT + tc.table_schema, + tc.table_name, + tc.constraint_name, + ctu.table_name, + ctu.table_schema, + ARRAY_AGG(DISTINCT ccu.column_name), + ARRAY_AGG( + DISTINCT CONCAT( + CAST(kcu.ordinal_position AS STRING), + '_____', + kcu.column_name + ) + ) + FROM information_schema.table_constraints AS tc + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + JOIN information_schema.constraint_table_usage AS ctu + ON ctu.constraint_name = tc.constraint_name + JOIN information_schema.key_column_usage AS kcu + ON kcu.constraint_name = tc.constraint_name + JOIN information_schema.tables AS t + ON tc.table_name = t.table_name + WHERE + {table_filter_query} + {table_type_query} + {schema_filter_query} + tc.constraint_type = "FOREIGN KEY" + GROUP BY tc.table_name, tc.table_schema, tc.constraint_name, + ctu.table_name, ctu.table_schema + """.format( + table_filter_query=table_filter_query, + table_type_query=table_type_query, + schema_filter_query=schema_filter_query, ) - keys = [] with connection.connection.database.snapshot() as snap: - rows = snap.execute_sql(sql) + rows = list(snap.execute_sql(sql)) + result_dict = {} for row in rows: # Due to Spanner limitations, arrays order is not guaranteed during @@ -851,20 +1148,45 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw): # # The solution seem a bit clumsy, and should be improved as soon as a # better approach found. - for index, value in enumerate(sorted(row[4])): - row[4][index] = value.split("_____")[1] - - keys.append( - { - "name": row[0], - "referred_table": row[1], - "referred_schema": row[2] or None, - "referred_columns": row[3], - "constrained_columns": row[4], - } - ) + row[0] = row[0] or None + table_info = result_dict.get((row[0], row[1]), []) + for index, value in enumerate(sorted(row[6])): + row[6][index] = value.split("_____")[1] + + fk_info = { + "name": row[2], + "referred_table": row[3], + "referred_schema": row[4] or None, + "referred_columns": row[5], + "constrained_columns": row[6], + } + + table_info.append(fk_info) + result_dict[(row[0], row[1])] = table_info + + return result_dict + + @engine_to_connection + def get_foreign_keys(self, connection, table_name, schema=None, **kw): + """Get the table foreign key constraints. + + The method is used by SQLAlchemy introspection systems. - return keys + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + table_name (str): Name of the table to introspect. + schema (str): Optional. Schema name + + Returns: + list: Dicts, each of which describes a foreign key constraint. + """ + kind = None if not USING_SQLACLCHEMY_20 else ObjectKind.ANY + dict = self.get_multi_foreign_keys( + connection, schema=schema, filter_names=[table_name], kind=kind + ) + schema = schema or None + return dict.get((schema, table_name), []) @engine_to_connection def get_table_names(self, connection, schema=None, **kw): @@ -883,9 +1205,9 @@ def get_table_names(self, connection, schema=None, **kw): sql = """ SELECT table_name FROM information_schema.tables -WHERE table_schema = '{}' +WHERE table_type = 'BASE TABLE' AND table_schema = '{schema}' """.format( - schema or "" + schema=schema or "" ) table_names = [] @@ -937,7 +1259,7 @@ def get_unique_constraints(self, connection, table_name, schema=None, **kw): return cols @engine_to_connection - def has_table(self, connection, table_name, schema=None): + def has_table(self, connection, table_name, schema=None, **kw): """Check if the given table exists. The method is used by SQLAlchemy introspection systems. diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 7405974492b4..394269df5abe 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -165,6 +165,7 @@ def compliance_test_13(session): "--cov-fail-under=0", "--asyncio-mode=auto", "test/test_suite_13.py", + *session.posargs, ) @@ -193,7 +194,6 @@ def compliance_test_14(session): session.install("-e", ".[tracing]") session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") session.run("python", "create_test_database.py") - session.run( "py.test", "--cov=google.cloud.sqlalchemy_spanner", @@ -204,6 +204,45 @@ def compliance_test_14(session): "--cov-fail-under=0", "--asyncio-mode=auto", "test/test_suite_14.py", + *session.posargs, + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def compliance_test_20(session): + """Run SQLAlchemy dialect compliance test suite.""" + + # Sanity check: Only run tests if the environment variable is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( + "SPANNER_EMULATOR_HOST", "" + ): + session.skip( + "Credentials or emulator host must be set via environment variable" + ) + + session.install( + "pytest", + "pytest-cov", + "pytest-asyncio", + ) + + session.install("mock") + session.install("-e", ".[tracing]") + session.run("python", "create_test_database.py") + + session.install("sqlalchemy>=2.0") + + session.run( + "py.test", + "--cov=google.cloud.sqlalchemy_spanner", + "--cov=test", + "--cov-append", + "--cov-config=.coveragerc", + "--cov-report=", + "--cov-fail-under=0", + "--asyncio-mode=auto", + "test/test_suite_20.py", + *session.posargs, ) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index e519dd4ba5fc..a5b2e3bb1a02 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -526,6 +526,34 @@ class UnicodeTextTest(UnicodeFixtureTest, _UnicodeTextTest): class ComponentReflectionTest(_ComponentReflectionTest): + @classmethod + def define_views(cls, metadata, schema): + table_info = { + "users": ["user_id", "test1", "test2"], + "email_addresses": ["address_id", "remote_user_id", "email_address"], + } + if testing.requires.self_referential_foreign_keys.enabled: + table_info["users"] = table_info["users"] + ["parent_user_id"] + for table_name in ("users", "email_addresses"): + fullname = table_name + if schema: + fullname = "%s.%s" % (schema, table_name) + view_name = fullname + "_v" + columns = "" + for column in table_info[table_name]: + stmt = table_name + "." + column + " AS " + column + if columns: + columns = columns + ", " + stmt + else: + columns = stmt + query = f"""CREATE VIEW {view_name} + SQL SECURITY INVOKER + AS SELECT {columns} + FROM {fullname}""" + + event.listen(metadata, "after_create", DDL(query)) + event.listen(metadata, "before_drop", DDL("DROP VIEW %s" % view_name)) + @classmethod def define_reflected_tables(cls, metadata, schema): if schema: @@ -665,11 +693,24 @@ def define_reflected_tables(cls, metadata, schema): sqlalchemy.Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) - if testing.requires.view_column_reflection.enabled: + if testing.requires.view_column_reflection.enabled and not bool( + os.environ.get("SPANNER_EMULATOR_HOST") + ): cls.define_views(metadata, schema) if not schema and testing.requires.temp_table_reflection.enabled: cls.define_temp_tables(metadata) + def _test_get_columns(self, schema=None, table_type="table"): + if table_type == "view" and bool(os.environ.get("SPANNER_EMULATOR_HOST")): + pytest.skip("View tables not supported on emulator") + super()._test_get_columns(schema, table_type) + + @testing.provide_metadata + def _test_get_view_definition(self, schema=None): + if bool(os.environ.get("SPANNER_EMULATOR_HOST")): + pytest.skip("View tables not supported on emulator") + super()._test_get_view_definition(schema) + @classmethod def define_temp_tables(cls, metadata): """ @@ -858,7 +899,7 @@ def _test_get_table_names(self, schema=None, table_type="table", order_by=None): insp = inspect(meta.bind) - if table_type == "view": + if table_type == "view" and not bool(os.environ.get("SPANNER_EMULATOR_HOST")): table_names = insp.get_view_names(schema) table_names.sort() answer = ["email_addresses_v", "users_v"] @@ -921,14 +962,14 @@ def test_array_reflection(self): str_array = ARRAY(String(16)) int_array = ARRAY(Integer) - Table( + arrays_test = Table( "arrays_test", orig_meta, Column("id", Integer, primary_key=True), Column("str_array", str_array), Column("int_array", int_array), ) - orig_meta.create_all() + arrays_test.create(create_engine(get_db_url())) # autoload the table and check its columns reflection tab = Table("arrays_test", orig_meta, autoload=True) @@ -969,6 +1010,22 @@ def test_fk_column_order(self): eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) + @testing.requires.primary_key_constraint_reflection + def test_pk_column_order(self, connection): + """ + SPANNER OVERRIDE: + Emultor doesn't support returning pk sorted by ordinal value + of columns. + """ + insp = inspect(connection) + primary_key = insp.get_pk_constraint(self.tables.tb1.name) + exp = ( + ["id", "name", "attr"] + if bool(os.environ.get("SPANNER_EMULATOR_HOST")) + else ["name", "id", "attr"] + ) + eq_(primary_key.get("constrained_columns"), exp) + class RowFetchTest(_RowFetchTest): def test_row_w_scalar_select(self): diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index bd77a63f9d53..a13477b3941e 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -60,6 +60,7 @@ from sqlalchemy.types import Text from sqlalchemy.testing import requires from sqlalchemy.testing import is_true +from sqlalchemy import types as sql_types from sqlalchemy.testing.fixtures import ( ComputedReflectionFixtureTest as _ComputedReflectionFixtureTest, ) @@ -229,6 +230,34 @@ def test_binary_reflection(self, connection, metadata): class ComponentReflectionTest(_ComponentReflectionTest): + @classmethod + def define_views(cls, metadata, schema): + table_info = { + "users": ["user_id", "test1", "test2"], + "email_addresses": ["address_id", "remote_user_id", "email_address"], + } + if testing.requires.self_referential_foreign_keys.enabled: + table_info["users"] = table_info["users"] + ["parent_user_id"] + for table_name in ("users", "email_addresses"): + fullname = table_name + if schema: + fullname = "%s.%s" % (schema, table_name) + view_name = fullname + "_v" + columns = "" + for column in table_info[table_name]: + stmt = table_name + "." + column + " AS " + column + if columns: + columns = columns + ", " + stmt + else: + columns = stmt + query = f"""CREATE VIEW {view_name} + SQL SECURITY INVOKER + AS SELECT {columns} + FROM {fullname}""" + + event.listen(metadata, "after_create", DDL(query)) + event.listen(metadata, "before_drop", DDL("DROP VIEW %s" % view_name)) + @classmethod def define_tables(cls, metadata): cls.define_reflected_tables(metadata, None) @@ -374,9 +403,102 @@ def define_reflected_tables(cls, metadata, schema): sqlalchemy.Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) - if testing.requires.view_column_reflection.enabled: + if testing.requires.view_column_reflection.enabled and not bool( + os.environ.get("SPANNER_EMULATOR_HOST") + ): cls.define_views(metadata, schema) + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + @testing.requires.view_reflection + @testing.combinations( + (False,), (True, testing.requires.schemas), argnames="use_schema" + ) + def test_get_view_definition(self, connection, use_schema): + if use_schema: + schema = config.test_schema + else: + schema = None + view_name1 = "users_v" + view_name2 = "email_addresses_v" + insp = inspect(connection) + v1 = insp.get_view_definition(view_name1, schema=schema) + self.assert_(v1) + v2 = insp.get_view_definition(view_name2, schema=schema) + self.assert_(v2) + + @testing.combinations( + (False, False), + (False, True, testing.requires.schemas), + (True, False, testing.requires.view_reflection), + ( + True, + True, + testing.requires.schemas + testing.requires.view_reflection, + ), + argnames="use_views,use_schema", + ) + def test_get_columns(self, connection, use_views, use_schema): + if use_views and bool(os.environ.get("SPANNER_EMULATOR_HOST")): + pytest.skip("Skipped on emulator") + + schema = None + users, addresses = (self.tables.users, self.tables.email_addresses) + if use_views: + table_names = ["users_v", "email_addresses_v"] + else: + table_names = ["users", "email_addresses"] + + insp = inspect(connection) + for table_name, table in zip(table_names, (users, addresses)): + schema_name = schema + cols = insp.get_columns(table_name, schema=schema_name) + self.assert_(len(cols) > 0, len(cols)) + + # should be in order + + for i, col in enumerate(table.columns): + eq_(col.name, cols[i]["name"]) + ctype = cols[i]["type"].__class__ + ctype_def = col.type + if isinstance(ctype_def, sqlalchemy.types.TypeEngine): + ctype_def = ctype_def.__class__ + + # Oracle returns Date for DateTime. + + if testing.against("oracle") and ctype_def in ( + sql_types.Date, + sql_types.DateTime, + ): + ctype_def = sql_types.Date + + # assert that the desired type and return type share + # a base within one of the generic types. + + self.assert_( + len( + set(ctype.__mro__) + .intersection(ctype_def.__mro__) + .intersection( + [ + sql_types.Integer, + sql_types.Numeric, + sql_types.DateTime, + sql_types.Date, + sql_types.Time, + sql_types.String, + sql_types._Binary, + ] + ) + ) + > 0, + "%s(%s), %s(%s)" % (col.name, col.type, cols[i]["name"], ctype), + ) + + if not col.primary_key: + assert cols[i]["default"] is None + @testing.combinations((False,), argnames="use_schema") @testing.requires.foreign_key_constraint_reflection def test_get_foreign_keys(self, connection, use_schema): @@ -669,7 +791,7 @@ def _test_get_table_names(self, schema=None, table_type="table", order_by=None): insp = inspect(meta.bind) - if table_type == "view": + if table_type == "view" and not bool(os.environ.get("SPANNER_EMULATOR_HOST")): table_names = insp.get_view_names(schema) table_names.sort() answer = ["email_addresses_v", "users_v"] @@ -730,6 +852,22 @@ def test_fk_column_order(self): eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) + @testing.requires.primary_key_constraint_reflection + def test_pk_column_order(self, connection): + """ + SPANNER OVERRIDE: + Emultor doesn't support returning pk sorted by ordinal value + of columns. + """ + insp = inspect(connection) + primary_key = insp.get_pk_constraint(self.tables.tb1.name) + exp = ( + ["id", "name", "attr"] + if bool(os.environ.get("SPANNER_EMULATOR_HOST")) + else ["name", "id", "attr"] + ) + eq_(primary_key.get("constrained_columns"), exp) + @pytest.mark.skip("Spanner doesn't support quotes in table names.") class QuotedNameArgumentTest(_QuotedNameArgumentTest): @@ -972,6 +1110,9 @@ def test_simple_limit_expr_offset(self, connection): def test_bound_offset(self, connection): pass + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) def test_limit_render_multiple_times(self, connection): table = self.tables.some_table stmt = select(table.c.id).limit(1).scalar_subquery() @@ -981,7 +1122,16 @@ def test_limit_render_multiple_times(self, connection): self._assert_result( connection, u, - [(2,)], + [(1,)], + ) + + @testing.requires.offset + def test_simple_offset(self, connection): + table = self.tables.some_table + self._assert_result( + connection, + select(table).order_by(table.c.id).offset(2), + [(3, 3, 4), (4, 4, 5), (5, 4, 6)], ) @@ -1827,6 +1977,14 @@ def define_tables(cls, metadata): def test_has_table_schema(self): pass + @testing.requires.views + def test_has_table_view(self, connection): + pass + + @testing.requires.views + def test_has_table_view_schema(self, connection): + pass + class PostCompileParamsTest(_PostCompileParamsTest): def test_execute(self): @@ -2048,7 +2206,7 @@ class JSONTest(_JSONTest): def test_single_element_round_trip(self, element): pass - def _test_round_trip(self, data_element): + def _test_round_trip(self, data_element, connection): data_table = self.tables.data_table config.db.execute( diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py new file mode 100644 index 000000000000..fb59b7250727 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -0,0 +1,3002 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import timezone +import decimal +import operator +import os +import pkg_resources +import pytest +import random +import time +from unittest import mock + +from google.cloud.spanner_v1 import RequestOptions +import sqlalchemy +from sqlalchemy import create_engine +from sqlalchemy.engine import Inspector +from sqlalchemy import inspect +from sqlalchemy import testing +from sqlalchemy import ForeignKey +from sqlalchemy import MetaData +from sqlalchemy.engine import ObjectKind +from sqlalchemy.engine import ObjectScope +from sqlalchemy.schema import DDL +from sqlalchemy.schema import Computed +from sqlalchemy.testing import config +from sqlalchemy.testing import engines +from sqlalchemy.testing import eq_ +from sqlalchemy.testing import provide_metadata, emits_warning +from sqlalchemy.testing import fixtures +from sqlalchemy.testing.provision import temp_table_keyword_args +from sqlalchemy.testing.schema import Column +from sqlalchemy.testing.schema import Table +from sqlalchemy import literal_column +from sqlalchemy import select +from sqlalchemy import util +from sqlalchemy import union +from sqlalchemy import event +from sqlalchemy import exists +from sqlalchemy import Boolean +from sqlalchemy import Float +from sqlalchemy import LargeBinary +from sqlalchemy import String +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship +from sqlalchemy.orm import Session +from sqlalchemy.types import Integer +from sqlalchemy.types import Numeric +from sqlalchemy.types import Text +from sqlalchemy.testing import requires +from sqlalchemy.testing import is_true +from sqlalchemy import Index +from sqlalchemy import types +from sqlalchemy.testing.fixtures import ( + ComputedReflectionFixtureTest as _ComputedReflectionFixtureTest, +) + +from google.api_core.datetime_helpers import DatetimeWithNanoseconds + +from google.cloud import spanner_dbapi + +from sqlalchemy.testing.suite.test_cte import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_ddl import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_dialect import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_insert import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_deprecations import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_unicode_ddl import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest +from sqlalchemy.testing.suite.test_ddl import TableDDLTest as _TableDDLTest +from sqlalchemy.testing.suite.test_ddl import ( + FutureTableDDLTest as _FutureTableDDLTest, + LongNameBlowoutTest as _LongNameBlowoutTest, +) +from sqlalchemy.testing.suite.test_update_delete import ( + SimpleUpdateDeleteTest as _SimpleUpdateDeleteTest, +) +from sqlalchemy.testing.suite.test_dialect import ( + DifficultParametersTest as _DifficultParametersTest, + EscapingTest as _EscapingTest, + ReturningGuardsTest as _ReturningGuardsTest, +) +from sqlalchemy.testing.suite.test_insert import ( + InsertBehaviorTest as _InsertBehaviorTest, +) +from sqlalchemy.testing.suite.test_select import ( # noqa: F401, F403 + CompoundSelectTest as _CompoundSelectTest, + ExistsTest as _ExistsTest, + FetchLimitOffsetTest as _FetchLimitOffsetTest, + IdentityAutoincrementTest as _IdentityAutoincrementTest, + IsOrIsNotDistinctFromTest as _IsOrIsNotDistinctFromTest, + LikeFunctionsTest as _LikeFunctionsTest, + OrderByLabelTest as _OrderByLabelTest, + PostCompileParamsTest as _PostCompileParamsTest, + SameNamedSchemaTableTest as _SameNamedSchemaTableTest, +) +from sqlalchemy.testing.suite.test_reflection import ( # noqa: F401, F403 + ComponentReflectionTestExtra as _ComponentReflectionTestExtra, + QuotedNameArgumentTest as _QuotedNameArgumentTest, + ComponentReflectionTest as _ComponentReflectionTest, + CompositeKeyReflectionTest as _CompositeKeyReflectionTest, + ComputedReflectionTest as _ComputedReflectionTest, + HasIndexTest as _HasIndexTest, + HasTableTest as _HasTableTest, +) +from sqlalchemy.testing.suite.test_results import ( + RowFetchTest as _RowFetchTest, +) +from sqlalchemy.testing.suite.test_types import ( # noqa: F401, F403 + BooleanTest as _BooleanTest, + DateTest as _DateTest, + _DateFixture as __DateFixture, + DateTimeHistoricTest, + DateTimeCoercedToDateTimeTest as _DateTimeCoercedToDateTimeTest, + DateTimeMicrosecondsTest as _DateTimeMicrosecondsTest, + DateTimeTest as _DateTimeTest, + IntegerTest as _IntegerTest, + JSONTest as _JSONTest, + _LiteralRoundTripFixture, + NumericTest as _NumericTest, + StringTest as _StringTest, + TextTest as _TextTest, + TimeTest as _TimeTest, + TimeMicrosecondsTest as _TimeMicrosecondsTest, + TimestampMicrosecondsTest, + UnicodeVarcharTest as _UnicodeVarcharTest, + UnicodeTextTest as _UnicodeTextTest, + _UnicodeFixture as __UnicodeFixture, +) # noqa: F401, F403 +from test._helpers import get_db_url + +config.test_schema = "" + + +class BooleanTest(_BooleanTest): + @pytest.mark.skip( + "The original test case was split into 2 parts: " + "test_render_literal_bool_true and test_render_literal_bool_false" + ) + def test_render_literal_bool(self): + pass + + def test_render_literal_bool_true(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip(Boolean(), [True], [True]) + + def test_render_literal_bool_false(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip(Boolean(), [False], [False]) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_whereclause(self): + pass + + +class ComponentReflectionTestExtra(_ComponentReflectionTestExtra): + @testing.requires.table_reflection + def test_nullable_reflection(self, connection, metadata): + t = Table( + "t", + metadata, + Column("a", Integer, nullable=True), + Column("b", Integer, nullable=False), + ) + t.create(connection) + connection.connection.commit() + eq_( + dict( + (col["name"], col["nullable"]) + for col in inspect(connection).get_columns("t") + ), + {"a": True, "b": False}, + ) + + def _type_round_trip(self, connection, metadata, *types): + t = Table( + "t", metadata, *[Column("t%d" % i, type_) for i, type_ in enumerate(types)] + ) + t.create(connection) + connection.connection.commit() + + return [c["type"] for c in inspect(connection).get_columns("t")] + + @testing.requires.table_reflection + def test_numeric_reflection(self, connection, metadata): + """ + SPANNER OVERRIDE: + + Spanner defines NUMERIC type with the constant precision=38 + and scale=9. Overriding the test to check if the NUMERIC + column is successfully created and has dimensions + correct for Cloud Spanner. + """ + for typ in self._type_round_trip(connection, metadata, Numeric(18, 5)): + assert isinstance(typ, Numeric) + eq_(typ.precision, 38) + eq_(typ.scale, 9) + + @testing.requires.table_reflection + def test_binary_reflection(self, connection, metadata): + """ + Check that a BYTES column with an explicitly + set size is correctly reflected. + """ + for typ in self._type_round_trip(connection, metadata, LargeBinary(20)): + assert isinstance(typ, LargeBinary) + eq_(typ.length, 20) + + +class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): + @classmethod + def define_tables(cls, metadata): + """SPANNER OVERRIDE: + + Avoid using default values for computed columns. + """ + Table( + "computed_default_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_col", Integer, Computed("normal + 42")), + Column("with_default", Integer), + ) + + t = Table( + "computed_column_table", + metadata, + Column("id", Integer, primary_key=True), + Column("normal", Integer), + Column("computed_no_flag", Integer, Computed("normal + 42")), + ) + + if testing.requires.computed_columns_virtual.enabled: + t.append_column( + Column( + "computed_virtual", + Integer, + Computed("normal + 2", persisted=False), + ) + ) + if testing.requires.computed_columns_stored.enabled: + t.append_column( + Column( + "computed_stored", + Integer, + Computed("normal - 42", persisted=True), + ) + ) + + +class ComputedReflectionTest(_ComputedReflectionTest, ComputedReflectionFixtureTest): + @testing.requires.schemas + def test_get_column_returns_persisted_with_schema(self): + insp = inspect(config.db) + + cols = insp.get_columns("computed_column_table", schema=config.test_schema) + data = {c["name"]: c for c in cols} + + self.check_column( + data, + "computed_no_flag", + "normal+42", + testing.requires.computed_columns_default_persisted.enabled, + ) + if testing.requires.computed_columns_virtual.enabled: + self.check_column( + data, + "computed_virtual", + "normal/2", + False, + ) + if testing.requires.computed_columns_stored.enabled: + self.check_column( + data, + "computed_stored", + "normal-42", + True, + ) + + @pytest.mark.skip("Default values are not supported.") + def test_computed_col_default_not_set(self): + pass + + def test_get_column_returns_computed(self): + """ + SPANNER OVERRIDE: + + In Spanner all the generated columns are STORED, + meaning there are no persisted and not persisted + (in the terms of the SQLAlchemy) columns. The + method override omits the persistence reflection checks. + """ + insp = inspect(config.db) + + cols = insp.get_columns("computed_default_table") + data = {c["name"]: c for c in cols} + for key in ("id", "normal", "with_default"): + is_true("computed" not in data[key]) + compData = data["computed_col"] + is_true("computed" in compData) + is_true("sqltext" in compData["computed"]) + eq_(self.normalize(compData["computed"]["sqltext"]), "normal+42") + + def test_create_not_null_computed_column(self, connection): + """ + SPANNER TEST: + + Check that on creating a computed column with a NOT NULL + clause the clause is set in front of the computed column + statement definition and doesn't cause failures. + """ + metadata = MetaData() + + Table( + "Singers", + metadata, + Column("SingerId", String(36), primary_key=True, nullable=False), + Column("FirstName", String(200)), + Column("LastName", String(200), nullable=False), + Column( + "FullName", + String(400), + Computed("COALESCE(FirstName || ' ', '') || LastName"), + nullable=False, + ), + ) + + metadata.create_all(connection) + + +class ComponentReflectionTest(_ComponentReflectionTest): + @pytest.mark.skip("Skip") + def test_not_existing_table(self, method, connection): + pass + + @classmethod + def define_tables(cls, metadata): + cls.define_reflected_tables(metadata, None) + + @classmethod + def define_views(cls, metadata, schema): + table_info = { + "dingalings": [ + "dingaling_id", + "address_id", + "data", + "id_user", + ], + "users": ["user_id", "test1", "test2"], + "email_addresses": ["address_id", "remote_user_id", "email_address"], + } + if testing.requires.self_referential_foreign_keys.enabled: + table_info["users"] = table_info["users"] + ["parent_user_id"] + if testing.requires.materialized_views.enabled: + materialized = {"dingalings"} + else: + materialized = set() + for table_name in ("users", "email_addresses", "dingalings"): + fullname = table_name + if schema: + fullname = f"{schema}.{table_name}" + view_name = fullname + "_v" + prefix = "MATERIALIZED " if table_name in materialized else "" + columns = "" + for column in table_info[table_name]: + stmt = table_name + "." + column + " AS " + column + if columns: + columns = columns + ", " + stmt + else: + columns = stmt + query = f"""CREATE {prefix}VIEW {view_name} + SQL SECURITY INVOKER + AS SELECT {columns} + FROM {fullname}""" + + event.listen(metadata, "after_create", DDL(query)) + if table_name in materialized: + index_name = "mat_index" + if schema and testing.against("oracle"): + index_name = f"{schema}.{index_name}" + idx = f"CREATE INDEX {index_name} ON {view_name}(data)" + event.listen(metadata, "after_create", DDL(idx)) + event.listen(metadata, "before_drop", DDL(f"DROP {prefix}VIEW {view_name}")) + + @classmethod + def define_reflected_tables(cls, metadata, schema): + if schema: + schema_prefix = schema + "." + else: + schema_prefix = "" + + if testing.requires.self_referential_foreign_keys.enabled: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + Column( + "parent_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey( + "%susers.user_id" % schema_prefix, name="user_id_fk" + ), + ), + schema=schema, + test_needs_fk=True, + ) + else: + users = Table( + "users", + metadata, + Column("user_id", sqlalchemy.INT, primary_key=True), + Column("test1", sqlalchemy.CHAR(5), nullable=False), + Column("test2", sqlalchemy.Float(5), nullable=False), + schema=schema, + test_needs_fk=True, + ) + + Table( + "dingalings", + metadata, + Column("dingaling_id", sqlalchemy.Integer, primary_key=True), + Column( + "address_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey("%semail_addresses.address_id" % schema_prefix), + ), + Column( + "id_user", + sqlalchemy.Integer, + sqlalchemy.ForeignKey("%susers.user_id" % schema_prefix), + ), + Column("data", sqlalchemy.String(30)), + schema=schema, + test_needs_fk=True, + ) + Table( + "email_addresses", + metadata, + Column("address_id", sqlalchemy.Integer, primary_key=True), + Column( + "remote_user_id", + sqlalchemy.Integer, + sqlalchemy.ForeignKey(users.c.user_id), + ), + Column("email_address", sqlalchemy.String(20)), + sqlalchemy.PrimaryKeyConstraint("address_id", name="email_ad_pk"), + schema=schema, + test_needs_fk=True, + ) + Table( + "comment_test", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True, comment="id comment"), + Column("data", sqlalchemy.String(20), comment="data % comment"), + Column( + "d2", + sqlalchemy.String(20), + comment=r"""Comment types type speedily ' " \ '' Fun!""", + ), + schema=schema, + comment=r"""the test % ' " \ table comment""", + ) + Table( + "no_constraints", + metadata, + Column("data", sqlalchemy.String(20)), + schema=schema, + ) + + if testing.requires.cross_schema_fk_reflection.enabled: + if schema is None: + Table( + "local_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + Column( + "remote_id", + ForeignKey("%s.remote_table_2.id" % testing.config.test_schema), + ), + test_needs_fk=True, + schema=config.db.dialect.default_schema_name, + ) + else: + Table( + "remote_table", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column( + "local_id", + ForeignKey( + "%s.local_table.id" % config.db.dialect.default_schema_name + ), + ), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + Table( + "remote_table_2", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("data", sqlalchemy.String(20)), + schema=schema, + test_needs_fk=True, + ) + + if testing.requires.index_reflection.enabled: + sqlalchemy.Index("users_t_idx", users.c.test1, users.c.test2, unique=True) + sqlalchemy.Index( + "users_all_idx", users.c.user_id, users.c.test2, users.c.test1 + ) + + if not schema: + # test_needs_fk is at the moment to force MySQL InnoDB + noncol_idx_test_nopk = Table( + "noncol_idx_test_nopk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + extend_existing=True, + ) + + noncol_idx_test_pk = Table( + "noncol_idx_test_pk", + metadata, + Column("id", sqlalchemy.Integer, primary_key=True), + Column("q", sqlalchemy.String(5)), + test_needs_fk=True, + extend_existing=True, + ) + + if testing.requires.indexes_with_ascdesc.enabled: + sqlalchemy.Index("noncol_idx_nopk", noncol_idx_test_nopk.c.q.desc()) + sqlalchemy.Index("noncol_idx_pk", noncol_idx_test_pk.c.q.desc()) + + if testing.requires.view_column_reflection.enabled and not bool( + os.environ.get("SPANNER_EMULATOR_HOST") + ): + cls.define_views(metadata, schema) + + @testing.combinations( + (False, False), + (False, True, testing.requires.schemas), + (True, False, testing.requires.view_reflection), + ( + True, + True, + testing.requires.schemas + testing.requires.view_reflection, + ), + argnames="use_views,use_schema", + ) + def test_get_columns(self, connection, use_views, use_schema): + if use_views and bool(os.environ.get("SPANNER_EMULATOR_HOST")): + pytest.skip("Skipped on emulator") + + schema = None + + users, addresses = (self.tables.users, self.tables.email_addresses) + if use_views: + table_names = ["users_v", "email_addresses_v", "dingalings_v"] + else: + table_names = ["users", "email_addresses"] + + insp = inspect(connection) + for table_name, table in zip(table_names, (users, addresses)): + schema_name = schema + cols = insp.get_columns(table_name, schema=schema_name) + is_true(len(cols) > 0, len(cols)) + + # should be in order + + for i, col in enumerate(table.columns): + eq_(col.name, cols[i]["name"]) + ctype = cols[i]["type"].__class__ + ctype_def = col.type + if isinstance(ctype_def, sqlalchemy.types.TypeEngine): + ctype_def = ctype_def.__class__ + + # Oracle returns Date for DateTime. + + if testing.against("oracle") and ctype_def in ( + types.Date, + types.DateTime, + ): + ctype_def = types.Date + + # assert that the desired type and return type share + # a base within one of the generic types. + + is_true( + len( + set(ctype.__mro__) + .intersection(ctype_def.__mro__) + .intersection( + [ + types.Integer, + types.Numeric, + types.DateTime, + types.Date, + types.Time, + types.String, + types._Binary, + ] + ) + ) + > 0, + "%s(%s), %s(%s)" % (col.name, col.type, cols[i]["name"], ctype), + ) + + if not col.primary_key: + assert cols[i]["default"] is None + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + @testing.requires.view_reflection + def test_get_view_definition( + self, + connection, + ): + schema = None + insp = inspect(connection) + for view in ["users_v", "email_addresses_v", "dingalings_v"]: + v = insp.get_view_definition(view, schema=schema) + is_true(bool(v)) + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + @testing.requires.view_reflection + def test_get_view_definition_does_not_exist(self, connection): + super().test_get_view_definition_does_not_exist(connection) + + def filter_name_values(): + return testing.combinations(True, False, argnames="use_filter") + + @filter_name_values() + @testing.requires.index_reflection + def test_get_multi_indexes( + self, + get_multi_exp, + use_filter, + schema=None, + scope=ObjectScope.DEFAULT, + kind=ObjectKind.TABLE, + ): + """ + SPANNER OVERRIDE: + + Spanner doesn't support indexes on views and + doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + insp, kws, exp = get_multi_exp( + schema, + scope, + kind, + use_filter, + Inspector.get_indexes, + self.exp_indexes, + ) + _ignore_tables = [ + (None, "comment_test"), + (None, "dingalings"), + (None, "email_addresses"), + (None, "no_constraints"), + ] + exp = {k: v for k, v in exp.items() if k not in _ignore_tables} + + for kw in kws: + insp.clear_cache() + result = insp.get_multi_indexes(**kw) + self._check_table_dict(result, exp, self._required_index_keys) + + def exp_pks( + self, + schema=None, + scope=ObjectScope.ANY, + kind=ObjectKind.ANY, + filter_names=None, + ): + def pk(*cols, name=mock.ANY, comment=None): + return { + "constrained_columns": list(cols), + "name": name, + "comment": comment, + } + + empty = pk(name=None) + if testing.requires.materialized_views_reflect_pk.enabled: + materialized = {(schema, "dingalings_v"): pk("dingaling_id")} + else: + materialized = {(schema, "dingalings_v"): empty} + views = { + (schema, "email_addresses_v"): empty, + (schema, "users_v"): empty, + (schema, "user_tmp_v"): empty, + } + self._resolve_views(views, materialized) + tables = { + (schema, "users"): pk("user_id"), + (schema, "dingalings"): pk("dingaling_id"), + (schema, "email_addresses"): pk( + "address_id", name="email_ad_pk", comment="ea pk comment" + ), + (schema, "comment_test"): pk("id"), + (schema, "no_constraints"): empty, + (schema, "local_table"): pk("id"), + (schema, "remote_table"): pk("id"), + (schema, "remote_table_2"): pk("id"), + (schema, "noncol_idx_test_nopk"): pk("id"), + (schema, "noncol_idx_test_pk"): pk("id"), + (schema, self.temp_table_name()): pk("id"), + } + if not testing.requires.reflects_pk_names.enabled: + for val in tables.values(): + if val["name"] is not None: + val["name"] = mock.ANY + res = self._resolve_kind(kind, tables, views, materialized) + res = self._resolve_names(schema, scope, filter_names, res) + return res + + @filter_name_values() + @testing.requires.primary_key_constraint_reflection + def test_get_multi_pk_constraint( + self, + get_multi_exp, + use_filter, + schema=None, + scope=ObjectScope.DEFAULT, + kind=ObjectKind.TABLE, + ): + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + insp, kws, exp = get_multi_exp( + schema, + scope, + kind, + use_filter, + Inspector.get_pk_constraint, + self.exp_pks, + ) + _ignore_tables = [(None, "no_constraints")] + exp = {k: v for k, v in exp.items() if k not in _ignore_tables} + + for kw in kws: + insp.clear_cache() + result = insp.get_multi_pk_constraint(**kw) + self._check_table_dict(result, exp, self._required_pk_keys, make_lists=True) + + def exp_fks( + self, + schema=None, + scope=ObjectScope.ANY, + kind=ObjectKind.ANY, + filter_names=None, + ): + class tt: + def __eq__(self, other): + return other is None or config.db.dialect.default_schema_name == other + + def fk( + cols, + ref_col, + ref_table, + ref_schema=schema, + name=mock.ANY, + comment=None, + ): + return { + "constrained_columns": cols, + "referred_columns": ref_col, + "name": name, + "options": mock.ANY, + "referred_schema": ref_schema if ref_schema is not None else tt(), + "referred_table": ref_table, + "comment": comment, + } + + materialized = {} + views = {} + self._resolve_views(views, materialized) + tables = { + (schema, "users"): [ + fk(["parent_user_id"], ["user_id"], "users", name="user_id_fk") + ], + (schema, "dingalings"): [ + fk(["address_id"], ["address_id"], "email_addresses"), + fk(["id_user"], ["user_id"], "users"), + ], + (schema, "email_addresses"): [fk(["remote_user_id"], ["user_id"], "users")], + (schema, "local_table"): [ + fk( + ["remote_id"], + ["id"], + "remote_table_2", + ref_schema=config.test_schema, + ) + ], + (schema, "remote_table"): [ + fk(["local_id"], ["id"], "local_table", ref_schema=None) + ], + } + if not testing.requires.self_referential_foreign_keys.enabled: + tables[(schema, "users")].clear() + if not testing.requires.named_constraints.enabled: + for vals in tables.values(): + for val in vals: + if val["name"] is not mock.ANY: + val["name"] = mock.ANY + + res = self._resolve_kind(kind, tables, views, materialized) + res = self._resolve_names(schema, scope, filter_names, res) + return res + + @filter_name_values() + @testing.requires.foreign_key_constraint_reflection + def test_get_multi_foreign_keys( + self, + get_multi_exp, + use_filter, + schema=None, + scope=ObjectScope.DEFAULT, + kind=ObjectKind.TABLE, + ): + + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + insp, kws, exp = get_multi_exp( + schema, + scope, + kind, + use_filter, + Inspector.get_foreign_keys, + self.exp_fks, + ) + for kw in kws: + insp.clear_cache() + result = insp.get_multi_foreign_keys(**kw) + self._adjust_sort(result, exp, lambda d: tuple(d["constrained_columns"])) + self._check_table_dict( + { + key: sorted(value, key=lambda x: x["constrained_columns"]) + for key, value in result.items() + }, + { + key: sorted(value, key=lambda x: x["constrained_columns"]) + for key, value in exp.items() + }, + self._required_fk_keys, + ) + + def exp_columns( + self, + schema=None, + scope=ObjectScope.ANY, + kind=ObjectKind.ANY, + filter_names=None, + ): + def col(name, auto=False, default=mock.ANY, comment=None, nullable=True): + res = { + "name": name, + "autoincrement": auto, + "type": mock.ANY, + "default": default, + "comment": comment, + "nullable": nullable, + } + if auto == "omit": + res.pop("autoincrement") + return res + + def pk(name, **kw): + kw = {"auto": True, "default": mock.ANY, "nullable": False, **kw} + return col(name, **kw) + + materialized = { + (schema, "dingalings_v"): [ + col("dingaling_id", auto="omit", nullable=mock.ANY), + col("address_id"), + col("id_user"), + col("data"), + ] + } + views = { + (schema, "email_addresses_v"): [ + col("address_id", auto="omit", nullable=mock.ANY), + col("remote_user_id"), + col("email_address"), + ], + (schema, "users_v"): [ + col("user_id", auto="omit", nullable=mock.ANY), + col("test1", nullable=mock.ANY), + col("test2", nullable=mock.ANY), + col("parent_user_id"), + ], + (schema, "user_tmp_v"): [ + col("id", auto="omit", nullable=mock.ANY), + col("name"), + col("foo"), + ], + } + self._resolve_views(views, materialized) + tables = { + (schema, "users"): [ + pk("user_id"), + col("test1", nullable=False), + col("test2", nullable=False), + col("parent_user_id"), + ], + (schema, "dingalings"): [ + pk("dingaling_id"), + col("address_id"), + col("id_user"), + col("data"), + ], + (schema, "email_addresses"): [ + pk("address_id"), + col("remote_user_id"), + col("email_address"), + ], + (schema, "comment_test"): [ + pk("id", comment="id comment"), + col("data", comment="data % comment"), + col( + "d2", + comment=r"""Comment types type speedily ' " \ '' Fun!""", + ), + ], + (schema, "no_constraints"): [col("data")], + (schema, "local_table"): [pk("id"), col("data"), col("remote_id")], + (schema, "remote_table"): [pk("id"), col("local_id"), col("data")], + (schema, "remote_table_2"): [pk("id"), col("data")], + (schema, "noncol_idx_test_nopk"): [pk("id"), col("q")], + (schema, "noncol_idx_test_pk"): [pk("id"), col("q")], + (schema, self.temp_table_name()): [ + pk("id"), + col("name"), + col("foo"), + ], + } + res = self._resolve_kind(kind, tables, views, materialized) + res = self._resolve_names(schema, scope, filter_names, res) + return res + + @filter_name_values() + def test_get_multi_columns( + self, + get_multi_exp, + use_filter, + schema=None, + scope=ObjectScope.DEFAULT, + kind=ObjectKind.TABLE, + ): + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + insp, kws, exp = get_multi_exp( + schema, + scope, + kind, + use_filter, + Inspector.get_columns, + self.exp_columns, + ) + + for kw in kws: + insp.clear_cache() + result = insp.get_multi_columns(**kw) + self._check_table_dict(result, exp, self._required_column_keys) + + @pytest.mark.skip( + "Requires an introspection method to be implemented in SQLAlchemy first" + ) + def test_get_multi_unique_constraints(): + pass + + @pytest.mark.skip( + "Requires an introspection method to be implemented in SQLAlchemy first" + ) + def test_get_multi_check_constraints(): + pass + + @testing.combinations((False,), argnames="use_schema") + @testing.requires.foreign_key_constraint_reflection + def test_get_foreign_keys(self, connection, use_schema): + if use_schema: + schema = config.test_schema + else: + schema = None + + users, addresses = (self.tables.users, self.tables.email_addresses) + insp = inspect(connection) + expected_schema = schema + # users + + if testing.requires.self_referential_foreign_keys.enabled: + users_fkeys = insp.get_foreign_keys(users.name, schema=schema) + fkey1 = users_fkeys[0] + + with testing.requires.named_constraints.fail_if(): + eq_(fkey1["name"], "user_id_fk") + + eq_(fkey1["referred_schema"], expected_schema) + eq_(fkey1["referred_table"], users.name) + eq_(fkey1["referred_columns"], ["user_id"]) + if testing.requires.self_referential_foreign_keys.enabled: + eq_(fkey1["constrained_columns"], ["parent_user_id"]) + + # addresses + addr_fkeys = insp.get_foreign_keys(addresses.name, schema=schema) + fkey1 = addr_fkeys[0] + + with testing.requires.implicitly_named_constraints.fail_if(): + self.assert_(fkey1["name"] is not None) + + eq_(fkey1["referred_schema"], expected_schema) + eq_(fkey1["referred_table"], users.name) + eq_(fkey1["referred_columns"], ["user_id"]) + eq_(fkey1["constrained_columns"], ["remote_user_id"]) + + @testing.combinations( + None, + ("foreign_key", testing.requires.foreign_key_constraint_reflection), + argnames="order_by", + ) + @testing.combinations( + (True, testing.requires.schemas), False, argnames="use_schema" + ) + def test_get_table_names(self, connection, order_by, use_schema): + + schema = None + + _ignore_tables = [ + "account", + "alembic_version", + "bytes_table", + "comment_test", + "date_table", + "noncol_idx_test_pk", + "noncol_idx_test_nopk", + "local_table", + "remote_table", + "remote_table_2", + "text_table", + "user_tmp", + "no_constraints", + ] + + insp = inspect(connection) + + if order_by: + tables = [ + rec[0] for rec in insp.get_sorted_table_and_fkc_names(schema) if rec[0] + ] + else: + tables = insp.get_table_names(schema) + table_names = [t for t in tables if t not in _ignore_tables] + + if order_by == "foreign_key": + answer = ["users", "email_addresses", "dingalings"] + eq_(table_names, answer) + else: + answer = ["dingalings", "email_addresses", "users"] + eq_(sorted(table_names), answer) + + @classmethod + def define_temp_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + In Cloud Spanner unique indexes are used instead of directly + creating unique constraints. Overriding the test to replace + constraints with indexes in testing data. + """ + kw = temp_table_keyword_args(config, config.db) + user_tmp = Table( + "user_tmp", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + Column("foo", sqlalchemy.INT), + sqlalchemy.Index("user_tmp_uq", "name", unique=True), + sqlalchemy.Index("user_tmp_ix", "foo"), + extend_existing=True, + **kw, + ) + if ( + testing.requires.view_reflection.enabled + and testing.requires.temporary_views.enabled + ): + event.listen( + user_tmp, + "after_create", + DDL("create temporary view user_tmp_v as " "select * from user_tmp"), + ) + event.listen(user_tmp, "before_drop", DDL("drop view user_tmp_v")) + + @testing.provide_metadata + def test_reflect_string_column_max_len(self, connection): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the STRING type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + metadata = MetaData() + Table("text_table", metadata, Column("TestColumn", Text, nullable=False)) + metadata.create_all(connection) + + Table("text_table", metadata, autoload=True) + + def test_reflect_bytes_column_max_len(self, connection): + """ + SPANNER SPECIFIC TEST: + + In Spanner column of the BYTES type can be + created with size defined as MAX. The test + checks that such a column is correctly reflected. + """ + metadata = MetaData() + Table( + "bytes_table", + metadata, + Column("TestColumn", LargeBinary, nullable=False), + ) + metadata.create_all(connection) + + Table("bytes_table", metadata, autoload=True) + + @testing.requires.unique_constraint_reflection + def test_get_unique_constraints(self, metadata, connection, use_schema=False): + # SQLite dialect needs to parse the names of the constraints + # separately from what it gets from PRAGMA index_list(), and + # then matches them up. so same set of column_names in two + # constraints will confuse it. Perhaps we should no longer + # bother with index_list() here since we have the whole + # CREATE TABLE? + + if use_schema: + schema = config.test_schema + else: + schema = None + uniques = sorted( + [ + {"name": "unique_a", "column_names": ["a"]}, + {"name": "unique_a_b_c", "column_names": ["a", "b", "c"]}, + {"name": "unique_c_a_b", "column_names": ["c", "a", "b"]}, + {"name": "unique_asc_key", "column_names": ["asc", "key"]}, + {"name": "i.have.dots", "column_names": ["b"]}, + {"name": "i have spaces", "column_names": ["c"]}, + ], + key=operator.itemgetter("name"), + ) + table = Table( + "testtbl", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("a", String(20)), + Column("b", String(30)), + Column("c", Integer), + # reserved identifiers + Column("asc", String(30)), + Column("key", String(30)), + sqlalchemy.Index("unique_a", "a", unique=True), + sqlalchemy.Index("unique_a_b_c", "a", "b", "c", unique=True), + sqlalchemy.Index("unique_c_a_b", "c", "a", "b", unique=True), + sqlalchemy.Index("unique_asc_key", "asc", "key", unique=True), + schema=schema, + ) + table.create(connection) + connection.connection.commit() + + inspector = inspect(connection) + reflected = sorted( + inspector.get_unique_constraints("testtbl", schema=schema), + key=operator.itemgetter("name"), + ) + + names_that_duplicate_index = set() + + for orig, refl in zip(uniques, reflected): + # Different dialects handle duplicate index and constraints + # differently, so ignore this flag + dupe = refl.pop("duplicates_index", None) + if dupe: + names_that_duplicate_index.add(dupe) + eq_(orig, refl) + + reflected_metadata = MetaData() + reflected = Table( + "testtbl", + reflected_metadata, + autoload_with=connection, + schema=schema, + ) + + # test "deduplicates for index" logic. MySQL and Oracle + # "unique constraints" are actually unique indexes (with possible + # exception of a unique that is a dupe of another one in the case + # of Oracle). make sure # they aren't duplicated. + idx_names = set([idx.name for idx in reflected.indexes]) + uq_names = set( + [ + uq.name + for uq in reflected.constraints + if isinstance(uq, sqlalchemy.UniqueConstraint) + ] + ).difference(["unique_c_a_b"]) + + assert not idx_names.intersection(uq_names) + if names_that_duplicate_index: + eq_(names_that_duplicate_index, idx_names) + eq_(uq_names, set()) + + @testing.provide_metadata + def test_unique_constraint_raises(self, connection): + """ + Checking that unique constraint creation + fails due to a ProgrammingError. + """ + metadata = MetaData() + Table( + "user_tmp_failure", + metadata, + Column("id", sqlalchemy.INT, primary_key=True), + Column("name", sqlalchemy.VARCHAR(50)), + sqlalchemy.UniqueConstraint("name", name="user_tmp_uq"), + ) + + with pytest.raises(spanner_dbapi.exceptions.ProgrammingError): + metadata.create_all(connection) + + @testing.provide_metadata + def _test_get_table_names(self, schema=None, table_type="table", order_by=None): + """ + SPANNER OVERRIDE: + + Spanner doesn't support temporary tables, so real tables are + used for testing. As the original test expects only real + tables to be read, and in Spanner all the tables are real, + expected results override is required. + """ + _ignore_tables = [ + "comment_test", + "noncol_idx_test_pk", + "noncol_idx_test_nopk", + "local_table", + "remote_table", + "remote_table_2", + "no_constraints", + ] + meta = self.metadata + + insp = inspect(meta.bind) + + if table_type == "view" and not bool(os.environ.get("SPANNER_EMULATOR_HOST")): + table_names = insp.get_view_names(schema) + table_names.sort() + answer = ["email_addresses_v", "users_v"] + eq_(sorted(table_names), answer) + else: + if order_by: + tables = [ + rec[0] + for rec in insp.get_sorted_table_and_fkc_names(schema) + if rec[0] + ] + else: + tables = insp.get_table_names(schema) + table_names = [t for t in tables if t not in _ignore_tables] + + if order_by == "foreign_key": + answer = {"dingalings", "email_addresses", "user_tmp", "users"} + eq_(set(table_names), answer) + else: + answer = ["dingalings", "email_addresses", "user_tmp", "users"] + eq_(sorted(table_names), answer) + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_get_view_names(self, connection, use_schema=False): + insp = inspect(connection) + schema = None + table_names = insp.get_view_names(schema) + if testing.requires.materialized_views.enabled: + eq_(sorted(table_names), ["email_addresses_v", "users_v"]) + eq_(insp.get_materialized_view_names(schema), ["dingalings_v"]) + else: + answer = ["dingalings_v", "email_addresses_v", "users_v"] + eq_(sorted(table_names), answer) + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_indexes(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_unique_constraints(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_get_temp_table_columns(self): + pass + + @pytest.mark.skip("Spanner doesn't support temporary tables") + def test_reflect_table_temp_table(self, connection): + pass + + def exp_indexes( + self, + schema=None, + scope=ObjectScope.ANY, + kind=ObjectKind.ANY, + filter_names=None, + ): + def idx( + *cols, + name, + unique=False, + column_sorting=None, + duplicates=False, + fk=False, + ): + fk_req = testing.requires.foreign_keys_reflect_as_index + dup_req = testing.requires.unique_constraints_reflect_as_index + if (fk and not fk_req.enabled) or (duplicates and not dup_req.enabled): + return () + res = { + "unique": unique, + "column_names": list(cols), + "name": name, + "dialect_options": mock.ANY, + "include_columns": [], + } + if column_sorting: + res["column_sorting"] = {"q": "DESC"} + if duplicates: + res["duplicates_constraint"] = name + return [res] + + materialized = {(schema, "dingalings_v"): []} + views = { + (schema, "email_addresses_v"): [], + (schema, "users_v"): [], + (schema, "user_tmp_v"): [], + } + self._resolve_views(views, materialized) + if materialized: + materialized[(schema, "dingalings_v")].extend(idx("data", name="mat_index")) + tables = { + (schema, "users"): [ + *idx("parent_user_id", name="user_id_fk", fk=True), + *idx("user_id", "test2", "test1", name="users_all_idx"), + *idx("test1", "test2", name="users_t_idx", unique=True), + ], + (schema, "dingalings"): [ + *idx("data", name=mock.ANY, unique=True, duplicates=True), + *idx("id_user", name=mock.ANY, fk=True), + *idx( + "address_id", + "dingaling_id", + name="zz_dingalings_multiple", + unique=True, + duplicates=True, + ), + ], + (schema, "email_addresses"): [ + *idx("email_address", name=mock.ANY), + *idx("remote_user_id", name=mock.ANY, fk=True), + ], + (schema, "comment_test"): [], + (schema, "no_constraints"): [], + (schema, "local_table"): [*idx("remote_id", name=mock.ANY, fk=True)], + (schema, "remote_table"): [*idx("local_id", name=mock.ANY, fk=True)], + (schema, "remote_table_2"): [], + (schema, "noncol_idx_test_nopk"): [ + *idx( + "q", + name="noncol_idx_nopk", + column_sorting={"q": "DESC"}, + ) + ], + (schema, "noncol_idx_test_pk"): [ + *idx("q", name="noncol_idx_pk", column_sorting={"q": "DESC"}) + ], + (schema, self.temp_table_name()): [ + *idx("foo", name="user_tmp_ix"), + *idx( + "name", + name=f"user_tmp_uq_{config.ident}", + duplicates=True, + unique=True, + ), + ], + } + if ( + not testing.requires.indexes_with_ascdesc.enabled + or not testing.requires.reflect_indexes_with_ascdesc.enabled + ): + tables[(schema, "noncol_idx_test_nopk")].clear() + tables[(schema, "noncol_idx_test_pk")].clear() + res = self._resolve_kind(kind, tables, views, materialized) + res = self._resolve_names(schema, scope, filter_names, res) + return res + + def _check_list(self, result, exp, req_keys=None, msg=None): + if req_keys is None: + eq_(result, exp, msg) + else: + eq_(len(result), len(exp), msg) + for r, e in zip(result, exp): + for k in set(r) | set(e): + if (k in req_keys and (k in r and k in e)) or (k in r and k in e): + if isinstance(r[k], list): + r[k].sort() + e[k].sort() + eq_(r[k], e[k], f"{msg} - {k} - {r}") + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + @testing.combinations(True, False, argnames="use_schema") + @testing.combinations((True, testing.requires.views), False, argnames="views") + def test_metadata(self, connection, use_schema, views): + m = MetaData() + schema = None + m.reflect(connection, schema=schema, views=views, resolve_fks=False) + + insp = inspect(connection) + tables = insp.get_table_names(schema) + if views: + tables += insp.get_view_names(schema) + try: + tables += insp.get_materialized_view_names(schema) + except NotImplementedError: + pass + if schema is not None: + tables = [f"{schema}.{t}" for t in tables] + eq_(sorted(m.tables), sorted(tables)) + + +class CompositeKeyReflectionTest(_CompositeKeyReflectionTest): + @testing.requires.foreign_key_constraint_reflection + def test_fk_column_order(self, connection): + """ + SPANNER OVERRIDE: + + Spanner column usage reflection doesn't support determenistic + ordering. Overriding the test to check that columns are + reflected correctly, without considering their order. + """ + # test for issue #5661 + insp = inspect(connection) + foreign_keys = insp.get_foreign_keys(self.tables.tb2.name) + eq_(len(foreign_keys), 1) + fkey1 = foreign_keys[0] + eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) + eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) + + @testing.requires.primary_key_constraint_reflection + def test_pk_column_order(self, connection): + """ + SPANNER OVERRIDE: + Emultor doesn't support returning pk sorted by ordinal value + of columns. + """ + insp = inspect(connection) + primary_key = insp.get_pk_constraint(self.tables.tb1.name) + exp = ( + ["id", "name", "attr"] + if bool(os.environ.get("SPANNER_EMULATOR_HOST")) + else ["name", "id", "attr"] + ) + eq_(primary_key.get("constrained_columns"), exp) + + +@pytest.mark.skip("Spanner doesn't support quotes in table names.") +class QuotedNameArgumentTest(_QuotedNameArgumentTest): + pass + + +class _DateFixture(__DateFixture): + compare = None + + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + + class Decorated(sqlalchemy.TypeDecorator): + impl = cls.datatype + cache_ok = True + + Table( + "date_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("date_data", cls.datatype), + Column("decorated_date_data", Decorated), + ) + + +class DateTest(_DateTest): + """ + SPANNER OVERRIDE: + + DateTest tests used same class method to create table, so to avoid those failures + and maintain DRY concept just inherit the class to run tests successfully. + """ + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + +class CTETest(_CTETest): + @classmethod + def define_tables(cls, metadata): + """ + The original method creates a foreign key without a name, + which causes troubles on test cleanup. Overriding the + method to explicitly set a foreign key name. + """ + Table( + "some_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", ForeignKey("some_table.id", name="fk_some_table")), + ) + + Table( + "some_other_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("parent_id", Integer), + ) + + @pytest.mark.skip("INSERT from WITH subquery is not supported") + def test_insert_from_select_round_trip(self): + """ + The test checks if an INSERT can be done from a cte, like: + + WITH some_cte AS (...) + INSERT INTO some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_scalar_subq_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("DELETE from WITH subquery is not supported") + def test_delete_from_round_trip(self): + """ + The test checks if a DELETE can be done from a cte, like: + + WITH some_cte AS (...) + DELETE FROM some_other_table (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("UPDATE from WITH subquery is not supported") + def test_update_from_round_trip(self): + """ + The test checks if an UPDATE can be done from a cte, like: + + WITH some_cte AS (...) + UPDATE some_other_table + SET (... SELECT * FROM some_cte) + + Such queries are not supported by Spanner. + """ + pass + + @pytest.mark.skip("WITH RECURSIVE subqueries are not supported") + def test_select_recursive_round_trip(self): + pass + + +class DateTimeMicrosecondsTest(_DateTimeMicrosecondsTest, DateTest): + @pytest.mark.skip("Spanner dates are time zone independent") + def test_select_direct(self): + pass + + def test_round_trip(self): + """ + SPANNER OVERRIDE: + + Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid + assert failures convert datetime input to the desire timestamp format. + """ + date_table = self.tables.date_table + + with config.db.connect() as connection: + connection.execute(date_table.insert(), {"date_data": self.data, "id": 250}) + row = connection.execute(select(date_table.c.date_data)).first() + + compare = self.compare or self.data + compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + eq_(row[0].rfc3339(), compare) + assert isinstance(row[0], DatetimeWithNanoseconds) + + def test_round_trip_decorated(self, connection): + """ + SPANNER OVERRIDE: + + Spanner converts timestamp into `%Y-%m-%dT%H:%M:%S.%fZ` format, so to avoid + assert failures convert datetime input to the desire timestamp format. + """ + date_table = self.tables.date_table + + connection.execute( + date_table.insert(), {"id": 1, "decorated_date_data": self.data} + ) + + row = connection.execute(select(date_table.c.decorated_date_data)).first() + + compare = self.compare or self.data + compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + eq_(row[0].rfc3339(), compare) + assert isinstance(row[0], DatetimeWithNanoseconds) + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + +class DateTimeTest(_DateTimeTest, DateTimeMicrosecondsTest): + """ + SPANNER OVERRIDE: + + DateTimeTest tests have the same failures same as DateTimeMicrosecondsTest tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null_bound_comparison(self): + super().test_null_bound_comparison() + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_null(self, connection): + super().test_null(connection) + + @pytest.mark.skip("Spanner dates are time zone independent") + def test_select_direct(self): + pass + + +@pytest.mark.skip("Not supported by Spanner") +class DifficultParametersTest(_DifficultParametersTest): + pass + + +class FetchLimitOffsetTest(_FetchLimitOffsetTest): + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_expr_limit_simple_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_simple_limit_expr_offset(self, connection): + pass + + @pytest.mark.skip("Spanner doesn't support composite LIMIT and OFFSET clauses") + def test_bound_offset(self, connection): + pass + + @pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" + ) + def test_limit_render_multiple_times(self, connection): + table = self.tables.some_table + stmt = select(table.c.id).limit(1).scalar_subquery() + + u = union(select(stmt), select(stmt)).subquery().select() + + self._assert_result( + connection, + u, + [(1,)], + ) + + @testing.requires.offset + def test_simple_offset(self, connection): + table = self.tables.some_table + self._assert_result( + connection, + select(table).order_by(table.c.id).offset(2), + [(3, 3, 4), (4, 4, 5), (5, 4, 6)], + ) + + +@pytest.mark.skip("Spanner doesn't support autoincrement") +class IdentityAutoincrementTest(_IdentityAutoincrementTest): + pass + + +@pytest.mark.skip("Spanner doesn't support returning") +class ReturningGuardsTest(_ReturningGuardsTest): + pass + + +@pytest.mark.skip("Spanner doesn't support user made schemas") +class SameNamedSchemaTableTest(_SameNamedSchemaTableTest): + pass + + +class EscapingTest(_EscapingTest): + @provide_metadata + def test_percent_sign_round_trip(self): + """Test that the DBAPI accommodates for escaped / nonescaped + percent signs in a way that matches the compiler + + SPANNER OVERRIDE + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + m = self.metadata + t = Table("t", m, Column("data", String(50))) + t.create(config.db) + with config.db.begin() as conn: + conn.execute(t.insert(), dict(data="some % value")) + + eq_( + conn.scalar( + select(t.c.data).where(t.c.data == literal_column("'some % value'")) + ), + "some % value", + ) + + conn.execute(t.delete()) + conn.execute(t.insert(), dict(data="some %% other value")) + eq_( + conn.scalar( + select(t.c.data).where( + t.c.data == literal_column("'some %% other value'") + ) + ), + "some %% other value", + ) + + +class ExistsTest(_ExistsTest): + def test_select_exists(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select(exists().where(stuff.c.data == "some data")) + ).fetchall(), + [(True,)], + ) + + def test_select_exists_false(self, connection): + """ + SPANNER OVERRIDE: + + The original test is trying to execute a query like: + + SELECT ... + WHERE EXISTS (SELECT ...) + + SELECT WHERE without FROM clause is not supported by Spanner. + Rewriting the test to force it to generate a query like: + + SELECT EXISTS (SELECT ...) + """ + stuff = self.tables.stuff + eq_( + connection.execute( + select(exists().where(stuff.c.data == "no data")) + ).fetchall(), + [(False,)], + ) + + +class TableDDLTest(_TableDDLTest): + @pytest.mark.skip( + "Spanner table name must start with an uppercase or lowercase letter" + ) + def test_underscore_names(self): + pass + + @pytest.mark.skip("Table names incuding schemas are not supported by Spanner") + def test_create_table_schema(self): + pass + + +class FutureTableDDLTest(_FutureTableDDLTest): + @pytest.mark.skip("Table names incuding schemas are not supported by Spanner") + def test_create_table_schema(self): + pass + + @pytest.mark.skip( + "Spanner table name must start with an uppercase or lowercase letter" + ) + def test_underscore_names(self): + pass + + +@pytest.mark.skip("Max identifier length in Spanner is 128") +class LongNameBlowoutTest(_LongNameBlowoutTest): + pass + + +@pytest.mark.skip("Spanner doesn't support Time data type.") +class TimeTests(_TimeMicrosecondsTest, _TimeTest): + pass + + +@pytest.mark.skip("Spanner doesn't coerce dates from datetime.") +class DateTimeCoercedToDateTimeTest(_DateTimeCoercedToDateTimeTest): + pass + + +class IntegerTest(_IntegerTest): + @provide_metadata + def _round_trip(self, datatype, data): + """ + SPANNER OVERRIDE: + + This is the helper method for integer class tests which creates a table and + performs an insert operation. + Cloud Spanner supports tables with an empty primary key, but only one + row can be inserted into such a table - following insertions will fail with + `400 id must not be NULL in table date_table`. + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + metadata = self.metadata + int_table = Table( + "integer_table", + metadata, + Column("id", Integer, primary_key=True, test_needs_autoincrement=True), + Column("integer_data", datatype), + ) + + metadata.create_all(config.db) + + config.db.execute(int_table.insert(), {"id": 1, "integer_data": data}) + + row = config.db.execute(select(int_table.c.integer_data)).first() + + eq_(row, (data,)) + + if util.py3k: + assert isinstance(row[0], int) + else: + assert isinstance(row[0], (long, int)) # noqa + + def _huge_ints(): + + return testing.combinations( + 2147483649, # 32 bits + 2147483648, # 32 bits + 2147483647, # 31 bits + 2147483646, # 31 bits + -2147483649, # 32 bits + -2147483648, # 32 interestingly, asyncpg accepts this one as int32 + -2147483647, # 31 + -2147483646, # 31 + 0, + 1376537018368127, + -1376537018368127, + argnames="intvalue", + ) + + @_huge_ints() + def test_huge_int_auto_accommodation(self, connection, intvalue): + """ + Spanner does not allow query to have FROM clause without a WHERE clause + """ + eq_( + connection.scalar(select(intvalue)), + intvalue, + ) + + +class _UnicodeFixture(__UnicodeFixture): + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + Table( + "unicode_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("unicode_data", cls.datatype), + ) + + def test_round_trip_executemany(self, connection): + """ + SPANNER OVERRIDE + + Cloud Spanner supports tables with empty primary key, but + only single one row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + unicode_table = self.tables.unicode_table + + connection.execute( + unicode_table.insert(), + [{"id": i, "unicode_data": self.data} for i in range(1, 4)], + ) + + rows = connection.execute(select(unicode_table.c.unicode_data)).fetchall() + eq_(rows, [(self.data,) for i in range(1, 4)]) + for row in rows: + assert isinstance(row[0], str) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal(self): + pass + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + +class UnicodeVarcharTest(_UnicodeFixture, _UnicodeVarcharTest): + """ + SPANNER OVERRIDE: + + UnicodeVarcharTest class inherits the __UnicodeFixture class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +class UnicodeTextTest(_UnicodeFixture, _UnicodeTextTest): + """ + SPANNER OVERRIDE: + + UnicodeTextTest class inherits the __UnicodeFixture class's tests, + so to avoid those failures and maintain DRY concept just inherit the class to run + tests successfully. + """ + + pass + + +class RowFetchTest(_RowFetchTest): + def test_row_w_scalar_select(self, connection): + """ + SPANNER OVERRIDE: + + Cloud Spanner returns a DatetimeWithNanoseconds() for date + data types. Overriding the test to use a DatetimeWithNanoseconds + type value as an expected result. + -------------- + + test that a scalar select as a column is returned as such + and that type conversion works OK. + + (this is half a SQLAlchemy Core test and half to catch database + backends that may have unusual behavior with scalar selects.) + """ + datetable = self.tables.has_dates + s = select(datetable.alias("x").c.today).scalar_subquery() + s2 = select(datetable.c.id, s.label("somelabel")) + row = connection.execute(s2).first() + + eq_( + row.somelabel, + DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=timezone.utc), + ) + + +class InsertBehaviorTest(_InsertBehaviorTest): + @pytest.mark.skip("Spanner doesn't support empty inserts") + def test_empty_insert(self): + pass + + @pytest.mark.skip("Spanner doesn't support empty inserts") + def test_empty_insert_multiple(self): + pass + + @pytest.mark.skip("Spanner doesn't support auto increment") + def test_insert_from_select_autoinc(self): + pass + + def test_autoclose_on_insert(self): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support tables with an auto increment primary key, + following insertions will fail with `400 id must not be NULL in table + autoinc_pk`. + + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + if ( + hasattr(config.requirements, "returning") + and config.requirements.returning.enabled + ): + engine = engines.testing_engine(options={"implicit_returning": False}) + else: + engine = config.db + + with engine.begin() as conn: + r = conn.execute( + self.tables.autoinc_pk.insert(), dict(id=1, data="some data") + ) + + assert r._soft_closed + assert not r.closed + assert r.is_insert + assert not r.returns_rows + + +class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): + __backend__ = True + + def test_nolength_binary(self): + metadata = MetaData() + foo = Table("foo", metadata, Column("one", LargeBinary)) + + foo.create(config.db) + foo.drop(config.db) + + +class StringTest(_StringTest): + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + def test_dont_truncate_rightside( + self, metadata, connection, expr=None, expected=None + ): + t = Table( + "t", + metadata, + Column("x", String(2)), + Column("id", Integer, primary_key=True), + ) + t.create(connection) + connection.connection.commit() + connection.execute( + t.insert(), + [{"x": "AB", "id": 1}, {"x": "BC", "id": 2}, {"x": "AC", "id": 3}], + ) + combinations = [("%B%", ["AB", "BC"]), ("A%C", ["AC"]), ("A%C%Z", [])] + + for args in combinations: + eq_( + connection.scalars(select(t.c.x).where(t.c.x.like(args[0]))).all(), + args[1], + ) + + +class TextTest(_TextTest): + @classmethod + def define_tables(cls, metadata): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support auto incrementing ids feature, + which is used by the original test. Overriding the test data + creation method to disable autoincrement and make id column + nullable. + """ + Table( + "text_table", + metadata, + Column("id", Integer, primary_key=True, nullable=True), + Column("text_data", Text), + ) + + @pytest.mark.skip("Spanner doesn't support non-ascii characters") + def test_literal_non_ascii(self): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_roundtrip(self, connection): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_empty_strings(self, connection): + pass + + @pytest.mark.skip("Not supported by Spanner") + def test_text_null_strings(self, connection): + pass + + +class NumericTest(_NumericTest): + @testing.fixture + def do_numeric_test(self, metadata, connection): + @testing.emits_warning(r".*does \*not\* support Decimal objects natively") + def run(type_, input_, output, filter_=None, check_scale=False): + t = Table( + "t", + metadata, + Column("x", type_), + Column("id", Integer, primary_key=True), + ) + t.create(connection) + connection.connection.commit() + connection.execute( + t.insert(), [{"x": x, "id": i} for i, x in enumerate(input_)] + ) + + result = {row[0] for row in connection.execute(t.select())} + output = set(output) + if filter_: + result = set(filter_(x) for x in result) + output = set(filter_(x) for x in output) + eq_(result, output) + if check_scale: + eq_([str(x) for x in result], [str(x) for x in output]) + + return run + + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + @emits_warning(r".*does \*not\* support Decimal objects natively") + def test_render_literal_numeric_asfloat(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563")], + [15.7563], + ) + + def test_render_literal_float(self, literal_round_trip): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + literal_round_trip( + Float(4), + [decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_generic_float_type + def test_float_custom_scale(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(None, decimal_return_scale=7, asdecimal=True), + [decimal.Decimal("15.7563827"), decimal.Decimal("15.7563827")], + [decimal.Decimal("15.7563827")], + check_scale=True, + ) + + def test_numeric_as_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + do_numeric_test( + Numeric(precision=8, scale=4), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], + ) + + def test_numeric_as_float(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Spanner throws an error 400 Value has type FLOAT64 which cannot be + inserted into column x, which has type NUMERIC for value 15.7563. + Overriding the test to remove the failure case. + """ + do_numeric_test( + Numeric(precision=8, scale=4, asdecimal=False), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [15.7563], + ) + + @requires.floats_to_four_decimals + def test_float_as_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(precision=8, asdecimal=True), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563"), None], + [decimal.Decimal("15.7563"), None], + filter_=lambda n: n is not None and round(n, 4) or None, + ) + + def test_float_as_float(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + do_numeric_test( + Float(precision=8), + [decimal.Decimal("15.7563"), decimal.Decimal("15.7563")], + [15.7563], + filter_=lambda n: n is not None and round(n, 5) or None, + ) + + @requires.precision_numerics_general + def test_precision_decimal(self, do_numeric_test): + """ + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + + Remove an extra digits after decimal point as cloud spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + numbers = set( + [ + decimal.Decimal("54.246451650"), + decimal.Decimal("0.004354"), + decimal.Decimal("900.0"), + ] + ) + do_numeric_test(Numeric(precision=18, scale=9), numbers, numbers) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal_large(self, do_numeric_test): + """test exceedingly large decimals. + + SPANNER OVERRIDE: + + Cloud Spanner supports tables with an empty primary key, but + only a single row can be inserted into such a table - + following insertions will fail with `Row [] already exists". + Overriding the test to avoid the same failure. + """ + numbers = set( + [ + decimal.Decimal("4E+8"), + decimal.Decimal("5748E+15"), + decimal.Decimal("1.521E+15"), + decimal.Decimal("000000000.1E+9"), + ] + ) + do_numeric_test(Numeric(precision=25, scale=2), numbers, numbers) + + @testing.requires.precision_numerics_enotation_large + def test_enotation_decimal(self, do_numeric_test): + """test exceedingly small decimals. + + Decimal reports values with E notation when the exponent + is greater than 6. + + SPANNER OVERRIDE: + + Remove extra digits after decimal point as Cloud Spanner is + capable of representing an exact numeric value with a precision + of 38 and scale of 9. + """ + numbers = set( + [ + decimal.Decimal("1E-2"), + decimal.Decimal("1E-3"), + decimal.Decimal("1E-4"), + decimal.Decimal("1E-5"), + decimal.Decimal("1E-6"), + decimal.Decimal("1E-7"), + decimal.Decimal("1E-8"), + decimal.Decimal("0.105940696"), + decimal.Decimal("0.005940696"), + decimal.Decimal("0.000000696"), + decimal.Decimal("0.700000696"), + decimal.Decimal("696E-9"), + ] + ) + do_numeric_test(Numeric(precision=38, scale=9), numbers, numbers) + + +class LikeFunctionsTest(_LikeFunctionsTest): + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_contains_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_endswith_autoescape_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_autoescape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_escape(self): + pass + + @pytest.mark.skip("Spanner doesn't support LIKE ESCAPE clause") + def test_startswith_autoescape_escape(self): + pass + + def test_escape_keyword_raises(self): + """Check that ESCAPE keyword causes an exception when used.""" + with pytest.raises(NotImplementedError): + col = self.tables.some_table.c.data + self._test(col.contains("b##cde", escape="#"), {7}) + + +@pytest.mark.skip("Spanner doesn't support IS DISTINCT FROM clause") +class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): + pass + + +class OrderByLabelTest(_OrderByLabelTest): + @pytest.mark.skip( + "Spanner requires an alias for the GROUP BY list when specifying derived " + "columns also used in SELECT" + ) + def test_group_by_composed(self): + pass + + +class CompoundSelectTest(_CompoundSelectTest): + """ + See: https://github.com/googleapis/python-spanner/issues/347 + """ + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_limit_offset_selectable_in_unions(self): + pass + + @pytest.mark.skip( + "Spanner DBAPI incorrectly classify the statement starting with brackets." + ) + def test_order_by_selectable_in_unions(self): + pass + + +class TestQueryHints(fixtures.TablesTest): + """ + Compile a complex query with JOIN and check that + the table hint was set into the right place. + """ + + __backend__ = True + + def test_complex_query_table_hints(self): + EXPECTED_QUERY = ( + "SELECT users.id, users.name \nFROM users @{FORCE_INDEX=table_1_by_int_idx}" + " JOIN addresses ON users.id = addresses.user_id " + "\nWHERE users.name IN (__[POSTCOMPILE_name_1])" + ) + + Base = declarative_base() + engine = create_engine( + "spanner:///projects/project-id/instances/instance-id/databases/database-id" + ) + + class User(Base): + __tablename__ = "users" + id = Column(Integer, primary_key=True) + name = Column(String(50)) + addresses = relationship("Address", backref="user") + + class Address(Base): + __tablename__ = "addresses" + id = Column(Integer, primary_key=True) + email = Column(String(50)) + user_id = Column(Integer, ForeignKey("users.id")) + + session = Session(engine) + + query = session.query(User) + query = query.with_hint( + selectable=User, text="@{FORCE_INDEX=table_1_by_int_idx}" + ) + + query = query.filter(User.name.in_(["val1", "val2"])) + query = query.join(Address) + + assert str(query.statement.compile(session.bind)) == EXPECTED_QUERY + + +class InterleavedTablesTest(fixtures.TestBase): + """ + Check that CREATE TABLE statements for interleaved tables are correctly + generated. + """ + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData() + + def test_interleave(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) + + def test_interleave_on_delete_cascade(self): + EXP_QUERY = ( + "\nCREATE TABLE client (\n\tteam_id INT64 NOT NULL, " + "\n\tclient_id INT64 NOT NULL, " + "\n\tclient_name STRING(16) NOT NULL" + "\n) PRIMARY KEY (team_id, client_id)," + "\nINTERLEAVE IN PARENT team ON DELETE CASCADE\n\n" + ) + client = Table( + "client", + self._metadata, + Column("team_id", Integer, primary_key=True), + Column("client_id", Integer, primary_key=True), + Column("client_name", String(16), nullable=False), + spanner_interleave_in="team", + spanner_interleave_on_delete_cascade=True, + ) + with mock.patch("google.cloud.spanner_dbapi.cursor.Cursor.execute") as execute: + client.create(self._engine) + execute.assert_called_once_with(EXP_QUERY, []) + + +class UserAgentTest(fixtures.TestBase): + """Check that SQLAlchemy dialect uses correct user agent.""" + + def setUp(self): + self._engine = create_engine( + "spanner:///projects/appdev-soda-spanner-staging/instances/" + "sqlalchemy-dialect-test/databases/compliance-test" + ) + self._metadata = MetaData() + + def test_user_agent(self): + dist = pkg_resources.get_distribution("sqlalchemy-spanner") + + with self._engine.connect() as connection: + assert ( + connection.connection.instance._client._client_info.user_agent + == "gl-" + dist.project_name + "/" + dist.version + ) + + +class SimpleUpdateDeleteTest(_SimpleUpdateDeleteTest): + """ + SPANNER OVERRIDE: + + Spanner doesn't support `rowcount` property. These + test cases overrides omit `rowcount` checks. + """ + + def test_delete(self, connection): + t = self.tables.plain_pk + r = connection.execute(t.delete().where(t.c.id == 2)) + assert not r.is_insert + assert not r.returns_rows + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (3, "d3")], + ) + + def test_update(self, connection): + t = self.tables.plain_pk + r = connection.execute(t.update().where(t.c.id == 2), dict(data="d2_new")) + assert not r.is_insert + assert not r.returns_rows + + eq_( + connection.execute(t.select().order_by(t.c.id)).fetchall(), + [(1, "d1"), (2, "d2_new"), (3, "d3")], + ) + + +class HasIndexTest(_HasIndexTest): + __backend__ = True + kind = testing.combinations("dialect", "inspector", argnames="kind") + + @classmethod + def define_tables(cls, metadata): + tt = Table( + "test_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + Column("data2", String(50)), + ) + sqlalchemy.Index("my_idx", tt.c.data) + + @kind + def test_has_index(self, kind, connection, metadata): + meth = self._has_index(kind, connection) + assert meth("test_table", "my_idx") + assert not meth("test_table", "my_idx_s") + assert not meth("nonexistent_table", "my_idx") + assert not meth("test_table", "nonexistent_idx") + + assert not meth("test_table", "my_idx_2") + assert not meth("test_table_2", "my_idx_3") + idx = Index("my_idx_2", self.tables.test_table.c.data2) + tbl = Table( + "test_table_2", + metadata, + Column("foo", Integer, primary_key=True), + Index("my_idx_3", "foo"), + ) + idx.create(connection) + tbl.create(connection) + + try: + if kind == "inspector": + assert not meth("test_table", "my_idx_2") + assert not meth("test_table_2", "my_idx_3") + meth.__self__.clear_cache() + connection.connection.commit() + assert meth("test_table", "my_idx_2") is True + assert meth("test_table_2", "my_idx_3") is True + finally: + tbl.drop(connection) + idx.drop(connection) + connection.connection.commit() + self.tables["test_table"].indexes.remove(idx) + + @pytest.mark.skip("Not supported by Cloud Spanner") + @kind + def test_has_index_schema(self, kind, connection): + pass + + +class HasTableTest(_HasTableTest): + @classmethod + def define_tables(cls, metadata): + Table( + "test_table", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(50)), + ) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_table_nonexistent_schema(self): + pass + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_table_schema(self): + pass + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_table_cache(self): + pass + + @testing.requires.views + def test_has_table_view(self, connection): + pass + + @testing.requires.views + def test_has_table_view_schema(self, connection): + pass + + +class PostCompileParamsTest(_PostCompileParamsTest): + def test_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + table.c.x == sqlalchemy.bindparam("q", literal_execute=True) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=10)) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " "\nWHERE some_table.x = 10", + [] if config.db.dialect.positional else {}, + ) + ) + + def test_execute_expanding_plus_literal_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + table.c.x.in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[5, 6, 7])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE some_table.x IN (5, 6, 7)", + [] if config.db.dialect.positional else {}, + ) + ) + + @testing.requires.tuple_in + def test_execute_tuple_expanding_plus_literal_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + sqlalchemy.tuple_(table.c.x, table.c.y).in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[(5, 10), (12, 18)])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE (some_table.x, some_table.y) " + "IN (%s(5, 10), (12, 18))" + % ("VALUES " if config.db.dialect.tuple_in_values else ""), + () if config.db.dialect.positional else {}, + ) + ) + + @testing.requires.tuple_in + def test_execute_tuple_expanding_plus_literal_heterogeneous_execute(self): + table = self.tables.some_table + + stmt = select(table.c.id).where( + sqlalchemy.tuple_(table.c.x, table.c.z).in_( + sqlalchemy.bindparam("q", expanding=True, literal_execute=True) + ) + ) + + with self.sql_execution_asserter() as asserter: + with config.db.connect() as conn: + conn.execute(stmt, dict(q=[(5, "z1"), (12, "z3")])) + + asserter.assert_( + sqlalchemy.testing.assertsql.CursorSQL( + "SELECT some_table.id \nFROM some_table " + "\nWHERE (some_table.x, some_table.z) " + "IN (%s(5, 'z1'), (12, 'z3'))" + % ("VALUES " if config.db.dialect.tuple_in_values else ""), + () if config.db.dialect.positional else {}, + ) + ) + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class JSONTest(_JSONTest): + @pytest.mark.skip("Values without keys are not supported.") + def test_single_element_round_trip(self, element): + pass + + def _test_round_trip(self, data_element, connection): + data_table = self.tables.data_table + + connection.execute( + data_table.insert(), + {"id": random.randint(1, 100000000), "name": "row1", "data": data_element}, + ) + + row = connection.execute(select(data_table.c.data)).first() + + eq_(row, (data_element,)) + + def test_unicode_round_trip(self): + # note we include Unicode supplementary characters as well + with config.db.connect() as conn: + conn.execute( + self.tables.data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "r1", + "data": { + "rΓ©ve🐍 illΓ©": "rΓ©ve🐍 illΓ©", + "data": {"k1": "drΓ΄l🐍e"}, + }, + }, + ) + + eq_( + conn.scalar(select(self.tables.data_table.c.data)), + { + "rΓ©ve🐍 illΓ©": "rΓ©ve🐍 illΓ©", + "data": {"k1": "drΓ΄l🐍e"}, + }, + ) + + @pytest.mark.skip("Parameterized types are not supported.") + def test_eval_none_flag_orm(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_index_typed_comparison(self): + pass + + @pytest.mark.skip( + "Spanner JSON_VALUE() always returns STRING," + "thus, this test case can't be executed." + ) + def test_path_typed_comparison(self): + pass + + @pytest.mark.skip("Custom JSON de-/serializers are not supported.") + def test_round_trip_custom_json(self): + pass + + def _index_fixtures(fn): + fn = testing.combinations( + ("boolean", True), + ("boolean", False), + ("boolean", None), + ("string", "some string"), + ("string", None), + ("integer", 15), + ("integer", 1), + ("integer", 0), + ("integer", None), + ("float", 28.5), + ("float", None), + id_="sa", + )(fn) + return fn + + @_index_fixtures + def test_index_typed_access(self, datatype, value): + data_table = self.tables.data_table + data_element = {"key1": value} + with config.db.connect() as conn: + conn.execute( + data_table.insert(), + { + "id": random.randint(1, 100000000), + "name": "row1", + "data": data_element, + "nulldata": data_element, + }, + ) + + expr = data_table.c.data["key1"] + expr = getattr(expr, "as_%s" % datatype)() + + roundtrip = conn.scalar(select(expr)) + if roundtrip in ("true", "false", None): + roundtrip = str(roundtrip).capitalize() + + eq_(str(roundtrip), str(value)) + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_json_null_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_json_null(self): + pass + + @pytest.mark.skip( + "Spanner doesn't support type casts inside JSON_VALUE() function." + ) + def test_round_trip_none_as_sql_null(self): + pass + + +class ExecutionOptionsRequestPriorotyTest(fixtures.TestBase): + def setUp(self): + self._engine = create_engine(get_db_url(), pool_size=1) + metadata = MetaData() + + self._table = Table( + "execution_options2", + metadata, + Column("opt_id", Integer, primary_key=True), + Column("opt_name", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + time.sleep(1) + + def test_request_priority(self): + PRIORITY = RequestOptions.Priority.PRIORITY_MEDIUM + with self._engine.connect().execution_options( + request_priority=PRIORITY + ) as connection: + connection.execute(select(self._table)).fetchall() + + with self._engine.connect() as connection: + assert connection.connection.request_priority is None + + engine = create_engine("sqlite:///database") + with engine.connect() as connection: + pass From 4dfc8a8390267c7c9cc4cd28af35d30eec6691a1 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 13:13:40 +0530 Subject: [PATCH 198/582] chore(main): release 1.5.0 (#315) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 11b0136cf2e0..d07cac51e81f 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.5.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.4.0...v1.5.0) (2023-04-19) + + +### Features + +* Feat: SQLAlchemy 2.0 support ([#314](https://github.com/googleapis/python-spanner-sqlalchemy/issues/314)) ([61d836b](https://github.com/googleapis/python-spanner-sqlalchemy/commit/61d836bade2a89d04b5c61e4ca9c56e7163f6cc6)) + ## [1.4.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.3.0...v1.4.0) (2023-04-06) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 108c5d32bed2..9d804245ac5f 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.4.0" +__version__ = "1.5.0" From 7e8e733df2f780e088bf052cd65c5ff898c55799 Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:10:01 +0530 Subject: [PATCH 199/582] feat: enable instance-level connection (#316) * chore: auto-release * feat:enable instance-level connection * lint --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 23 ++++++++-- .../sqlalchemy-spanner/test/test_suite_13.py | 14 ++++++ .../sqlalchemy-spanner/test/test_suite_14.py | 14 ++++++ .../sqlalchemy-spanner/test/test_suite_20.py | 45 ++++++++++++++++++- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e7a2ba17daa3..b6bf3278ad8d 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -645,11 +645,14 @@ def create_connect_args(self, url): The given URL follows the style: `spanner:///projects/{project-id}/instances/{instance-id}/databases/{database-id}` + or `spanner:///projects/{project-id}/instances/{instance-id}`. For the latter, + database operations will be not be possible and if required a new engine with + database-id set will need to be created. """ match = re.match( ( r"^projects/(?P.+?)/instances/" - "(?P.+?)/databases/(?P.+?)$" + "(?P.+?)(/databases/(?P.+)|$)" ), url.database, ) @@ -1346,17 +1349,29 @@ def do_rollback(self, dbapi_connection): ): pass else: - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Rollback", trace_attributes): dbapi_connection.rollback() def do_commit(self, dbapi_connection): - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Commit", trace_attributes): dbapi_connection.commit() def do_close(self, dbapi_connection): - trace_attributes = {"db.instance": dbapi_connection.database.name} + trace_attributes = { + "db.instance": dbapi_connection.database.name + if dbapi_connection.database + else "" + } with trace_call("SpannerSqlAlchemy.Close", trace_attributes): dbapi_connection.close() diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index a5b2e3bb1a02..0561de5d5edc 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -2045,3 +2045,17 @@ def test_create_engine_w_invalid_client_object(self): with pytest.raises(ValueError): engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index a13477b3941e..3ff069b22bbd 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -2378,3 +2378,17 @@ def test_create_engine_w_invalid_client_object(self): with pytest.raises(ValueError): engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index fb59b7250727..b4bf26fa5b3b 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -24,7 +24,7 @@ import time from unittest import mock -from google.cloud.spanner_v1 import RequestOptions +from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.engine import Inspector @@ -144,7 +144,7 @@ UnicodeTextTest as _UnicodeTextTest, _UnicodeFixture as __UnicodeFixture, ) # noqa: F401, F403 -from test._helpers import get_db_url +from test._helpers import get_db_url, get_project config.test_schema = "" @@ -3000,3 +3000,44 @@ def test_request_priority(self): engine = create_engine("sqlite:///database") with engine.connect() as connection: pass + + +class CreateEngineWithClientObjectTest(fixtures.TestBase): + def test_create_engine_w_valid_client_object(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + by passing custom Client object. + """ + client = Client(project=get_project()) + engine = create_engine(get_db_url(), connect_args={"client": client}) + with engine.connect() as connection: + assert connection.connection.instance._client == client + + def test_create_engine_w_invalid_client_object(self): + """ + SPANNER TEST: + + Check that if project id in url and custom Client + Object passed to enginer mismatch, error is thrown. + """ + client = Client(project="project_id") + engine = create_engine(get_db_url(), connect_args={"client": client}) + + with pytest.raises(ValueError): + engine.connect() + + +class CreateEngineWithoutDatabaseTest(fixtures.TestBase): + def test_create_engine_wo_database(self): + """ + SPANNER TEST: + + Check that we can connect to SqlAlchemy + without passing database id in the + connection URL. + """ + engine = create_engine(get_db_url().split("/database")[0]) + with engine.connect() as connection: + assert connection.connection.database is None From c9258ff7197fc9a5ae867e2fe1df514cfe3cbae7 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 17:07:01 +0530 Subject: [PATCH 200/582] chore(main): release 1.6.0 (#318) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index d07cac51e81f..1ecea6c59336 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.6.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.5.0...v1.6.0) (2023-04-26) + + +### Features + +* Enable instance-level connection ([#316](https://github.com/googleapis/python-spanner-sqlalchemy/issues/316)) ([9af8e86](https://github.com/googleapis/python-spanner-sqlalchemy/commit/9af8e863f7fb0fa8bea050ca022bbe4e05315d6d)) + ## [1.5.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.4.0...v1.5.0) (2023-04-19) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 9d804245ac5f..d22bc4653607 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.5.0" +__version__ = "1.6.0" From d8046a332cf34c43c9cd4ed5e04449498450920f Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Tue, 23 May 2023 10:32:14 +0530 Subject: [PATCH 201/582] fix: add opentelemetry version (#322) * chore: auto-release * feat:enable instance-level connection * lint * fix: opentelemetry version * changes * changes * changes --- packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg | 2 +- packages/sqlalchemy-spanner/create_test_database.py | 2 +- packages/sqlalchemy-spanner/noxfile.py | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg index d6cf2690b281..972cbc50989e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg @@ -3,5 +3,5 @@ # Only run this nox session. env_vars: { key: "NOX_SESSION" - value: "compliance_test_13" + value: "compliance_test_20" } diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 4d740ddfdb2f..915c5040f995 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -70,7 +70,7 @@ def create_test_instance(): configs = list(CLIENT.list_instance_configs()) if not USE_EMULATOR: # Filter out non "us" locations - configs = [config for config in configs if "us-west1" in config.name] + configs = [config for config in configs if "asia-southeast1" in config.name] instance_config = configs[0].name create_time = str(int(time.time())) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 394269df5abe..77df05f7f74d 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -212,6 +212,10 @@ def compliance_test_14(session): def compliance_test_20(session): """Run SQLAlchemy dialect compliance test suite.""" + # Check the value of `RUN_COMPLIANCE_TESTS` env var. It defaults to true. + if os.environ.get("RUN_COMPLIANCE_TESTS", "true") == "false": + session.skip("RUN_COMPLIANCE_TESTS is set to false, skipping") + # Sanity check: Only run tests if the environment variable is set. if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( "SPANNER_EMULATOR_HOST", "" @@ -228,6 +232,7 @@ def compliance_test_20(session): session.install("mock") session.install("-e", ".[tracing]") + session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") session.run("python", "create_test_database.py") session.install("sqlalchemy>=2.0") From 0cb7311a4bdcc5e6f9163a8d9f398b95e2d7b878 Mon Sep 17 00:00:00 2001 From: Jake Hilton Date: Mon, 22 May 2023 23:56:13 -0600 Subject: [PATCH 202/582] fix: Fix check so it's all lowercase. (#321) Fixes #319 - [x] Tests pass - [x] Appropriate changes to README are included in PR --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index b6bf3278ad8d..f350146eb5a6 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -182,6 +182,7 @@ class SpannerIdentifierPreparer(IdentifierPreparer): reserved_words = RESERVED_WORDS.copy() reserved_words.update(spanner_dbapi.parse_utils.SPANNER_RESERVED_KEYWORDS) + reserved_words_lc = set(map(str.lower, reserved_words)) def __init__(self, dialect): super(SpannerIdentifierPreparer, self).__init__( @@ -195,7 +196,7 @@ def _requires_quotes(self, value): return False return ( - lc_value in self.reserved_words + lc_value in self.reserved_words_lc or value[0] in self.illegal_initial_characters or not self.legal_characters.match(str(value)) or (lc_value != value) From e122181ab5e15e54c19b3f08ed2e86d3a6c24c90 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 15:20:07 +0530 Subject: [PATCH 203/582] chore(main): release 1.6.1 (#323) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 8 ++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 1ecea6c59336..750d78402227 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.6.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.0...v1.6.1) (2023-05-23) + + +### Bug Fixes + +* Add opentelemetry version ([#322](https://github.com/googleapis/python-spanner-sqlalchemy/issues/322)) ([b80d24d](https://github.com/googleapis/python-spanner-sqlalchemy/commit/b80d24d251f07d4c000aa214955cf9729cd49545)) +* Fix check so it's all lowercase. ([#321](https://github.com/googleapis/python-spanner-sqlalchemy/issues/321)) ([8fae358](https://github.com/googleapis/python-spanner-sqlalchemy/commit/8fae3587d5c963539b255c976136b18041147e5b)) + ## [1.6.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.5.0...v1.6.0) (2023-04-26) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index d22bc4653607..a75219edcb36 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.6.0" +__version__ = "1.6.1" From a046afacfb555a55ca93e7d3b5c8c04ce3c2f9ba Mon Sep 17 00:00:00 2001 From: Cody Fincher <204685+cofin@users.noreply.github.com> Date: Wed, 31 May 2023 01:18:06 -0500 Subject: [PATCH 204/582] fix: disables sequence support (#326) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index f350146eb5a6..9fe0914015f2 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -531,7 +531,7 @@ class SpannerDialect(DefaultDialect): supports_sane_rowcount = False supports_sane_multi_rowcount = False supports_default_values = False - supports_sequences = True + supports_sequences = False supports_native_enum = True supports_native_boolean = True supports_native_decimal = True From 6b84509a0e1572eaba87c6d6eddcb57119797f58 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:34:57 +0530 Subject: [PATCH 205/582] chore(main): release 1.6.2 (#327) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 750d78402227..7fd74610d1cc 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.6.2](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.1...v1.6.2) (2023-05-31) + + +### Bug Fixes + +* Disables sequence support ([#326](https://github.com/googleapis/python-spanner-sqlalchemy/issues/326)) ([7b441ff](https://github.com/googleapis/python-spanner-sqlalchemy/commit/7b441ff867160a102ebe88dfa27b3e21b9149007)) + ## [1.6.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.0...v1.6.1) (2023-05-23) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index a75219edcb36..3d0af4f97506 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.6.1" +__version__ = "1.6.2" From 69be80a875f164c36bc2d260d315f6c8eeecdbcf Mon Sep 17 00:00:00 2001 From: Astha Mohta <35952883+asthamohta@users.noreply.github.com> Date: Thu, 3 Aug 2023 16:14:34 +0530 Subject: [PATCH 206/582] chore: change owner to harshachinta (#334) * chore: auto-release * feat:enable instance-level connection * lint * change --- packages/sqlalchemy-spanner/.github/blunderbuss.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/blunderbuss.yml b/packages/sqlalchemy-spanner/.github/blunderbuss.yml index fc2092ed7f76..68b2d1df5465 100644 --- a/packages/sqlalchemy-spanner/.github/blunderbuss.yml +++ b/packages/sqlalchemy-spanner/.github/blunderbuss.yml @@ -1,2 +1,2 @@ assign_issues: - - asthamohta + - harshachinta From 153d3556f3d1935ba12dc87cf1c0949a8659c3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 25 Oct 2023 08:53:31 +0200 Subject: [PATCH 207/582] chore: fix build and lint errors (#351) * chore: fix build and lint errors * test: skip another test using auto increment * test: skip isolation level test --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- packages/sqlalchemy-spanner/test/test_suite_20.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 9fe0914015f2..ca20e134e379 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -304,7 +304,7 @@ def render_literal_value(self, value, type_): generate a SQL statement. """ raw = ["\\", "'", '"', "\n", "\t", "\r"] - if type(value) == str and any(single in value for single in raw): + if isinstance(value, str) and any(single in value for single in raw): value = 'r"""{}"""'.format(value) return value else: diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index b4bf26fa5b3b..ea537a3c0be0 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -2111,6 +2111,10 @@ def test_empty_insert_multiple(self): def test_insert_from_select_autoinc(self): pass + @pytest.mark.skip("Spanner does not support auto increment") + def test_no_results_for_non_returning_insert(self, connection, style, executemany): + pass + def test_autoclose_on_insert(self): """ SPANNER OVERRIDE: @@ -2495,6 +2499,17 @@ class IsOrIsNotDistinctFromTest(_IsOrIsNotDistinctFromTest): pass +@pytest.mark.skip("Spanner doesn't bizarre characters in foreign key names") +class BizarroCharacterFKResolutionTest(fixtures.TestBase): + pass + + +class IsolationLevelTest(fixtures.TestBase): + @pytest.mark.skip("Cloud Spanner does not support different isolation levels") + def test_dialect_user_setting_is_restored(self, testing_engine): + pass + + class OrderByLabelTest(_OrderByLabelTest): @pytest.mark.skip( "Spanner requires an alias for the GROUP BY list when specifying derived " From b7e5fac06deaf28ee7ee2fba43944d51ce019188 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:30:38 +0200 Subject: [PATCH 208/582] build(deps): bump certifi from 2022.12.7 to 2023.7.22 in /.kokoro (#338) Bumps [certifi](https://github.com/certifi/python-certifi) from 2022.12.7 to 2023.7.22. - [Commits](https://github.com/certifi/python-certifi/compare/2022.12.07...2023.07.22) --- updated-dependencies: - dependency-name: certifi dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index aba408a84677..1cd018f2c6e2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ @@ -407,7 +407,7 @@ pygments==2.13.0 \ # via # readme-renderer # rich -PyJWT==2.6.0 \ +pyjwt==2.6.0 \ --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 # via gcp-releasetool @@ -495,5 +495,6 @@ zipp==3.8.1 \ # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# pinned when the requirements file includes hashes and the requirement is not +# satisfied by a package already installed. Consider using the --allow-unsafe flag. # setuptools From d51a0a70d53ed24f17bde1f9aaa02921a0545a0c Mon Sep 17 00:00:00 2001 From: Gilles <113915790+gillesleblanc@users.noreply.github.com> Date: Wed, 25 Oct 2023 07:34:29 -0400 Subject: [PATCH 209/582] fix: db.params OpenTelemetry integration issue (#346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When db.params are not all of the same type OpenTelemetry will log a warning. Prevent this by stringifying values. Also adds a SQLALCHEMY_SPANNER_TRACE_HIDE_QUERY_PARAMETERS env var to prevent logging db.params to OpenTelemetry. Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/_opentelemetry_tracing.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py index cc0e8ac6bad7..5e8c244dab3e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py @@ -14,6 +14,9 @@ """Manages OpenTelemetry trace creation and handling""" +import collections +import os + from contextlib import contextmanager from google.api_core.exceptions import GoogleAPICallError @@ -46,6 +49,16 @@ def trace_call(name, extra_attributes=None): } if extra_attributes: + if os.environ.get("SQLALCHEMY_SPANNER_TRACE_HIDE_QUERY_PARAMETERS"): + extra_attributes.pop("db.params", None) + + # Stringify "db.params" sequence values before sending to OpenTelemetry, + # otherwise OpenTelemetry may log a Warning if types differ. + if isinstance(extra_attributes, dict): + for k, v in extra_attributes.items(): + if k == "db.params" and isinstance(v, collections.abc.Sequence): + extra_attributes[k] = [str(e) for e in v] + attributes.update(extra_attributes) with tracer.start_as_current_span( From 317c0807fc0810acc61c8d2439f08417e4ccc560 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:54:38 +0000 Subject: [PATCH 210/582] build(deps): bump opentelemetry-instrumentation from 0.33b0 to 0.41b0 (#343) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [opentelemetry-instrumentation](https://togithub.com/open-telemetry/opentelemetry-python-contrib) from 0.33b0 to 0.41b0.
Release notes

Sourced from opentelemetry-instrumentation's releases.

opentelemetry-contrib v0.36b0

What's Changed

New Contributors

Full Changelog: https://togithub.com/open-telemetry/opentelemetry-python-contrib/compare/v0.35b0...v0.36b0

opentelemetry-contrib v0.35b0

Deprecated

  • opentelemetry-distro Deprecate otlp_proto_grpc and otlp_proto_http in favor of using OTEL_EXPORTER_OTLP_TRACES_PROTOCOL as according to specifications (#1250)

... (truncated)

Changelog

Sourced from opentelemetry-instrumentation's changelog.

Version 1.20.0/0.41b0 (2023-09-01)

Fixed

  • opentelemetry-instrumentation-asgi Fix UnboundLocalError local variable 'start' referenced before assignment (#1889)
  • Fixed union typing error not compatible with Python 3.7 introduced in opentelemetry-util-http, fix tests introduced by patch related to sanitize method for wsgi (#1913)
  • opentelemetry-instrumentation-celery Unwrap Celery's ExceptionInfo errors and report the actual exception that was raised. (#1863)

Added

  • opentelemetry-resource-detector-azure Add resource detectors for Azure App Service and VM (#1901)

Version 1.19.0/0.40b0 (2023-07-13)

  • opentelemetry-instrumentation-asgi Add http.server.request.size metric (#1867)

Fixed

  • opentelemetry-instrumentation-django Fix empty span name when using path("", ...) (#1788
  • Fix elastic-search instrumentation sanitization to support bulk queries (#1870)
  • Update falcon instrumentation to follow semantic conventions (#1824)
  • Fix sqlalchemy instrumentation wrap methods to accept sqlcommenter options (#1873)

Added

  • Add instrumentor support for cassandra and scylla (#1902)
  • Add instrumentor support for mysqlclient (#1744)
  • Fix async redis clients not being traced correctly (#1830)
  • Make Flask request span attributes available for start_span. (#1784)
  • Fix falcon instrumentation's usage of Span Status to only set the description if the status code is ERROR. (#1840)
  • Instrument all httpx versions >= 0.18. (#1748)
  • Fix Invalid type NoneType for attribute X (opentelemetry-instrumentation-aws-lambda) error when some attributes do not exist (#1780)
  • Add metric instrumentation for celery (#1679)
  • opentelemetry-instrumentation-asgi Add http.server.response.size metric (#1789)

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=opentelemetry-instrumentation&package-manager=pip&previous-version=0.33b0&new-version=0.41b0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://togithub.com/googleapis/python-spanner-sqlalchemy/network/alerts).
--- packages/sqlalchemy-spanner/requirements.txt | 30 +++++--------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 395cbffc1998..3bf0de225ea8 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -194,14 +194,6 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests -importlib-metadata==5.0.0 \ - --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ - --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 - # via alembic -importlib-resources==5.10.1 \ - --hash=sha256:32bb095bda29741f6ef0e5278c42df98d135391bee5f932841efc0041f748dc3 \ - --hash=sha256:c09b067d82e72c66f4f8eb12332f5efbebc9b007c0b6c40818108c9870adc363 - # via alembic mako==1.2.3 \ --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ --hash=sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f @@ -255,9 +247,9 @@ opentelemetry-api==1.13.0 \ # -r requirements.in # opentelemetry-instrumentation # opentelemetry-sdk -opentelemetry-instrumentation==0.33b0 \ - --hash=sha256:763eb288b1c0fff9f6baa5494752cc9997f1f03ae3b03dd1fe0d667b1a04eecf \ - --hash=sha256:90f1eff6e134ad6c1fc2cbd8e0b652c5057deed7b567bfcb40150d8001742161 +opentelemetry-instrumentation==0.41b0 \ + --hash=sha256:0ef9e5705ceca0205992a4a845ae4251ce6ec15a1206ca07c2b00afb0c5bd386 \ + --hash=sha256:214382ba10dfd29d4e24898a4c7ef18b7368178a6277a1aec95cdb75cabf4612 # via -r requirements.in opentelemetry-sdk==1.13.0 \ --hash=sha256:0eddcacd5a484fe2918116b9a4e31867e3d10322ff8392b1c7b0dae1ac724d48 \ @@ -339,7 +331,7 @@ six==1.16.0 \ # via # google-auth # grpcio -SQLAlchemy==1.4.42 \ +sqlalchemy==1.4.42 \ --hash=sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9 \ --hash=sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049 \ --hash=sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80 \ @@ -391,10 +383,7 @@ sqlparse==0.4.3 \ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via - # -r requirements.in - # build - # pep517 + # via -r requirements.in typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e @@ -475,14 +464,9 @@ wrapt==1.14.1 \ # via # deprecated # opentelemetry-instrumentation -zipp==3.8.1 \ - --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ - --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 - # via - # importlib-metadata - # importlib-resources # WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. +# pinned when the requirements file includes hashes and the requirement is not +# satisfied by a package already installed. Consider using the --allow-unsafe flag. # pip # setuptools From 8777d254cb1e6ef991445cb2640ea3e42b279400 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:19:55 +0200 Subject: [PATCH 211/582] build(deps): bump pygments from 2.13.0 to 2.15.0 in /.kokoro (#354) Bumps [pygments](https://github.com/pygments/pygments) from 2.13.0 to 2.15.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.13.0...2.15.0) --- updated-dependencies: - dependency-name: pygments dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 1cd018f2c6e2..4b5f6b8322b4 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -401,9 +401,9 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pygments==2.13.0 \ - --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ - --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 +pygments==2.15.0 \ + --hash=sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094 \ + --hash=sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500 # via # readme-renderer # rich From 054263ed7fb123464a07c4cdfc9c6d4b143e77e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 18:56:17 +0000 Subject: [PATCH 212/582] build(deps): bump grpcio from 1.50.0 to 1.53.0 (#353) Bumps [grpcio](https://togithub.com/grpc/grpc) from 1.50.0 to 1.53.0.
Release notes

Sourced from grpcio's releases.

Release v1.53.0

This is release 1.53.0 (glockenspiel) of gRPC Core.

For gRPC documentation, see grpc.io. For previous releases, see Releases.

This release contains refinements, improvements, and bug fixes, with highlights listed below.

Core

  • xDS: fix crash when removing the last endpoint from the last locality in weighted_target. (#32592)
  • filter stack: pass peer name up via recv_initial_metadata batch. (#31933)
  • [EventEngine] Add advice against blocking work in callbacks. (#32397)
  • [http2] Dont drop connections on metadata limit exceeded. (#32309)
  • xDS: reject aggregate cluster with empty cluster list. (#32238)
  • Fix Python epoll1 Fork Support. (#32196)
  • server: introduce ServerMetricRecorder API and move per-call reporting from a C++ interceptor to a C-core filter. (#32106)
  • [EventEngine] Add invalid handle types to the public API. (#32202)
  • [EventEngine] Refactoring the EventEngine Test Suite: Part 1. (#32127)
  • xDS: fix WeightedClusters total weight handling. (#32134)

C++

  • Update minimum MSVC version to 2019. (#32615)
  • Use CMake variables for paths in pkg-config files. (#31671)

C#

  • Grpc.Tools: Use x86 protoc binaries on arm64 Windows. (#32017)

Python

  • Support python 3.11 on aarch64. (#32270)
  • Include .pyi file. (#32268)
  • De-experimentalize wait-for-ready. (#32143)
  • De-experimentalize compression. (#32138)

Ruby

  • [ruby]: add pre-compiled binaries for ruby 3.2; drop them for ruby 2.6. (#32089)

Release v1.53.0-pre2

This is a prerelease of gRPC Core 1.53.0 (glockenspiel).

For gRPC documentation, see grpc.io. For previous releases, see Releases.

... (truncated)

Commits
  • 358bfb5 Bump version to 1.53.0 (#32685)
  • 6e1ebe7 Backport: Ensure compatibility with the new custom kokoro win2019 image (#326...
  • 44a77f6 Backport 1.53: Update minimum MSVC version to 2019 (#32615)
  • c11153c backport to 1.53: xDS: fix crash when removing the last endpoint from the las...
  • 7c7712a Bump version to 1.53.0-pre2. (#32545)
  • a4017dc backport to 1.53: [promises] Make Poll<T> its own type, not a variant<> (#32540)
  • 3f93c16 Fuzzer fix backport to v1.53 (#32511)
  • 5b244b2 Bump release version to 1.53.0-pre1 (#32428)
  • 6589340 Bump core version 202302161703 (#32416)
  • d49e151 [backoff] Add random early detection classifier (#32354)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=grpcio&package-manager=pip&previous-version=1.50.0&new-version=1.53.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://togithub.com/googleapis/python-spanner-sqlalchemy/network/alerts).
--- packages/sqlalchemy-spanner/requirements.txt | 96 ++++++++++---------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 3bf0de225ea8..ac241cf1b075 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -135,52 +135,52 @@ grpc-google-iam-v1==0.12.4 \ --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ --hash=sha256:3f0ac2c940b9a855d7ce7e31fde28bddb0d9ac362d32d07c67148306931a0e30 # via google-cloud-spanner -grpcio==1.50.0 \ - --hash=sha256:05f7c248e440f538aaad13eee78ef35f0541e73498dd6f832fe284542ac4b298 \ - --hash=sha256:080b66253f29e1646ac53ef288c12944b131a2829488ac3bac8f52abb4413c0d \ - --hash=sha256:12b479839a5e753580b5e6053571de14006157f2ef9b71f38c56dc9b23b95ad6 \ - --hash=sha256:156f8009e36780fab48c979c5605eda646065d4695deea4cfcbcfdd06627ddb6 \ - --hash=sha256:15f9e6d7f564e8f0776770e6ef32dac172c6f9960c478616c366862933fa08b4 \ - --hash=sha256:177afaa7dba3ab5bfc211a71b90da1b887d441df33732e94e26860b3321434d9 \ - --hash=sha256:1a4cd8cb09d1bc70b3ea37802be484c5ae5a576108bad14728f2516279165dd7 \ - --hash=sha256:1d8d02dbb616c0a9260ce587eb751c9c7dc689bc39efa6a88cc4fa3e9c138a7b \ - --hash=sha256:2b71916fa8f9eb2abd93151fafe12e18cebb302686b924bd4ec39266211da525 \ - --hash=sha256:2d9fd6e38b16c4d286a01e1776fdf6c7a4123d99ae8d6b3f0b4a03a34bf6ce45 \ - --hash=sha256:3b611b3de3dfd2c47549ca01abfa9bbb95937eb0ea546ea1d762a335739887be \ - --hash=sha256:3e4244c09cc1b65c286d709658c061f12c61c814be0b7030a2d9966ff02611e0 \ - --hash=sha256:40838061e24f960b853d7bce85086c8e1b81c6342b1f4c47ff0edd44bbae2722 \ - --hash=sha256:4b123fbb7a777a2fedec684ca0b723d85e1d2379b6032a9a9b7851829ed3ca9a \ - --hash=sha256:531f8b46f3d3db91d9ef285191825d108090856b3bc86a75b7c3930f16ce432f \ - --hash=sha256:67dd41a31f6fc5c7db097a5c14a3fa588af54736ffc174af4411d34c4f306f68 \ - --hash=sha256:7489dbb901f4fdf7aec8d3753eadd40839c9085967737606d2c35b43074eea24 \ - --hash=sha256:8d4c8e73bf20fb53fe5a7318e768b9734cf122fe671fcce75654b98ba12dfb75 \ - --hash=sha256:8e69aa4e9b7f065f01d3fdcecbe0397895a772d99954bb82eefbb1682d274518 \ - --hash=sha256:8e8999a097ad89b30d584c034929f7c0be280cd7851ac23e9067111167dcbf55 \ - --hash=sha256:906f4d1beb83b3496be91684c47a5d870ee628715227d5d7c54b04a8de802974 \ - --hash=sha256:92d7635d1059d40d2ec29c8bf5ec58900120b3ce5150ef7414119430a4b2dd5c \ - --hash=sha256:931e746d0f75b2a5cff0a1197d21827a3a2f400c06bace036762110f19d3d507 \ - --hash=sha256:95ce51f7a09491fb3da8cf3935005bff19983b77c4e9437ef77235d787b06842 \ - --hash=sha256:9eea18a878cffc804506d39c6682d71f6b42ec1c151d21865a95fae743fda500 \ - --hash=sha256:a23d47f2fc7111869f0ff547f771733661ff2818562b04b9ed674fa208e261f4 \ - --hash=sha256:a4c23e54f58e016761b576976da6a34d876420b993f45f66a2bfb00363ecc1f9 \ - --hash=sha256:a50a1be449b9e238b9bd43d3857d40edf65df9416dea988929891d92a9f8a778 \ - --hash=sha256:ab5d0e3590f0a16cb88de4a3fa78d10eb66a84ca80901eb2c17c1d2c308c230f \ - --hash=sha256:ae23daa7eda93c1c49a9ecc316e027ceb99adbad750fbd3a56fa9e4a2ffd5ae0 \ - --hash=sha256:af98d49e56605a2912cf330b4627e5286243242706c3a9fa0bcec6e6f68646fc \ - --hash=sha256:b2f77a90ba7b85bfb31329f8eab9d9540da2cf8a302128fb1241d7ea239a5469 \ - --hash=sha256:baab51dcc4f2aecabf4ed1e2f57bceab240987c8b03533f1cef90890e6502067 \ - --hash=sha256:ca8a2254ab88482936ce941485c1c20cdeaef0efa71a61dbad171ab6758ec998 \ - --hash=sha256:cb11464f480e6103c59d558a3875bd84eed6723f0921290325ebe97262ae1347 \ - --hash=sha256:ce8513aee0af9c159319692bfbf488b718d1793d764798c3d5cff827a09e25ef \ - --hash=sha256:cf151f97f5f381163912e8952eb5b3afe89dec9ed723d1561d59cabf1e219a35 \ - --hash=sha256:d144ad10eeca4c1d1ce930faa105899f86f5d99cecfe0d7224f3c4c76265c15e \ - --hash=sha256:d534d169673dd5e6e12fb57cc67664c2641361e1a0885545495e65a7b761b0f4 \ - --hash=sha256:d75061367a69808ab2e84c960e9dce54749bcc1e44ad3f85deee3a6c75b4ede9 \ - --hash=sha256:d84d04dec64cc4ed726d07c5d17b73c343c8ddcd6b59c7199c801d6bbb9d9ed1 \ - --hash=sha256:de411d2b030134b642c092e986d21aefb9d26a28bf5a18c47dd08ded411a3bc5 \ - --hash=sha256:e07fe0d7ae395897981d16be61f0db9791f482f03fee7d1851fe20ddb4f69c03 \ - --hash=sha256:ea8ccf95e4c7e20419b7827aa5b6da6f02720270686ac63bd3493a651830235c \ - --hash=sha256:f7025930039a011ed7d7e7ef95a1cb5f516e23c5a6ecc7947259b67bea8e06ca +grpcio==1.53.0 \ + --hash=sha256:0698c094688a2dd4c7c2f2c0e3e142cac439a64d1cef6904c97f6cde38ba422f \ + --hash=sha256:104a2210edd3776c38448b4f76c2f16e527adafbde171fc72a8a32976c20abc7 \ + --hash=sha256:14817de09317dd7d3fbc8272864288320739973ef0f4b56bf2c0032349da8cdf \ + --hash=sha256:1948539ce78805d4e6256ab0e048ec793956d54787dc9d6777df71c1d19c7f81 \ + --hash=sha256:19caa5b7282a89b799e63776ff602bb39604f7ca98db6df27e2de06756ae86c3 \ + --hash=sha256:1b172e6d497191940c4b8d75b53de82dc252e15b61de2951d577ec5b43316b29 \ + --hash=sha256:1c734a2d4843e4e14ececf5600c3c4750990ec319e1299db7e4f0d02c25c1467 \ + --hash=sha256:2a912397eb8d23c177d6d64e3c8bc46b8a1c7680b090d9f13a640b104aaec77c \ + --hash=sha256:2eddaae8af625e45b5c8500dcca1043264d751a6872cde2eda5022df8a336959 \ + --hash=sha256:55930c56b8f5b347d6c8c609cc341949a97e176c90f5cbb01d148d778f3bbd23 \ + --hash=sha256:658ffe1e39171be00490db5bd3b966f79634ac4215a1eb9a85c6cd6783bf7f6e \ + --hash=sha256:6601d812105583948ab9c6e403a7e2dba6e387cc678c010e74f2d6d589d1d1b3 \ + --hash=sha256:6b6d60b0958be711bab047e9f4df5dbbc40367955f8651232bfdcdd21450b9ab \ + --hash=sha256:6beb84f83360ff29a3654f43f251ec11b809dcb5524b698d711550243debd289 \ + --hash=sha256:752d2949b40e12e6ad3ed8cc552a65b54d226504f6b1fb67cab2ccee502cc06f \ + --hash=sha256:7dc8584ca6c015ad82e186e82f4c0fe977394588f66b8ecfc4ec873285314619 \ + --hash=sha256:82434ba3a5935e47908bc861ce1ebc43c2edfc1001d235d6e31e5d3ed55815f7 \ + --hash=sha256:8270d1dc2c98ab57e6dbf36fa187db8df4c036f04a398e5d5e25b4e01a766d70 \ + --hash=sha256:8a48fd3a7222be226bb86b7b413ad248f17f3101a524018cdc4562eeae1eb2a3 \ + --hash=sha256:95952d3fe795b06af29bb8ec7bbf3342cdd867fc17b77cc25e6733d23fa6c519 \ + --hash=sha256:976a7f24eb213e8429cab78d5e120500dfcdeb01041f1f5a77b17b9101902615 \ + --hash=sha256:9c84a481451e7174f3a764a44150f93b041ab51045aa33d7b5b68b6979114e48 \ + --hash=sha256:a34d6e905f071f9b945cabbcc776e2055de1fdb59cd13683d9aa0a8f265b5bf9 \ + --hash=sha256:a4952899b4931a6ba12951f9a141ef3e74ff8a6ec9aa2dc602afa40f63595e33 \ + --hash=sha256:a96c3c7f564b263c5d7c0e49a337166c8611e89c4c919f66dba7b9a84abad137 \ + --hash=sha256:aef7d30242409c3aa5839b501e877e453a2c8d3759ca8230dd5a21cda029f046 \ + --hash=sha256:b5bd026ac928c96cc23149e6ef79183125542062eb6d1ccec34c0a37e02255e7 \ + --hash=sha256:b6a2ead3de3b2d53119d473aa2f224030257ef33af1e4ddabd4afee1dea5f04c \ + --hash=sha256:ba074af9ca268ad7b05d3fc2b920b5fb3c083da94ab63637aaf67f4f71ecb755 \ + --hash=sha256:c5fb6f3d7824696c1c9f2ad36ddb080ba5a86f2d929ef712d511b4d9972d3d27 \ + --hash=sha256:c705e0c21acb0e8478a00e7e773ad0ecdb34bd0e4adc282d3d2f51ba3961aac7 \ + --hash=sha256:c7ad9fbedb93f331c2e9054e202e95cf825b885811f1bcbbdfdc301e451442db \ + --hash=sha256:da95778d37be8e4e9afca771a83424f892296f5dfb2a100eda2571a1d8bbc0dc \ + --hash=sha256:dad5b302a4c21c604d88a5d441973f320134e6ff6a84ecef9c1139e5ffd466f6 \ + --hash=sha256:dbc1ba968639c1d23476f75c356e549e7bbf2d8d6688717dcab5290e88e8482b \ + --hash=sha256:ddb2511fbbb440ed9e5c9a4b9b870f2ed649b7715859fd6f2ebc585ee85c0364 \ + --hash=sha256:df9ba1183b3f649210788cf80c239041dddcb375d6142d8bccafcfdf549522cd \ + --hash=sha256:e4f513d63df6336fd84b74b701f17d1bb3b64e9d78a6ed5b5e8a198bbbe8bbfa \ + --hash=sha256:e6f90698b5d1c5dd7b3236cd1fa959d7b80e17923f918d5be020b65f1c78b173 \ + --hash=sha256:eaf8e3b97caaf9415227a3c6ca5aa8d800fecadd526538d2bf8f11af783f1550 \ + --hash=sha256:ee81349411648d1abc94095c68cd25e3c2812e4e0367f9a9355be1e804a5135c \ + --hash=sha256:f144a790f14c51b8a8e591eb5af40507ffee45ea6b818c2482f0457fec2e1a2e \ + --hash=sha256:f3e837d29f0e1b9d6e7b29d569e2e9b0da61889e41879832ea15569c251c303a \ + --hash=sha256:fa8eaac75d3107e3f5465f2c9e3bbd13db21790c6e45b7de1756eba16b050aca \ + --hash=sha256:fdc6191587de410a184550d4143e2b24a14df495c86ca15e59508710681690ac # via # google-api-core # googleapis-common-protos @@ -328,9 +328,7 @@ rsa==4.9 \ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 - # via - # google-auth - # grpcio + # via google-auth sqlalchemy==1.4.42 \ --hash=sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9 \ --hash=sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049 \ From d98742cb706ac780d084ba1e2c559e6e9588c6e5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 26 Oct 2023 07:03:11 +0200 Subject: [PATCH 213/582] chore(deps): update dependency protobuf to v3.20.3 (#254) --- .../.kokoro/requirements.txt | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 4b5f6b8322b4..285f39f67274 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -354,30 +354,29 @@ platformdirs==2.5.2 \ --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 # via virtualenv -protobuf==3.20.2 \ - --hash=sha256:03d76b7bd42ac4a6e109742a4edf81ffe26ffd87c5993126d894fe48a120396a \ - --hash=sha256:09e25909c4297d71d97612f04f41cea8fa8510096864f2835ad2f3b3df5a5559 \ - --hash=sha256:18e34a10ae10d458b027d7638a599c964b030c1739ebd035a1dfc0e22baa3bfe \ - --hash=sha256:291fb4307094bf5ccc29f424b42268640e00d5240bf0d9b86bf3079f7576474d \ - --hash=sha256:2c0b040d0b5d5d207936ca2d02f00f765906622c07d3fa19c23a16a8ca71873f \ - --hash=sha256:384164994727f274cc34b8abd41a9e7e0562801361ee77437099ff6dfedd024b \ - --hash=sha256:3cb608e5a0eb61b8e00fe641d9f0282cd0eedb603be372f91f163cbfbca0ded0 \ - --hash=sha256:5d9402bf27d11e37801d1743eada54372f986a372ec9679673bfcc5c60441151 \ - --hash=sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750 \ - --hash=sha256:7a5037af4e76c975b88c3becdf53922b5ffa3f2cddf657574a4920a3b33b80f3 \ - --hash=sha256:8228e56a865c27163d5d1d1771d94b98194aa6917bcfb6ce139cbfa8e3c27334 \ - --hash=sha256:84a1544252a933ef07bb0b5ef13afe7c36232a774affa673fc3636f7cee1db6c \ - --hash=sha256:84fe5953b18a383fd4495d375fe16e1e55e0a3afe7b4f7b4d01a3a0649fcda9d \ - --hash=sha256:9c673c8bfdf52f903081816b9e0e612186684f4eb4c17eeb729133022d6032e3 \ - --hash=sha256:9f876a69ca55aed879b43c295a328970306e8e80a263ec91cf6e9189243c613b \ - --hash=sha256:a9e5ae5a8e8985c67e8944c23035a0dff2c26b0f5070b2f55b217a1c33bbe8b1 \ - --hash=sha256:b4fdb29c5a7406e3f7ef176b2a7079baa68b5b854f364c21abe327bbeec01cdb \ - --hash=sha256:c184485e0dfba4dfd451c3bd348c2e685d6523543a0f91b9fd4ae90eb09e8422 \ - --hash=sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019 \ - --hash=sha256:e39cf61bb8582bda88cdfebc0db163b774e7e03364bbf9ce1ead13863e81e359 \ - --hash=sha256:e8fbc522303e09036c752a0afcc5c0603e917222d8bedc02813fd73b4b4ed804 \ - --hash=sha256:f34464ab1207114e73bba0794d1257c150a2b89b7a9faf504e00af7c9fd58978 \ - --hash=sha256:f52dabc96ca99ebd2169dadbe018824ebda08a795c7684a0b7d203a290f3adb0 +protobuf==3.20.3 \ + --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ + --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ + --hash=sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2 \ + --hash=sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b \ + --hash=sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050 \ + --hash=sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9 \ + --hash=sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7 \ + --hash=sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454 \ + --hash=sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480 \ + --hash=sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469 \ + --hash=sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c \ + --hash=sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e \ + --hash=sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db \ + --hash=sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905 \ + --hash=sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b \ + --hash=sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86 \ + --hash=sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4 \ + --hash=sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402 \ + --hash=sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7 \ + --hash=sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4 \ + --hash=sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99 \ + --hash=sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee # via # gcp-docuploader # gcp-releasetool From 7244901565b9a18f6e234d39c0f9606e69bb6cbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:04:00 +0200 Subject: [PATCH 214/582] build(deps): Bump requests from 2.28.1 to 2.31.0 (#357) Bumps [requests](https://github.com/psf/requests) from 2.28.1 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.1...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../.kokoro/requirements.txt | 20 +++++++++---------- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 285f39f67274..c7623203a6dc 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -155,11 +155,11 @@ filelock==3.8.0 \ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf - # via -r requirements.in + # via -r .kokoro/requirements.in gcp-releasetool==1.10.1 \ --hash=sha256:137b7e2e3fb7d94cb08fb4fe867a5e17d64a1e31dc262d3fd02ec17f49b75843 \ --hash=sha256:728f8bae63d45032aaf32412c5526bcf9f18bd30efed406ab8171943e117292e - # via -r requirements.in + # via -r .kokoro/requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e @@ -268,7 +268,7 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via - # -r requirements.in + # -r .kokoro/requirements.in # twine jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ @@ -339,7 +339,7 @@ more-itertools==8.14.0 \ nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c - # via -r requirements.in + # via -r .kokoro/requirements.in packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 @@ -425,9 +425,9 @@ readme-renderer==37.2 \ --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ --hash=sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923 # via twine -requests==2.28.1 \ - --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ - --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 +requests==2.31.0 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # gcp-releasetool # google-api-core @@ -465,11 +465,11 @@ six==1.16.0 \ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 - # via -r requirements.in + # via -r .kokoro/requirements.in typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e - # via -r requirements.in + # via -r .kokoro/requirements.in urllib3==1.26.12 \ --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 @@ -487,7 +487,7 @@ webencodings==0.5.1 \ wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 - # via -r requirements.in + # via -r .kokoro/requirements.in zipp==3.8.1 \ --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ac241cf1b075..865417969f99 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -317,9 +317,9 @@ pyparsing==3.0.9 \ # via # -r requirements.in # packaging -requests==2.28.1 \ - --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ - --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 +requests==2.31.0 \ + --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ + --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via google-api-core rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ From b571d932510fdf8cc2356a1ad7060c21d1a3199f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 19:36:53 +0200 Subject: [PATCH 215/582] build(deps): Bump sqlparse from 0.4.3 to 0.4.4 (#358) Bumps [sqlparse](https://github.com/andialbrecht/sqlparse) from 0.4.3 to 0.4.4. - [Changelog](https://github.com/andialbrecht/sqlparse/blob/master/CHANGELOG) - [Commits](https://github.com/andialbrecht/sqlparse/compare/0.4.3...0.4.4) --- updated-dependencies: - dependency-name: sqlparse dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 865417969f99..274dd13a7f97 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -374,9 +374,9 @@ sqlalchemy==1.4.42 \ # via # -r requirements.in # alembic -sqlparse==0.4.3 \ - --hash=sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34 \ - --hash=sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268 +sqlparse==0.4.4 \ + --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \ + --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c # via google-cloud-spanner tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ From 83b2c273b2d6f4868f5d77fdaa9228155303c6ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 07:37:02 +0200 Subject: [PATCH 216/582] build(deps): bump urllib3 from 1.26.12 to 1.26.18 (#348) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.12 to 1.26.18. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.12...1.26.18) --- updated-dependencies: - dependency-name: urllib3 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../.kokoro/requirements.txt | 11 +++++--- packages/sqlalchemy-spanner/requirements.txt | 25 ++++++++++++++++--- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c7623203a6dc..3218f1ac385d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -269,6 +269,7 @@ importlib-metadata==5.0.0 \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via # -r .kokoro/requirements.in + # keyring # twine jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ @@ -469,10 +470,12 @@ twine==4.0.1 \ typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e - # via -r .kokoro/requirements.in -urllib3==1.26.12 \ - --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ - --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 + # via + # -r .kokoro/requirements.in + # rich +urllib3==1.26.18 \ + --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ + --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 # via # requests # twine diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 274dd13a7f97..1d66be775905 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -194,6 +194,14 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests +importlib-metadata==6.8.0 \ + --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ + --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743 + # via alembic +importlib-resources==6.1.0 \ + --hash=sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9 \ + --hash=sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83 + # via alembic mako==1.2.3 \ --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ --hash=sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f @@ -381,14 +389,17 @@ sqlparse==0.4.4 \ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via -r requirements.in + # via + # -r requirements.in + # build + # pep517 typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e # via opentelemetry-sdk -urllib3==1.26.12 \ - --hash=sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e \ - --hash=sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997 +urllib3==1.26.18 \ + --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ + --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 # via requests wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ @@ -462,6 +473,12 @@ wrapt==1.14.1 \ # via # deprecated # opentelemetry-instrumentation +zipp==3.17.0 \ + --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ + --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 + # via + # importlib-metadata + # importlib-resources # WARNING: The following packages were not pinned, but pip requires them to be # pinned when the requirements file includes hashes and the requirement is not From b49a2e55815a1ed8f24081c0067ac083cb7868f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 08:54:20 +0000 Subject: [PATCH 217/582] build(deps): bump cryptography from 38.0.1 to 41.0.4 in /.kokoro (#342) Bumps [cryptography](https://togithub.com/pyca/cryptography) from 38.0.1 to 41.0.4.
Changelog

Sourced from cryptography's changelog.

41.0.4 - 2023-09-19


* Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.1.3.

.. _v41-0-3:

41.0.3 - 2023-08-01

  • Fixed performance regression loading DH public keys.
  • Fixed a memory leak when using :class:~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305.
  • Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.1.2.

.. _v41-0-2:

41.0.2 - 2023-07-10


* Fixed bugs in creating and parsing SSH certificates where critical options
  with values were handled incorrectly. Certificates are now created correctly
  and parsing accepts correct values as well as the previously generated
  invalid forms with a warning. In the next release, support for parsing these
  invalid forms will be removed.

.. _v41-0-1:

41.0.1 - 2023-06-01

  • Temporarily allow invalid ECDSA signature algorithm parameters in X.509 certificates, which are generated by older versions of Java.
  • Allow null bytes in pass phrases when serializing private keys.

.. _v41-0-0:

41.0.0 - 2023-05-30


* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been
  removed.  Users on older version of OpenSSL will need to upgrade.
* **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed.
* **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL < 3.6.
* Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0.
* Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.1.1.
* Added support for the :class:`~cryptography.x509.OCSPAcceptableResponses`
  OCSP extension.
* Added support for the :class:`~cryptography.x509.MSCertificateTemplate`
  proprietary Microsoft certificate extension.
</tr></table>

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cryptography&package-manager=pip&previous-version=38.0.1&new-version=41.0.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://togithub.com/googleapis/python-spanner-sqlalchemy/network/alerts).
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .../.kokoro/requirements.txt | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3218f1ac385d..2cce8bbecc46 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -110,33 +110,30 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==38.0.1 \ - --hash=sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a \ - --hash=sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f \ - --hash=sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0 \ - --hash=sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407 \ - --hash=sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7 \ - --hash=sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6 \ - --hash=sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153 \ - --hash=sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750 \ - --hash=sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad \ - --hash=sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6 \ - --hash=sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b \ - --hash=sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5 \ - --hash=sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a \ - --hash=sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d \ - --hash=sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d \ - --hash=sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294 \ - --hash=sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0 \ - --hash=sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a \ - --hash=sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac \ - --hash=sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61 \ - --hash=sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013 \ - --hash=sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e \ - --hash=sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb \ - --hash=sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9 \ - --hash=sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd \ - --hash=sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818 +cryptography==41.0.4 \ + --hash=sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67 \ + --hash=sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311 \ + --hash=sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8 \ + --hash=sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13 \ + --hash=sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143 \ + --hash=sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f \ + --hash=sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829 \ + --hash=sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd \ + --hash=sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397 \ + --hash=sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac \ + --hash=sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d \ + --hash=sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a \ + --hash=sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839 \ + --hash=sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e \ + --hash=sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6 \ + --hash=sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9 \ + --hash=sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860 \ + --hash=sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca \ + --hash=sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91 \ + --hash=sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d \ + --hash=sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714 \ + --hash=sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb \ + --hash=sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f # via # gcp-releasetool # secretstorage @@ -155,11 +152,11 @@ filelock==3.8.0 \ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf - # via -r .kokoro/requirements.in + # via -r requirements.in gcp-releasetool==1.10.1 \ --hash=sha256:137b7e2e3fb7d94cb08fb4fe867a5e17d64a1e31dc262d3fd02ec17f49b75843 \ --hash=sha256:728f8bae63d45032aaf32412c5526bcf9f18bd30efed406ab8171943e117292e - # via -r .kokoro/requirements.in + # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e @@ -268,8 +265,7 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via - # -r .kokoro/requirements.in - # keyring + # -r requirements.in # twine jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ @@ -340,7 +336,7 @@ more-itertools==8.14.0 \ nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c - # via -r .kokoro/requirements.in + # via -r requirements.in packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 @@ -466,13 +462,11 @@ six==1.16.0 \ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 - # via -r .kokoro/requirements.in + # via -r requirements.in typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e - # via - # -r .kokoro/requirements.in - # rich + # via -r requirements.in urllib3==1.26.18 \ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 @@ -490,7 +484,7 @@ webencodings==0.5.1 \ wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 - # via -r .kokoro/requirements.in + # via -r requirements.in zipp==3.8.1 \ --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 From b28671cfa314cfdf67cc7c3b8f2ac097062b72a2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 12:33:44 +0200 Subject: [PATCH 218/582] chore(deps): update dependency gcp-releasetool to v1.16.0 (#360) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 2cce8bbecc46..6c82aa722fe0 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -153,9 +153,9 @@ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf # via -r requirements.in -gcp-releasetool==1.10.1 \ - --hash=sha256:137b7e2e3fb7d94cb08fb4fe867a5e17d64a1e31dc262d3fd02ec17f49b75843 \ - --hash=sha256:728f8bae63d45032aaf32412c5526bcf9f18bd30efed406ab8171943e117292e +gcp-releasetool==1.16.0 \ + --hash=sha256:27bf19d2e87aaa884096ff941aa3c592c482be3d6a2bfe6f06afafa6af2353e3 \ + --hash=sha256:a316b197a543fd036209d0caba7a8eb4d236d8e65381c80cbc6d7efaa7606d63 # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ From 806a00538f3e6c80d9fd083b43f620500e2c85a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 11:54:55 +0000 Subject: [PATCH 219/582] build(deps): bump certifi from 2022.12.7 to 2023.7.22 (#340) Bumps [certifi](https://togithub.com/certifi/python-certifi) from 2022.12.7 to 2023.7.22.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=certifi&package-manager=pip&previous-version=2022.12.7&new-version=2023.7.22)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://togithub.com/googleapis/python-spanner-sqlalchemy/network/alerts).
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .../sqlalchemy-spanner/.kokoro/requirements.txt | 17 ++++++++++------- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 6c82aa722fe0..4f6cdee1b5e2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -152,11 +152,11 @@ filelock==3.8.0 \ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf - # via -r requirements.in + # via -r .kokoro/requirements.in gcp-releasetool==1.16.0 \ --hash=sha256:27bf19d2e87aaa884096ff941aa3c592c482be3d6a2bfe6f06afafa6af2353e3 \ --hash=sha256:a316b197a543fd036209d0caba7a8eb4d236d8e65381c80cbc6d7efaa7606d63 - # via -r requirements.in + # via -r .kokoro/requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e @@ -265,7 +265,8 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via - # -r requirements.in + # -r .kokoro/requirements.in + # keyring # twine jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ @@ -336,7 +337,7 @@ more-itertools==8.14.0 \ nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c - # via -r requirements.in + # via -r .kokoro/requirements.in packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 @@ -462,11 +463,13 @@ six==1.16.0 \ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 - # via -r requirements.in + # via -r .kokoro/requirements.in typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e - # via -r requirements.in + # via + # -r .kokoro/requirements.in + # rich urllib3==1.26.18 \ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 @@ -484,7 +487,7 @@ webencodings==0.5.1 \ wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 - # via -r requirements.in + # via -r .kokoro/requirements.in zipp==3.8.1 \ --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1d66be775905..8259d6dd5196 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests charset-normalizer==2.1.1 \ --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ From b81d0bed8292cf1febc5a4d1acb3b056791a6a92 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 15:16:14 +0200 Subject: [PATCH 220/582] chore(deps): update dependency typing-extensions to v4.8.0 (#362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [typing-extensions](https://togithub.com/python/typing_extensions) ([changelog](https://togithub.com/python/typing_extensions/blob/main/CHANGELOG.md)) | `==4.4.0` -> `==4.8.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/typing-extensions/4.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/typing-extensions/4.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/typing-extensions/4.4.0/4.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/typing-extensions/4.4.0/4.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
python/typing_extensions (typing-extensions) ### [`v4.8.0`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-480-September-17-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.7.1...4.8.0) No changes since 4.8.0rc1. ### [`v4.7.1`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-471-July-2-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.7.0...4.7.1) - Fix support for `TypedDict`, `NamedTuple` and `is_protocol` on PyPy-3.7 and PyPy-3.8. Patch by Alex Waygood. Note that PyPy-3.7 and PyPy-3.8 are unsupported by the PyPy project. The next feature release of typing-extensions will drop support for PyPy-3.7 and may also drop support for PyPy-3.8. ### [`v4.7.0`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-470-June-28-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.6.3...4.7.0) - This is expected to be the last feature release supporting Python 3.7, which reaches its end of life on June 27, 2023. Version 4.8.0 will support only Python 3.8.0 and up. - Fix bug where a `typing_extensions.Protocol` class that had one or more non-callable members would raise `TypeError` when `issubclass()` was called against it, even if it defined a custom `__subclasshook__` method. The correct behaviour -- which has now been restored -- is not to raise `TypeError` in these situations if a custom `__subclasshook__` method is defined. Patch by Alex Waygood (backport[https://togithub.com/python/cpython/pull/105976](https://togithub.com/python/cpython/pull/105976)l/105976). ### [`v4.6.3`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-463-June-1-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.6.2...4.6.3) - Fix a regression introduced in v4.6.0 in the implementation of runtime-checkable protocols. The regression meant that doing `class Foo(X, typing_extensions.Protocol)`, where `X` was a class that had `abc.ABCMeta` as its metaclass, would then cause subsequent `isinstance(1, X)` calls to erroneously raise `TypeError`. Patch by Alex Waygood (backporting the CPython[https://togithub.com/python/cpython/pull/105152](https://togithub.com/python/cpython/pull/105152)l/105152). - Sync the repository's LICENSE file with that of CPython. `typing_extensions` is distributed under the same license as CPython itself. - Skip a problematic test on Python 3.12.0b1. The test fails on 3.12.0b1 due to a bug in CPython, which will be fixed in 3.12.0b2. The `typing_extensions` test suite now passes on 3.12.0b1. ### [`v4.6.2`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-462-May-25-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.6.1...4.6.2) - Fix use of `@deprecated` on classes with `__new__` but no `__init__`. Patch by Jelle Zijlstra. - Fix regression in version 4.6.1 where comparing a generic class against a runtime-checkable protocol using `isinstance()` would cause `AttributeError` to be raised if using Python 3.7. ### [`v4.6.1`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-461-May-23-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.6.0...4.6.1) - Change deprecated `@runtime` to formal API `@runtime_checkable` in the error message. Patch by Xuehai Pan. - Fix regression in 4.6.0 where attempting to define a `Protocol` that was generic over a `ParamSpec` or a `TypeVarTuple` would cause `TypeError` to be raised. Patch by Alex Waygood. ### [`v4.6.0`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-460-May-22-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.5.0...4.6.0) - `typing_extensions` is now documented at https://typing-extensions.readthedocs.io/en/latest/. Patch by Jelle Zijlstra. - Add `typing_extensions.Buffer`, a marker class for buffer types, as proposed by PEP 688. Equivalent to `collections.abc.Buffer` in Python 3.12. Patch by Jelle Zijlstra. - Backport two CPython PRs fixing various issues with `typing.Literal`: [https://togithub.com/python/cpython/pull/23294](https://togithub.com/python/cpython/pull/23294)3294 [https://togithub.com/python/cpython/pull/23383](https://togithub.com/python/cpython/pull/23383)ll/23383. Both CPython PRs were originally by Yurii Karabas, and both were backported to Python >=3.9.1, but no earlier. Patch by Alex Waygood. A side effect of one of the changes is that equality comparisons of `Literal` objects will now raise a `TypeError` if one of the `Literal` objects being compared has a mutable parameter. (Using mutable parameters with `Literal` is not supported by PEP 586 or by any major static type checkers.) - `Literal` is now reimplemented on all Python versions <= 3.10.0. The `typing_extensions` version does not suffer from the bug that was fixed in [https://togithub.com/python/cpython/pull/29334](https://togithub.com/python/cpython/pull/29334)9334. (The CPython bugfix was backported to CPython 3.10.1 and 3.9.8, but no earlier.) - Backport [CPython PR 26067](https://togithub.com/python/cpython/pull/26067) (originally by Yurii Karabas), ensuring that `isinstance()` calls on protocols raise `TypeError` when the protocol is not decorated with `@runtime_checkable`. Patch by Alex Waygood. - Backport several significant performance improvements to runtime-checkable protocols that have been made in Python 3.12 ([https://togithub.com/python/cpython/issues/74690](https://togithub.com/python/cpython/issues/74690)es/74690 for details). Patch by Alex Waygood. A side effect of one of the performance improvements is that the members of a runtime-checkable protocol are now considered β€œfrozen” at runtime as soon as the class has been created. Monkey-patching attributes onto a runtime-checkable protocol will still work, but will have no impact on `isinstance()` checks comparing objects to the protocol. See ["What's New in Python 3.12"](https://docs.python.org/3.12/whatsnew/3.12.html#typing) for more details. - `isinstance()` checks against runtime-checkable protocols now use `inspect.getattr_static()` rather than `hasattr()` to lookup whether attributes exist (backport[https://togithub.com/python/cpython/pull/103034](https://togithub.com/python/cpython/pull/103034)3034). This means that descriptors and `__getattr__` methods are no longer unexpectedly evaluated during `isinstance()` checks against runtime-checkable protocols. However, it may also mean that some objects which used to be considered instances of a runtime-checkable protocol on older versions of `typing_extensions` may no longer be considered instances of that protocol using the new release, and vice versa. Most users are unlikely to be affected by this change. Patch by Alex Waygood. - Backport the ability to define `__init__` methods on Protocol classes, a change made in Python 3.11 (originally implemented[https://togithub.com/python/cpython/pull/31628](https://togithub.com/python/cpython/pull/31628)ll/31628 by Adrian Garcia Badaracco). Patch by Alex Waygood. - Speedup `isinstance(3, typing_extensions.SupportsIndex)` by >10x on Python <3.12. Patch by Alex Waygood. - Add `typing_extensions` versions of `SupportsInt`, `SupportsFloat`, `SupportsComplex`, `SupportsBytes`, `SupportsAbs` and `SupportsRound`. These have the same semantics as the versions from the `typing` module, but `isinstance()` checks against the `typing_extensions` versions are >10x faster at runtime on Python <3.12. Patch by Alex Waygood. - Add `__orig_bases__` to non-generic TypedDicts, call-based TypedDicts, and call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute. Patch by Adrian Garcia Badaracco. - Add `typing_extensions.get_original_bases`, a backport of [`types.get_original_bases`](https://docs.python.org/3.12/library/types.html#types.get_original_bases), introduced in Python 3.12 (CPython[https://togithub.com/python/cpython/pull/101827](https://togithub.com/python/cpython/pull/101827)l/101827, originally by James Hilton-Balfe). Patch by Alex Waygood. This function should always produce correct results when called on classes constructed using features from `typing_extensions`. However, it may produce incorrect results when called on some `NamedTuple` or `TypedDict` classes that use `typing.{NamedTuple,TypedDict}` on Python <=3.11. - Constructing a call-based `TypedDict` using keyword arguments for the fields now causes a `DeprecationWarning` to be emitted. This matches the behaviour of `typing.TypedDict` on 3.11 and 3.12. - Backport the implementation of `NewType` from 3.10 (where it is implemented as a class rather than a function). This allows user-defined `NewType`s to be pickled. Patch by Alex Waygood. - Fix tests and import on Python 3.12, where `typing.TypeVar` can no longer be subclassed. Patch by Jelle Zijlstra. - Add `typing_extensions.TypeAliasType`, a backport of `typing.TypeAliasType` from PEP 695. Patch by Jelle Zijlstra. - Backport changes to the repr of `typing.Unpack` that were made in order to implement [PEP 692](https://peps.python.org/pep-0692/) (backport of [https://togithub.com/python/cpython/pull/104048](https://togithub.com/python/cpython/pull/104048)4048). Patch by Alex Waygood. ### [`v4.5.0`](https://togithub.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-450-February-14-2023) [Compare Source](https://togithub.com/python/typing_extensions/compare/4.4.0...4.5.0) - Runtime support for PEP 702, adding `typing_extensions.deprecated`. Patch by Jelle Zijlstra. - Add better default value for TypeVar `default` parameter, PEP 696. Enables runtime check if `None` was passed as default. Patch by Marc Mueller ([@​cdce8p](https://togithub.com/cdce8p)). - The `@typing_extensions.override` decorator now sets the `.__override__` attribute. Patch by Steven Troxler. - Fix `get_type_hints()` on cross-module inherited `TypedDict` in 3.9 and 3.10. Patch by Carl Meyer. - Add `frozen_default` parameter on `dataclass_transform`. Patch by Erik De Bonte.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 4f6cdee1b5e2..86bacd26e2e0 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -464,9 +464,9 @@ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 # via -r .kokoro/requirements.in -typing-extensions==4.4.0 \ - --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ - --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e +typing-extensions==4.8.0 \ + --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ + --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via # -r .kokoro/requirements.in # rich diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8259d6dd5196..8c35cae08dd0 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -393,9 +393,9 @@ tomli==2.0.1 \ # -r requirements.in # build # pep517 -typing-extensions==4.4.0 \ - --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ - --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e +typing-extensions==4.8.0 \ + --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ + --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via opentelemetry-sdk urllib3==1.26.18 \ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ From 5a75ce84ca2a00cbf9a7e59550f73f4e76a077f8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 16:38:14 +0200 Subject: [PATCH 221/582] chore(deps): update dependency cryptography to v41.0.5 (#363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [cryptography](https://togithub.com/pyca/cryptography) ([changelog](https://cryptography.io/en/latest/changelog/)) | `==41.0.4` -> `==41.0.5` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/cryptography/41.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/cryptography/41.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/cryptography/41.0.4/41.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/cryptography/41.0.4/41.0.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
pyca/cryptography (cryptography) ### [`v41.0.5`](https://togithub.com/pyca/cryptography/compare/41.0.4...41.0.5) [Compare Source](https://togithub.com/pyca/cryptography/compare/41.0.4...41.0.5)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- .../.kokoro/requirements.txt | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 86bacd26e2e0..685abd5d05f5 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -110,30 +110,30 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==41.0.4 \ - --hash=sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67 \ - --hash=sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311 \ - --hash=sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8 \ - --hash=sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13 \ - --hash=sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143 \ - --hash=sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f \ - --hash=sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829 \ - --hash=sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd \ - --hash=sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397 \ - --hash=sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac \ - --hash=sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d \ - --hash=sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a \ - --hash=sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839 \ - --hash=sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e \ - --hash=sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6 \ - --hash=sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9 \ - --hash=sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860 \ - --hash=sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca \ - --hash=sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91 \ - --hash=sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d \ - --hash=sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714 \ - --hash=sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb \ - --hash=sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f +cryptography==41.0.5 \ + --hash=sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf \ + --hash=sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84 \ + --hash=sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e \ + --hash=sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8 \ + --hash=sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7 \ + --hash=sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1 \ + --hash=sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88 \ + --hash=sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86 \ + --hash=sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179 \ + --hash=sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81 \ + --hash=sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20 \ + --hash=sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548 \ + --hash=sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d \ + --hash=sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d \ + --hash=sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5 \ + --hash=sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1 \ + --hash=sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147 \ + --hash=sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936 \ + --hash=sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797 \ + --hash=sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696 \ + --hash=sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72 \ + --hash=sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da \ + --hash=sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723 # via # gcp-releasetool # secretstorage From 59f66f1ec0cecf712aada867e731943719e65bd7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 18:30:11 +0200 Subject: [PATCH 222/582] chore(deps): update dependency deprecated to v1.2.14 (#364) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8c35cae08dd0..4cae11b6f753 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -32,9 +32,9 @@ click==8.1.3 \ # via # -r requirements.in # pip-tools -deprecated==1.2.13 \ - --hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \ - --hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d +Deprecated==1.2.14 \ + --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ + --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 # via opentelemetry-api google-api-core[grpc]==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ From 36a639696440b5e33325f38101347d59123e6569 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 19:52:14 +0200 Subject: [PATCH 223/582] chore(deps): update dependency distlib to v0.3.7 (#365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [distlib](https://togithub.com/pypa/distlib) | `==0.3.6` -> `==0.3.7` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/distlib/0.3.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/distlib/0.3.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/distlib/0.3.6/0.3.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/distlib/0.3.6/0.3.7?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
pypa/distlib (distlib) ### [`v0.3.7`](https://togithub.com/pypa/distlib/compare/0.3.6...0.3.7) [Compare Source](https://togithub.com/pypa/distlib/compare/0.3.6...0.3.7)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 685abd5d05f5..88489a33c13f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -137,9 +137,9 @@ cryptography==41.0.5 \ # via # gcp-releasetool # secretstorage -distlib==0.3.6 \ - --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ - --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e +distlib==0.3.7 \ + --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \ + --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8 # via virtualenv docutils==0.19 \ --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ From b926cc41c0694c3ffe264c6681c047799d3ec72a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 21:12:13 +0200 Subject: [PATCH 224/582] chore(deps): update dependency google-cloud-core to v2.3.3 (#366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-cloud-core](https://togithub.com/googleapis/python-cloud-core) | `==2.3.2` -> `==2.3.3` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/google-cloud-core/2.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/google-cloud-core/2.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/google-cloud-core/2.3.2/2.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/google-cloud-core/2.3.2/2.3.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-cloud-core (google-cloud-core) ### [`v2.3.3`](https://togithub.com/googleapis/python-cloud-core/blob/HEAD/CHANGELOG.md#233-2023-06-29) [Compare Source](https://togithub.com/googleapis/python-cloud-core/compare/v2.3.2...v2.3.3) ##### Documentation - Update docs structure for c.g.c usage ([#​226](https://togithub.com/googleapis/python-cloud-core/issues/226)) ([b805f4a](https://togithub.com/googleapis/python-cloud-core/commit/b805f4a273de53017f74ca693ba7243fb4694848))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 88489a33c13f..b3c643364b74 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -171,9 +171,9 @@ google-auth==2.13.0 \ # google-api-core # google-cloud-core # google-cloud-storage -google-cloud-core==2.3.2 \ - --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ - --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a +google-cloud-core==2.3.3 \ + --hash=sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb \ + --hash=sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863 # via google-cloud-storage google-cloud-storage==2.5.0 \ --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4cae11b6f753..404ba8920cc5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -48,9 +48,9 @@ google-auth==2.13.0 \ # via # google-api-core # google-cloud-core -google-cloud-core==2.3.2 \ - --hash=sha256:8417acf6466be2fa85123441696c4badda48db314c607cf1e5d543fa8bdc22fe \ - --hash=sha256:b9529ee7047fd8d4bf4a2182de619154240df17fbe60ead399078c1ae152af9a +google-cloud-core==2.3.3 \ + --hash=sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb \ + --hash=sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863 # via google-cloud-spanner google-cloud-spanner==3.22.2 \ --hash=sha256:97c1c1d207d63340011e2204e448fa3ccbd9ecc45102e9943a3e65992a136e62 \ From 35a902f9af1796f9108d1ded468ead6c6396c875 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 28 Oct 2023 22:42:13 +0200 Subject: [PATCH 225/582] chore(deps): update dependency google-resumable-media to v2.6.0 (#361) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-resumable-media](https://togithub.com/googleapis/google-resumable-media-python) | `==2.4.0` -> `==2.6.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/google-resumable-media/2.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/google-resumable-media/2.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/google-resumable-media/2.4.0/2.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/google-resumable-media/2.4.0/2.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/google-resumable-media-python (google-resumable-media) ### [`v2.6.0`](https://togithub.com/googleapis/google-resumable-media-python/blob/HEAD/CHANGELOG.md#260-2023-09-06) [Compare Source](https://togithub.com/googleapis/google-resumable-media-python/compare/v2.5.0...v2.6.0) ##### Features - Add support for concurrent XML MPU uploads ([#​395](https://togithub.com/googleapis/google-resumable-media-python/issues/395)) ([a8d56bc](https://togithub.com/googleapis/google-resumable-media-python/commit/a8d56bc7f51b9b75f5735b241b4bcdb5b2c62fd6)) - Introduce compatibility with native namespace packages ([#​385](https://togithub.com/googleapis/google-resumable-media-python/issues/385)) ([cdd7a5e](https://togithub.com/googleapis/google-resumable-media-python/commit/cdd7a5ec140d9e4f77fa7201d9d6dd289f82dabf)) ##### Bug Fixes - Add google-auth to aiohttp extra ([#​386](https://togithub.com/googleapis/google-resumable-media-python/issues/386)) ([30c2ebd](https://togithub.com/googleapis/google-resumable-media-python/commit/30c2ebdb18be28cae522df9fd2af45f1cb2b406d)) ### [`v2.5.0`](https://togithub.com/googleapis/google-resumable-media-python/blob/HEAD/CHANGELOG.md#250-2023-04-21) [Compare Source](https://togithub.com/googleapis/google-resumable-media-python/compare/v2.4.1...v2.5.0) ##### Features - Add support to retry known connection errors ([#​375](https://togithub.com/googleapis/google-resumable-media-python/issues/375)) ([147e845](https://togithub.com/googleapis/google-resumable-media-python/commit/147e8458578cc500dfe98d9ac7a447332fb9c52b)) ### [`v2.4.1`](https://togithub.com/googleapis/google-resumable-media-python/blob/HEAD/CHANGELOG.md#241-2023-01-06) [Compare Source](https://togithub.com/googleapis/google-resumable-media-python/compare/v2.4.0...v2.4.1) ##### Bug Fixes - Avoid validating checksums for partial responses ([#​361](https://togithub.com/googleapis/google-resumable-media-python/issues/361)) ([354287f](https://togithub.com/googleapis/google-resumable-media-python/commit/354287f023c34e269ca5ef0b24b28b9c37ae9dd7))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b3c643364b74..ec6b55d2414e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -249,9 +249,9 @@ google-crc32c==1.5.0 \ --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 # via google-resumable-media -google-resumable-media==2.4.0 \ - --hash=sha256:2aa004c16d295c8f6c33b2b4788ba59d366677c0a25ae7382436cb30f776deaa \ - --hash=sha256:8d5518502f92b9ecc84ac46779bd4f09694ecb3ba38a3e7ca737a86d15cbca1f +google-resumable-media==2.6.0 \ + --hash=sha256:972852f6c65f933e15a4a210c2b96930763b47197cdf4aa5f5bea435efb626e7 \ + --hash=sha256:fc03d344381970f79eebb632a3c18bb1828593a2dc5572b5f90115ef7d11e81b # via google-cloud-storage googleapis-common-protos==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ From 2a7eff2f06da0c3228816cb292a51d4a43251f96 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sun, 29 Oct 2023 06:50:48 +0100 Subject: [PATCH 226/582] chore(deps): update dependency mako to v1.2.4 (#368) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 404ba8920cc5..256798120f23 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -202,9 +202,9 @@ importlib-resources==6.1.0 \ --hash=sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9 \ --hash=sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83 # via alembic -mako==1.2.3 \ - --hash=sha256:7fde96466fcfeedb0eed94f187f20b23d85e4cb41444be0e542e2c8c65c396cd \ - --hash=sha256:c413a086e38cd885088d5e165305ee8eed04e8b3f8f62df343480da0a385735f +Mako==1.2.4 \ + --hash=sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818 \ + --hash=sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34 # via alembic markupsafe==2.1.1 \ --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ From f151d1f1a4d7b4f0cf7bbee5d7016f3691a7b0ce Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sun, 29 Oct 2023 08:16:54 +0100 Subject: [PATCH 227/582] chore(deps): update dependency markupsafe to v2.1.3 (#369) --- .../.kokoro/requirements.txt | 102 +++++++++++------- packages/sqlalchemy-spanner/requirements.txt | 102 +++++++++++------- 2 files changed, 122 insertions(+), 82 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ec6b55d2414e..b47a15944da3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -288,47 +288,67 @@ keyring==23.9.3 \ # via # gcp-releasetool # twine -markupsafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 +MarkupSafe==2.1.3 \ + --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ + --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ + --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ + --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ + --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ + --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ + --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ + --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ + --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ + --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ + --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ + --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ + --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ + --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ + --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ + --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ + --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ + --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ + --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ + --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ + --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ + --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ + --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ + --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ + --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ + --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ + --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ + --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ + --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ + --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ + --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ + --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ + --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ + --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ + --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ + --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ + --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ + --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ + --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ + --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ + --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ + --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ + --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ + --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ + --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ + --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ + --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ + --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ + --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ + --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ + --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ + --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ + --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ + --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ + --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ + --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ + --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ + --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ + --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 # via jinja2 more-itertools==8.14.0 \ --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 256798120f23..ea032ac5c53f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -206,47 +206,67 @@ Mako==1.2.4 \ --hash=sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818 \ --hash=sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34 # via alembic -markupsafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 +MarkupSafe==2.1.3 \ + --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ + --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ + --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ + --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ + --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ + --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ + --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ + --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ + --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ + --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ + --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ + --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ + --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ + --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ + --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ + --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ + --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ + --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ + --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ + --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ + --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ + --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ + --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ + --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ + --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ + --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ + --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ + --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ + --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ + --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ + --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ + --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ + --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ + --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ + --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ + --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ + --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ + --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ + --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ + --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ + --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ + --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ + --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ + --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ + --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ + --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ + --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ + --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ + --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ + --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ + --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ + --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ + --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ + --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ + --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ + --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ + --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ + --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ + --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ + --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 # via mako opentelemetry-api==1.13.0 \ --hash=sha256:2db1e8713f48a119bae457cd22304a7919d5e57190a380485c442c4f731a46dd \ From 7ef7bda1a1c9888ad3e72e1de55d1268d3f57ca2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sun, 29 Oct 2023 21:09:55 +0100 Subject: [PATCH 228/582] chore(deps): update dependency proto-plus to v1.22.3 (#370) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ea032ac5c53f..ec1bd221e615 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -304,9 +304,9 @@ pip-tools==6.12.0 \ --hash=sha256:8e22fbc84ede7ca522ba4b033c4fcf6a6419adabc75d24747be3d8262504489a \ --hash=sha256:f441603c63b16f4af0dd5026f7522a49eddec2bc8a4a4979af44e1f6b0a1c13e # via -r requirements.in -proto-plus==1.22.1 \ - --hash=sha256:6c7dfd122dfef8019ff654746be4f5b1d9c80bba787fe9611b508dd88be3a2fa \ - --hash=sha256:ea8982669a23c379f74495bc48e3dcb47c822c484ce8ee1d1d7beb339d4e34c5 +proto-plus==1.22.3 \ + --hash=sha256:a49cd903bc0b6ab41f76bf65510439d56ca76f868adf0274e738bfdd096894df \ + --hash=sha256:fdcd09713cbd42480740d2fe29c990f7fbd885a67efc328aa8be6ee3e9f76a6b # via google-cloud-spanner protobuf==4.21.6 \ --hash=sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9 \ From e29d91289df63733ee55370f5f2776cd43fd7179 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 30 Oct 2023 06:55:29 +0100 Subject: [PATCH 229/582] chore(deps): update dependency grpc-google-iam-v1 to v0.12.6 (#367) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ec1bd221e615..12d6b087ffc6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -131,9 +131,9 @@ greenlet==1.1.3.post0 \ --hash=sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b \ --hash=sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04 # via sqlalchemy -grpc-google-iam-v1==0.12.4 \ - --hash=sha256:312801ae848aeb8408c099ea372b96d253077e7851aae1a9e745df984f81f20c \ - --hash=sha256:3f0ac2c940b9a855d7ce7e31fde28bddb0d9ac362d32d07c67148306931a0e30 +grpc-google-iam-v1==0.12.6 \ + --hash=sha256:2bc4b8fdf22115a65d751c9317329322602c39b7c86a289c9b72d228d960ef5f \ + --hash=sha256:5c10f3d8dc2d88678ab1a9b0cb5482735c5efee71e6c0cd59f872eef22913f5c # via google-cloud-spanner grpcio==1.53.0 \ --hash=sha256:0698c094688a2dd4c7c2f2c0e3e142cac439a64d1cef6904c97f6cde38ba422f \ From 812ef12def0087655222e254bfa06f72259c20d1 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH <57220027+harshachinta@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:39:13 +0530 Subject: [PATCH 230/582] feat: support sequences (#336) * feat: support sequences in sqlalchemy spanner * feat: remove unsupported test in 1.3 * feat: dummy commit for running build * feat: skip emulator tests * feat: skip emulator tests for sequences * feat: fix lint * feat: fix lint * feat: remove unused imports * feat: remove space * feat: fix lint * feat: fix lint * fix: lint * fix: lint * feat: remove unchanged tests and lint * docs: add comments --- .../cloud/sqlalchemy_spanner/requirements.py | 2 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 102 ++++++++++++- .../sqlalchemy-spanner/test/test_suite_13.py | 127 +++++++++++++++- .../sqlalchemy-spanner/test/test_suite_14.py | 132 ++++++++++++++++- .../sqlalchemy-spanner/test/test_suite_20.py | 136 +++++++++++++++++- 5 files changed, 494 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index 791a6b10edbd..a6e6dc009788 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -81,7 +81,7 @@ def isolation_level(self): @property def sequences(self): - return exclusions.closed() + return exclusions.open() @property def temporary_tables(self): diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index ca20e134e379..7f0b44a9647e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -40,6 +40,7 @@ ) from sqlalchemy.sql.default_comparator import operator_lookup from sqlalchemy.sql.operators import json_getitem_op +from sqlalchemy.sql import expression from google.cloud.spanner_v1.data_types import JsonObject from google.cloud import spanner_dbapi @@ -173,6 +174,16 @@ def pre_exec(self): if priority is not None: self._dbapi_connection.connection.request_priority = priority + def fire_sequence(self, seq, type_): + """Builds a statement for fetching next value of the sequence.""" + return self._execute_scalar( + ( + "SELECT GET_NEXT_SEQUENCE_VALUE(SEQUENCE %s)" + % self.identifier_preparer.format_sequence(seq) + ), + type_, + ) + class SpannerIdentifierPreparer(IdentifierPreparer): """Identifiers compiler. @@ -343,6 +354,20 @@ def limit_clause(self, select, **kw): text += " OFFSET " + self.process(select._offset_clause, **kw) return text + def returning_clause(self, stmt, returning_cols, **kw): + columns = [ + self._label_select_column(None, c, True, False, {}) + for c in expression._select_iterables(returning_cols) + ] + + return "THEN RETURN " + ", ".join(columns) + + def visit_sequence(self, seq, **kw): + """Builds a statement for fetching next value of the sequence.""" + return " GET_NEXT_SEQUENCE_VALUE(SEQUENCE %s)" % self.preparer.format_sequence( + seq + ) + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" @@ -457,6 +482,24 @@ def post_create_table(self, table): return post_cmds + def get_identity_options(self, identity_options): + text = ["sequence_kind = 'bit_reversed_positive'"] + if identity_options.start is not None: + text.append("start_with_counter = %d" % identity_options.start) + return ", ".join(text) + + def visit_create_sequence(self, create, prefix=None, **kw): + """Builds a ``CREATE SEQUENCE`` statement for the sequence.""" + text = "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element) + options = self.get_identity_options(create.element) + if options: + text += " OPTIONS (" + options + ")" + return text + + def visit_drop_sequence(self, drop, **kw): + """Builds a ``DROP SEQUENCE`` statement for the sequence.""" + return "DROP SEQUENCE %s" % self.preparer.format_sequence(drop.element) + class SpannerTypeCompiler(GenericTypeCompiler): """Spanner types compiler. @@ -531,7 +574,8 @@ class SpannerDialect(DefaultDialect): supports_sane_rowcount = False supports_sane_multi_rowcount = False supports_default_values = False - supports_sequences = False + supports_sequences = True + sequences_optional = False supports_native_enum = True supports_native_boolean = True supports_native_decimal = True @@ -694,6 +738,36 @@ def get_view_names(self, connection, schema=None, **kw): return all_views + @engine_to_connection + def get_sequence_names(self, connection, schema=None, **kw): + """ + Return a list of all sequence names available in the database. + + The method is used by SQLAlchemy introspection systems. + + Args: + connection (sqlalchemy.engine.base.Connection): + SQLAlchemy connection or engine object. + schema (str): Optional. Schema name + + Returns: + list: List of sequence names. + """ + sql = """ + SELECT name + FROM information_schema.sequences + WHERE SCHEMA='{}' + """.format( + schema or "" + ) + all_sequences = [] + with connection.connection.database.snapshot() as snap: + rows = list(snap.execute_sql(sql)) + for seq in rows: + all_sequences.append(seq[0]) + + return all_sequences + @engine_to_connection def get_view_definition(self, connection, view_name, schema=None, **kw): """ @@ -1294,6 +1368,32 @@ def has_table(self, connection, table_name, schema=None, **kw): return False + @engine_to_connection + def has_sequence(self, connection, sequence_name, schema=None, **kw): + """Check the existence of a particular sequence in the database. + + Given a :class:`_engine.Connection` object and a string + `sequence_name`, return True if the given sequence exists in + the database, False otherwise. + """ + + with connection.connection.database.snapshot() as snap: + rows = snap.execute_sql( + """ + SELECT true + FROM INFORMATION_SCHEMA.SEQUENCES + WHERE NAME="{sequence_name}" + LIMIT 1 + """.format( + sequence_name=sequence_name + ) + ) + + for _ in rows: + return True + + return False + def set_isolation_level(self, conn_proxy, level): """Set the connection isolation level. diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 0561de5d5edc..ca11979b6bb6 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -37,6 +37,7 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ +from sqlalchemy.testing import is_instance_of from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_true @@ -73,7 +74,10 @@ from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import ( + SequenceTest as _SequenceTest, + HasSequenceTest as _HasSequenceTest, +) # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest @@ -2059,3 +2063,124 @@ def test_create_engine_wo_database(self): engine = create_engine(get_db_url().split("/database")[0]) with engine.connect() as connection: assert connection.connection.database is None + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class SequenceTest(_SequenceTest): + @classmethod + def define_tables(cls, metadata): + Table( + "seq_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_opt_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq_opt", data_type=Integer, optional=True), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_no_returning", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("noret_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + implicit_returning=False, + ) + + def test_insert_lastrowid(self, connection): + r = connection.execute(self.tables.seq_pk.insert(), dict(data="some data")) + assert len(r.inserted_primary_key) == 1 + is_instance_of(r.inserted_primary_key[0], int) + + def test_nextval_direct(self, connection): + r = connection.execute(self.tables.seq_pk.c.id.default) + is_instance_of(r, int) + + def _assert_round_trip(self, table, conn): + row = conn.execute(table.select()).first() + id, name = row + is_instance_of(id, int) + eq_(name, "some data") + + @testing.combinations((True,), (False,), argnames="implicit_returning") + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_insert_roundtrip_translate(self, connection, implicit_returning): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_nextval_direct_schema_translate(self, connection): + pass + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class HasSequenceTest(_HasSequenceTest): + @classmethod + def define_tables(cls, metadata): + sqlalchemy.Sequence("user_id_seq", metadata=metadata) + sqlalchemy.Sequence( + "other_seq", metadata=metadata, nomaxvalue=True, nominvalue=True + ) + Table( + "user_id_table", + metadata, + Column("id", Integer, primary_key=True), + ) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_cache(self, connection, metadata): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_schemas_neg(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_default_not_in_remote(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_remote_not_in_default(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_get_sequence_names_no_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_get_sequence_names_sequences_schema(self, connection): + pass diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 3ff069b22bbd..87437b83c792 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -37,6 +37,7 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ +from sqlalchemy.testing import is_instance_of from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures from sqlalchemy.testing.provision import temp_table_keyword_args @@ -76,7 +77,11 @@ from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import ( + SequenceTest as _SequenceTest, + HasSequenceTest as _HasSequenceTest, + HasSequenceTestEmpty as _HasSequenceTestEmpty, +) # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest from sqlalchemy.testing.suite.test_ddl import TableDDLTest as _TableDDLTest @@ -2392,3 +2397,128 @@ def test_create_engine_wo_database(self): engine = create_engine(get_db_url().split("/database")[0]) with engine.connect() as connection: assert connection.connection.database is None + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class SequenceTest(_SequenceTest): + @classmethod + def define_tables(cls, metadata): + Table( + "seq_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_opt_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq_opt", data_type=Integer, optional=True), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_no_returning", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("noret_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + implicit_returning=False, + ) + + def test_insert_lastrowid(self, connection): + r = connection.execute(self.tables.seq_pk.insert(), dict(data="some data")) + assert len(r.inserted_primary_key) == 1 + is_instance_of(r.inserted_primary_key[0], int) + + def test_nextval_direct(self, connection): + r = connection.execute(self.tables.seq_pk.c.id.default) + is_instance_of(r, int) + + def _assert_round_trip(self, table, conn): + row = conn.execute(table.select()).first() + id, name = row + is_instance_of(id, int) + eq_(name, "some data") + + @testing.combinations((True,), (False,), argnames="implicit_returning") + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_insert_roundtrip_translate(self, connection, implicit_returning): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_nextval_direct_schema_translate(self, connection): + pass + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class HasSequenceTest(_HasSequenceTest): + @classmethod + def define_tables(cls, metadata): + sqlalchemy.Sequence("user_id_seq", metadata=metadata) + sqlalchemy.Sequence( + "other_seq", metadata=metadata, nomaxvalue=True, nominvalue=True + ) + Table( + "user_id_table", + metadata, + Column("id", Integer, primary_key=True), + ) + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_has_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_has_sequence_schemas_neg(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_has_sequence_default_not_in_remote(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_has_sequence_remote_not_in_default(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_get_sequence_names_no_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Spanner doesn't support user defined schemas") + def test_get_sequence_names_sequences_schema(self, connection): + pass + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class HasSequenceTestEmpty(_HasSequenceTestEmpty): + def test_get_sequence_names_no_sequence(self, connection): + super().test_get_sequence_names_no_sequence(connection) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index ea537a3c0be0..50958aaa8741 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -39,6 +39,7 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ +from sqlalchemy.testing import is_instance_of from sqlalchemy.testing import provide_metadata, emits_warning from sqlalchemy.testing import fixtures from sqlalchemy.testing.provision import temp_table_keyword_args @@ -80,7 +81,11 @@ from sqlalchemy.testing.suite.test_deprecations import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_sequence import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_sequence import ( + SequenceTest as _SequenceTest, + HasSequenceTest as _HasSequenceTest, + HasSequenceTestEmpty as _HasSequenceTestEmpty, +) # noqa: F401, F403 from sqlalchemy.testing.suite.test_unicode_ddl import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_update_delete import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_cte import CTETest as _CTETest @@ -3056,3 +3061,132 @@ def test_create_engine_wo_database(self): engine = create_engine(get_db_url().split("/database")[0]) with engine.connect() as connection: assert connection.connection.database is None + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class SequenceTest(_SequenceTest): + @classmethod + def define_tables(cls, metadata): + Table( + "seq_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_opt_pk", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("tab_id_seq_opt", data_type=Integer, optional=True), + primary_key=True, + ), + Column("data", String(50)), + ) + + Table( + "seq_no_returning", + metadata, + Column( + "id", + Integer, + sqlalchemy.Sequence("noret_id_seq"), + primary_key=True, + ), + Column("data", String(50)), + implicit_returning=False, + ) + + def test_insert_lastrowid(self, connection): + r = connection.execute(self.tables.seq_pk.insert(), dict(data="some data")) + assert len(r.inserted_primary_key) == 1 + is_instance_of(r.inserted_primary_key[0], int) + + def test_nextval_direct(self, connection): + r = connection.execute(self.tables.seq_pk.c.id.default) + is_instance_of(r, int) + + def _assert_round_trip(self, table, conn): + row = conn.execute(table.select()).first() + id, name = row + is_instance_of(id, int) + eq_(name, "some data") + + @testing.combinations((True,), (False,), argnames="implicit_returning") + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_insert_roundtrip_translate(self, connection, implicit_returning): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_nextval_direct_schema_translate(self, connection): + pass + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class HasSequenceTest(_HasSequenceTest): + @classmethod + def define_tables(cls, metadata): + sqlalchemy.Sequence("user_id_seq", metadata=metadata) + sqlalchemy.Sequence( + "other_seq", metadata=metadata, nomaxvalue=True, nominvalue=True + ) + Table( + "user_id_table", + metadata, + Column("id", Integer, primary_key=True), + ) + + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_cache(self, connection, metadata): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_schemas_neg(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_default_not_in_remote(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_has_sequence_remote_not_in_default(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_get_sequence_names_no_sequence_schema(self, connection): + pass + + @testing.requires.schemas + @pytest.mark.skip("Not supported by Cloud Spanner") + def test_get_sequence_names_sequences_schema(self, connection): + pass + + +@pytest.mark.skipif( + bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" +) +class HasSequenceTestEmpty(_HasSequenceTestEmpty): + def test_get_sequence_names_no_sequence(self, connection): + super().test_get_sequence_names_no_sequence(connection) From 8c03145bfbac2390e18c5d8426e9efac686e32ef Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 11 Nov 2023 15:23:52 +0100 Subject: [PATCH 231/582] chore(deps): update dependency charset-normalizer to v3 (#282) --- .../.kokoro/requirements.txt | 94 ++++++++++++++++++- packages/sqlalchemy-spanner/requirements.txt | 94 ++++++++++++++++++- 2 files changed, 182 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b47a15944da3..3322b956390a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -90,9 +90,97 @@ cffi==1.15.1 \ --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 # via cryptography -charset-normalizer==2.1.1 \ - --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ - --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f +charset-normalizer==3.3.2 \ + --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ + --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ + --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ + --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ + --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ + --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ + --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ + --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ + --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ + --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ + --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ + --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ + --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ + --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ + --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ + --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ + --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ + --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ + --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ + --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ + --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ + --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ + --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ + --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ + --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ + --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ + --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ + --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ + --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ + --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ + --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ + --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ + --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ + --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ + --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ + --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ + --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ + --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ + --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ + --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ + --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ + --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ + --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ + --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ + --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ + --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ + --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ + --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ + --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ + --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ + --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ + --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ + --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ + --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ + --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ + --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ + --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ + --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ + --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ + --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ + --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ + --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ + --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ + --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ + --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ + --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ + --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ + --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ + --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ + --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ + --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ + --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ + --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ + --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ + --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ + --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ + --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ + --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ + --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ + --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ + --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ + --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ + --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ + --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ + --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ + --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ + --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ + --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ + --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ + --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests click==8.0.4 \ --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 12d6b087ffc6..6772a155e0f2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -22,9 +22,97 @@ certifi==2023.7.22 \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests -charset-normalizer==2.1.1 \ - --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \ - --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f +charset-normalizer==3.3.2 \ + --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ + --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ + --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ + --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ + --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ + --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ + --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ + --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ + --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ + --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ + --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ + --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ + --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ + --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ + --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ + --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ + --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ + --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ + --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ + --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ + --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ + --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ + --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ + --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ + --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ + --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ + --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ + --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ + --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ + --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ + --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ + --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ + --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ + --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ + --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ + --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ + --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ + --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ + --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ + --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ + --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ + --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ + --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ + --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ + --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ + --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ + --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ + --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ + --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ + --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ + --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ + --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ + --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ + --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ + --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ + --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ + --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ + --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ + --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ + --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ + --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ + --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ + --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ + --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ + --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ + --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ + --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ + --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ + --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ + --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ + --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ + --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ + --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ + --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ + --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ + --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ + --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ + --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ + --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ + --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ + --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ + --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ + --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ + --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ + --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ + --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ + --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ + --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ + --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ + --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ From 2deb2293edc0445f32147dbf02fa25fecff513b7 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal <146331865+ankiaga@users.noreply.github.com> Date: Thu, 1 Feb 2024 07:59:41 +0530 Subject: [PATCH 232/582] fix: Fixing test for literals due to change in sqlalchemy core tests (#384) * fix: Fixing test for literals due to change in sqlalchemy core tests * tests: remove editable install in tests * One more literal test fix --- .../.github/sync-repo-settings.yaml | 1 + .../sqlalchemy_spanner/sqlalchemy_spanner.py | 7 +++ packages/sqlalchemy-spanner/noxfile.py | 12 ++-- packages/sqlalchemy-spanner/test/conftest.py | 63 +++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite_20.py | 56 +++++++++++++---- 5 files changed, 122 insertions(+), 17 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml index fd39852dc307..c83e8a4f6133 100644 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml @@ -11,6 +11,7 @@ branchProtectionRules: - 'unit' - 'compliance_tests_13' - 'compliance_tests_14' + - 'compliance_tests_20' - 'migration_tests' - 'cla/google' - 'Kokoro' diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 7f0b44a9647e..47176699fb11 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -23,6 +23,7 @@ format_type, ) from sqlalchemy.exc import NoSuchTableError +from sqlalchemy.sql import elements from sqlalchemy import ForeignKeyConstraint, types from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect, DefaultExecutionContext @@ -314,6 +315,12 @@ def render_literal_value(self, value, type_): in string. Override the method to add additional escape before using it to generate a SQL statement. """ + if value is None and not type_.should_evaluate_none: + # issue #10535 - handle NULL in the compiler without placing + # this onto each type, except for "evaluate None" types + # (e.g. JSON) + return self.process(elements.Null._instance()) + raw = ["\\", "'", '"', "\n", "\t", "\r"] if isinstance(value, str) and any(single in value for single in raw): value = 'r"""{}"""'.format(value) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 77df05f7f74d..614e593dff02 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -145,7 +145,7 @@ def compliance_test_13(session): ) session.install("mock") - session.install("-e", ".[tracing]") + session.install(".[tracing]") session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.24", "--force-reinstall") session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") session.run("pip", "install", "opentelemetry-sdk<=1.10", "--force-reinstall") @@ -191,7 +191,7 @@ def compliance_test_14(session): ) session.install("mock") - session.install("-e", ".[tracing]") + session.install(".[tracing]") session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") session.run("python", "create_test_database.py") session.run( @@ -231,7 +231,7 @@ def compliance_test_20(session): ) session.install("mock") - session.install("-e", ".[tracing]") + session.install(".[tracing]") session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") session.run("python", "create_test_database.py") @@ -257,7 +257,7 @@ def unit(session): # Run SQLAlchemy dialect compliance test suite with OpenTelemetry. session.install("pytest") session.install("mock") - session.install("-e", ".") + session.install(".") session.install("opentelemetry-api==1.1.0") session.install("opentelemetry-sdk==1.1.0") session.install("opentelemetry-instrumentation==0.20b0") @@ -292,7 +292,7 @@ def _migration_test(session): session.run("pip", "install", "sqlalchemy>=1.3.11,<2.0", "--force-reinstall") session.install("pytest") - session.install("-e", ".") + session.install(".") session.install("alembic") session.run("python", "create_test_database.py") @@ -360,7 +360,7 @@ def snippets(session): session.install( "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" ) - session.install("-e", ".") + session.install(".") session.run("python", "create_test_database.py") session.run( "py.test", diff --git a/packages/sqlalchemy-spanner/test/conftest.py b/packages/sqlalchemy-spanner/test/conftest.py index 35767cf2c673..3b01359d1473 100644 --- a/packages/sqlalchemy-spanner/test/conftest.py +++ b/packages/sqlalchemy-spanner/test/conftest.py @@ -16,9 +16,72 @@ import pytest from sqlalchemy.dialects import registry +from sqlalchemy.testing.schema import Column +from sqlalchemy.testing.schema import Table +from sqlalchemy.sql.elements import literal registry.register("spanner", "google.cloud.sqlalchemy_spanner", "SpannerDialect") pytest.register_assert_rewrite("sqlalchemy.testing.assertions") from sqlalchemy.testing.plugin.pytestplugin import * # noqa: E402, F401, F403 + + +@pytest.fixture +def literal_round_trip_spanner(metadata, connection): + # for literal, we test the literal render in an INSERT + # into a typed column. we can then SELECT it back as its + # official type; + + def run( + type_, + input_, + output, + filter_=None, + compare=None, + support_whereclause=True, + ): + t = Table("t", metadata, Column("x", type_)) + t.create(connection) + + for value in input_: + ins = t.insert().values(x=literal(value, type_, literal_execute=True)) + connection.execute(ins) + + if support_whereclause: + if compare: + stmt = t.select().where( + t.c.x + == literal( + compare, + type_, + literal_execute=True, + ), + t.c.x + == literal( + input_[0], + type_, + literal_execute=True, + ), + ) + else: + stmt = t.select().where( + t.c.x + == literal( + compare if compare is not None else input_[0], + type_, + literal_execute=True, + ) + ) + else: + stmt = t.select() + + rows = connection.execute(stmt).all() + assert rows, "No rows returned" + for row in rows: + value = row[0] + if filter_ is not None: + value = filter_(value) + assert value in output + + return run diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 50958aaa8741..8d6d81130f70 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -149,7 +149,10 @@ UnicodeTextTest as _UnicodeTextTest, _UnicodeFixture as __UnicodeFixture, ) # noqa: F401, F403 -from test._helpers import get_db_url, get_project +from test._helpers import ( + get_db_url, + get_project, +) config.test_schema = "" @@ -162,7 +165,7 @@ class BooleanTest(_BooleanTest): def test_render_literal_bool(self): pass - def test_render_literal_bool_true(self, literal_round_trip): + def test_render_literal_bool_true(self, literal_round_trip_spanner): """ SPANNER OVERRIDE: @@ -171,9 +174,9 @@ def test_render_literal_bool_true(self, literal_round_trip): following insertions will fail with `Row [] already exists". Overriding the test to avoid the same failure. """ - literal_round_trip(Boolean(), [True], [True]) + literal_round_trip_spanner(Boolean(), [True], [True]) - def test_render_literal_bool_false(self, literal_round_trip): + def test_render_literal_bool_false(self, literal_round_trip_spanner): """ SPANNER OVERRIDE: @@ -182,7 +185,7 @@ def test_render_literal_bool_false(self, literal_round_trip): following insertions will fail with `Row [] already exists". Overriding the test to avoid the same failure. """ - literal_round_trip(Boolean(), [False], [False]) + literal_round_trip_spanner(Boolean(), [False], [False]) @pytest.mark.skip("Not supported by Cloud Spanner") def test_whereclause(self): @@ -2003,6 +2006,9 @@ def test_huge_int_auto_accommodation(self, connection, intvalue): intvalue, ) + def test_literal(self, literal_round_trip_spanner): + literal_round_trip_spanner(Integer, [5], [5]) + class _UnicodeFixture(__UnicodeFixture): @classmethod @@ -2189,6 +2195,19 @@ def test_dont_truncate_rightside( args[1], ) + def test_literal(self, literal_round_trip_spanner): + # note that in Python 3, this invokes the Unicode + # datatype for the literal part because all strings are unicode + literal_round_trip_spanner(String(40), ["some text"], ["some text"]) + + def test_literal_quoting(self, literal_round_trip_spanner): + data = """some 'text' hey "hi there" that's text""" + literal_round_trip_spanner(String(40), [data], [data]) + + def test_literal_backslashes(self, literal_round_trip_spanner): + data = r"backslash one \ backslash two \\ end" + literal_round_trip_spanner(String(40), [data], [data]) + class TextTest(_TextTest): @classmethod @@ -2224,6 +2243,21 @@ def test_text_empty_strings(self, connection): def test_text_null_strings(self, connection): pass + def test_literal(self, literal_round_trip_spanner): + literal_round_trip_spanner(Text, ["some text"], ["some text"]) + + def test_literal_quoting(self, literal_round_trip_spanner): + data = """some 'text' hey "hi there" that's text""" + literal_round_trip_spanner(Text, [data], [data]) + + def test_literal_backslashes(self, literal_round_trip_spanner): + data = r"backslash one \ backslash two \\ end" + literal_round_trip_spanner(Text, [data], [data]) + + def test_literal_percentsigns(self, literal_round_trip_spanner): + data = r"percent % signs %% percent" + literal_round_trip_spanner(Text, [data], [data]) + class NumericTest(_NumericTest): @testing.fixture @@ -2254,7 +2288,7 @@ def run(type_, input_, output, filter_=None, check_scale=False): return run @emits_warning(r".*does \*not\* support Decimal objects natively") - def test_render_literal_numeric(self, literal_round_trip): + def test_render_literal_numeric(self, literal_round_trip_spanner): """ SPANNER OVERRIDE: @@ -2263,14 +2297,14 @@ def test_render_literal_numeric(self, literal_round_trip): following insertions will fail with `Row [] already exists". Overriding the test to avoid the same failure. """ - literal_round_trip( + literal_round_trip_spanner( Numeric(precision=8, scale=4), [decimal.Decimal("15.7563")], [decimal.Decimal("15.7563")], ) @emits_warning(r".*does \*not\* support Decimal objects natively") - def test_render_literal_numeric_asfloat(self, literal_round_trip): + def test_render_literal_numeric_asfloat(self, literal_round_trip_spanner): """ SPANNER OVERRIDE: @@ -2279,13 +2313,13 @@ def test_render_literal_numeric_asfloat(self, literal_round_trip): following insertions will fail with `Row [] already exists". Overriding the test to avoid the same failure. """ - literal_round_trip( + literal_round_trip_spanner( Numeric(precision=8, scale=4, asdecimal=False), [decimal.Decimal("15.7563")], [15.7563], ) - def test_render_literal_float(self, literal_round_trip): + def test_render_literal_float(self, literal_round_trip_spanner): """ SPANNER OVERRIDE: @@ -2294,7 +2328,7 @@ def test_render_literal_float(self, literal_round_trip): following insertions will fail with `Row [] already exists". Overriding the test to avoid the same failure. """ - literal_round_trip( + literal_round_trip_spanner( Float(4), [decimal.Decimal("15.7563")], [15.7563], From 457ffe8e526429b77e763e4f1a84f35d1295aaa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 5 Feb 2024 11:16:12 +0100 Subject: [PATCH 233/582] chore: support named schemas (#380) * chore: support named schemas Modify information_schema queries so these are able to handle databases that contain multiple schemas. * Reformatting --------- Co-authored-by: Ankit Agarwal <146331865+ankiaga@users.noreply.github.com> Co-authored-by: ankiaga --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 47176699fb11..e228dda8da31 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -846,7 +846,7 @@ def get_multi_columns( col.spanner_type, col.is_nullable, col.generation_expression FROM information_schema.columns as col JOIN information_schema.tables AS t - ON col.table_name = t.table_name + USING (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) WHERE {table_filter_query} {table_type_query} @@ -979,9 +979,14 @@ def get_multi_indexes( ARRAY_AGG(ic.column_ordering) FROM information_schema.indexes as i JOIN information_schema.index_columns AS ic - ON ic.index_name = i.index_name AND ic.table_name = i.table_name + ON ic.index_name = i.index_name + AND ic.table_catalog = i.table_catalog + AND ic.table_schema = i.table_schema + AND ic.table_name = i.table_name JOIN information_schema.tables AS t - ON i.table_name = t.table_name + ON i.table_catalog = t.table_catalog + AND i.table_schema = t.table_schema + AND i.table_name = t.table_name WHERE {table_filter_query} {table_type_query} @@ -1076,9 +1081,11 @@ def get_multi_pk_constraint( SELECT tc.table_schema, tc.table_name, ccu.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu - ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME + USING (TABLE_CATALOG, TABLE_SCHEMA, CONSTRAINT_NAME) JOIN information_schema.tables AS t - ON tc.table_name = t.table_name + ON tc.TABLE_CATALOG = t.TABLE_CATALOG + AND tc.TABLE_SCHEMA = t.TABLE_SCHEMA + AND tc.TABLE_NAME = t.TABLE_NAME WHERE {table_filter_query} {table_type_query} {schema_filter_query} tc.CONSTRAINT_TYPE = "PRIMARY KEY" """.format( @@ -1196,13 +1203,19 @@ def get_multi_foreign_keys( ) FROM information_schema.table_constraints AS tc JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name + USING (table_catalog, table_schema, constraint_name) JOIN information_schema.constraint_table_usage AS ctu - ON ctu.constraint_name = tc.constraint_name + ON ctu.table_catalog = tc.table_catalog + and ctu.table_schema = tc.table_schema + and ctu.constraint_name = tc.constraint_name JOIN information_schema.key_column_usage AS kcu - ON kcu.constraint_name = tc.constraint_name + ON kcu.table_catalog = tc.table_catalog + and kcu.table_schema = tc.table_schema + and kcu.constraint_name = tc.constraint_name JOIN information_schema.tables AS t - ON tc.table_name = t.table_name + ON t.table_catalog = tc.table_catalog + and t.table_schema = tc.table_schema + and t.table_name = tc.table_name WHERE {table_filter_query} {table_type_query} @@ -1323,15 +1336,14 @@ def get_unique_constraints(self, connection, table_name, schema=None, **kw): SELECT ccu.CONSTRAINT_NAME, ccu.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu - ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME -LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc - on tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME + USING (TABLE_CATALOG, TABLE_SCHEMA, CONSTRAINT_NAME) WHERE tc.TABLE_NAME="{table_name}" + AND tc.TABLE_SCHEMA="{table_schema}" AND tc.CONSTRAINT_TYPE = "UNIQUE" - AND rc.CONSTRAINT_NAME IS NOT NULL + AND tc.CONSTRAINT_NAME IS NOT NULL """.format( - table_name=table_name + table_schema=schema or "", table_name=table_name ) cols = [] @@ -1363,10 +1375,10 @@ def has_table(self, connection, table_name, schema=None, **kw): """ SELECT true FROM INFORMATION_SCHEMA.TABLES -WHERE TABLE_NAME="{table_name}" +WHERE TABLE_SCHEMA="{table_schema}" AND TABLE_NAME="{table_name}" LIMIT 1 """.format( - table_name=table_name + table_schema=schema or "", table_name=table_name ) ) @@ -1390,9 +1402,10 @@ def has_sequence(self, connection, sequence_name, schema=None, **kw): SELECT true FROM INFORMATION_SCHEMA.SEQUENCES WHERE NAME="{sequence_name}" + AND SCHEMA="{schema}" LIMIT 1 """.format( - sequence_name=sequence_name + sequence_name=sequence_name, schema=schema or "" ) ) From d6cda6aa09ccc6bfac01febd2239d7f671cec15d Mon Sep 17 00:00:00 2001 From: Ankit Agarwal <146331865+ankiaga@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:19:40 +0530 Subject: [PATCH 234/582] fix: Table name should be quoted by back quotes (`) on DROP TABLE (#385) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e228dda8da31..168de44d972d 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -438,7 +438,7 @@ def visit_drop_table(self, drop_table, **kw): for index in drop_table.element.indexes: indexes += "DROP INDEX {};".format(self.preparer.quote(index.name)) - return indexes + constrs + str(drop_table) + return indexes + constrs + super().visit_drop_table(drop_table) def visit_primary_key_constraint(self, constraint, **kw): """Build primary key definition. From 082f24aad0042d18715bebee7a7d47ebd4d26cb7 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:15:45 +0530 Subject: [PATCH 235/582] chore(main): release 1.7.0 (#355) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 14 ++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 7fd74610d1cc..83533552c59c 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [1.7.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.2...v1.7.0) (2024-02-07) + + +### Features + +* Support sequences ([#336](https://github.com/googleapis/python-spanner-sqlalchemy/issues/336)) ([e35a8a0](https://github.com/googleapis/python-spanner-sqlalchemy/commit/e35a8a01fadce8b5a4b0208f9e6146a4241fa827)) + + +### Bug Fixes + +* Db.params OpenTelemetry integration issue ([#346](https://github.com/googleapis/python-spanner-sqlalchemy/issues/346)) ([0a69031](https://github.com/googleapis/python-spanner-sqlalchemy/commit/0a69031c9145945e5c438df48977329a67f94a78)) +* Fixing test for literals due to change in sqlalchemy core tests ([#384](https://github.com/googleapis/python-spanner-sqlalchemy/issues/384)) ([62cccc3](https://github.com/googleapis/python-spanner-sqlalchemy/commit/62cccc33cba504f8a4c67bd215341a3e747ec9bf)) +* Table name should be quoted by back quotes (`) on DROP TABLE ([#385](https://github.com/googleapis/python-spanner-sqlalchemy/issues/385)) ([628d26c](https://github.com/googleapis/python-spanner-sqlalchemy/commit/628d26c416cbe44871d8114251989d9f581bebf0)) + ## [1.6.2](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.1...v1.6.2) (2023-05-31) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 3d0af4f97506..5c96bcc47d2a 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.6.2" +__version__ = "1.7.0" From 236c7476b0f14412474eee693193180cb6686183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 31 Oct 2024 08:51:12 +0100 Subject: [PATCH 236/582] deps: update all deps (#413) * deps: update all deps * chore: update tests * chore: run code formatter * chore: ignore warning * chore: make script work on Python 3.8 * chore: install setuptools * deps: update pip before running nox * deps: upgrade setuptools * build: remove kokoro presubmit workflows * build: add migration 1310 test runner * build: only run units + 1.4 compliance * build: try this config * build: only run unit tests on Kokoro --- .../.github/workflows/test_suite.yml | 28 +- packages/sqlalchemy-spanner/.gitignore | 4 +- packages/sqlalchemy-spanner/.kokoro/build.sh | 2 + .../.kokoro/presubmit/compliance.cfg | 2 +- .../create_test_database.py | 4 + packages/sqlalchemy-spanner/noxfile.py | 18 +- packages/sqlalchemy-spanner/requirements.txt | 1007 ++++++++--------- packages/sqlalchemy-spanner/setup.py | 46 +- packages/sqlalchemy-spanner/test/_helpers.py | 2 +- .../sqlalchemy-spanner/test/test_suite_20.py | 24 +- .../test/unit/test_opentelemetry_tracing.py | 5 +- 11 files changed, 588 insertions(+), 554 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 5d4e2c3020a7..518325f03f75 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.12 - name: Install nox run: python -m pip install nox - name: Run Lint @@ -102,7 +102,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.12 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -134,3 +134,27 @@ jobs: env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + + migration1310_tests: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + - name: Install nox + run: python -m pip install nox + - name: Run Migration Tests + run: nox -s migration_test_1310 + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/.gitignore b/packages/sqlalchemy-spanner/.gitignore index ff157fe97a8b..6cb13eed1d7e 100644 --- a/packages/sqlalchemy-spanner/.gitignore +++ b/packages/sqlalchemy-spanner/.gitignore @@ -57,4 +57,6 @@ system_tests/local_test_setup # Make sure a generated file isn't accidentally committed. pylintrc -pylintrc.test \ No newline at end of file +pylintrc.test + +test.cfg \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index da86aa22a93c..2c87f74912fe 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -43,6 +43,8 @@ fi # otherwise run all the sessions. if [[ -n "${NOX_SESSION:-}" ]]; then python3 -m nox -s ${NOX_SESSION:-} +elif [[ "${RUN_COMPLIANCE_TESTS}" -eq "false" ]]; then + python3 -m nox -s unit else python3 -m nox fi diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg index 972cbc50989e..1261d8a02f7d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg @@ -3,5 +3,5 @@ # Only run this nox session. env_vars: { key: "NOX_SESSION" - value: "compliance_test_20" + value: "unit" } diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 915c5040f995..1e29d44f7fcf 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -90,6 +90,10 @@ def create_test_instance(): except AlreadyExists: pass # instance was already created + if USE_EMULATOR: + database = instance.database("compliance-test") + database.drop() + try: database = instance.database("compliance-test") created_op = database.create() diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 614e593dff02..80713b166c36 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -78,9 +78,10 @@ class = StreamHandler BLACK_VERSION = "black==22.3.0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] DEFAULT_PYTHON_VERSION = "3.8" +DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.12" -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) def lint(session): """Run linters. @@ -101,7 +102,7 @@ def lint(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) def blacken(session): """Run black. @@ -118,10 +119,10 @@ def blacken(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) def lint_setup_py(session): """Verify that setup.py is valid (including RST check).""" - session.install("docutils", "pygments") + session.install("docutils", "pygments", "setuptools") session.run("python", "setup.py", "check", "--restructuredtext", "--strict") @@ -208,7 +209,7 @@ def compliance_test_14(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) def compliance_test_20(session): """Run SQLAlchemy dialect compliance test suite.""" @@ -255,12 +256,13 @@ def compliance_test_20(session): def unit(session): """Run unit tests.""" # Run SQLAlchemy dialect compliance test suite with OpenTelemetry. + session.install("setuptools") session.install("pytest") session.install("mock") session.install(".") - session.install("opentelemetry-api==1.1.0") - session.install("opentelemetry-sdk==1.1.0") - session.install("opentelemetry-instrumentation==0.20b0") + session.install("opentelemetry-api==1.27.0") + session.install("opentelemetry-sdk==1.27.0") + session.install("opentelemetry-instrumentation==0.48b0") session.run("python", "create_test_config.py", "my-project", "my-instance") session.run("py.test", "--quiet", os.path.join("test/unit"), *session.posargs) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6772a155e0f2..04fea757d921 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -1,592 +1,571 @@ # -# This file is autogenerated by pip-compile with python 3.8 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: # # pip-compile --generate-hashes # -alembic==1.8.1 \ - --hash=sha256:0a024d7f2de88d738d7395ff866997314c837be6104e90c5724350313dee4da4 \ - --hash=sha256:cd0b5e45b14b706426b833f06369b9a6d5ee03f826ec3238723ce8caaf6e5ffa +alembic==1.13.3 \ + --hash=sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2 \ + --hash=sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e # via -r requirements.in -build==0.8.0 \ - --hash=sha256:19b0ed489f92ace6947698c3ca8436cb0556a66e2aa2d34cd70e2a5d27cd0437 \ - --hash=sha256:887a6d471c901b1a6e6574ebaeeebb45e5269a79d095fe9a8f88d6614ed2e5f0 +build==1.2.2.post1 \ + --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ + --hash=sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7 # via # -r requirements.in # pip-tools -cachetools==5.2.0 \ - --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ - --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db +cachetools==5.5.0 \ + --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ + --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via google-auth -certifi==2023.7.22 \ - --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ - --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 +certifi==2024.8.30 \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 # via requests -charset-normalizer==3.3.2 \ - --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ - --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ - --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ - --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ - --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ - --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ - --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ - --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ - --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ - --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ - --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ - --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ - --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ - --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ - --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ - --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ - --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ - --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ - --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ - --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ - --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ - --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ - --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ - --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ - --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ - --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ - --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ - --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ - --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ - --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ - --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ - --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ - --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ - --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ - --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ - --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ - --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ - --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ - --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ - --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ - --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ - --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ - --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ - --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ - --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ - --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ - --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ - --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ - --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ - --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ - --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ - --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ - --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ - --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ - --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ - --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ - --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ - --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ - --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ - --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ - --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ - --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ - --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ - --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ - --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ - --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ - --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ - --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ - --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ - --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ - --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ - --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ - --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ - --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ - --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ - --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ - --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ - --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ - --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ - --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ - --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ - --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ - --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ - --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ - --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ - --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ - --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ - --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ - --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ - --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 +charset-normalizer==3.4.0 \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 # via requests -click==8.1.3 \ - --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ - --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 +click==8.1.7 \ + --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ + --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de # via # -r requirements.in # pip-tools -Deprecated==1.2.14 \ +deprecated==1.2.14 \ --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 - # via opentelemetry-api -google-api-core[grpc]==2.10.2 \ - --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ - --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e + # via + # opentelemetry-api + # opentelemetry-semantic-conventions +google-api-core[grpc]==2.21.0 \ + --hash=sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81 \ + --hash=sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d # via # google-cloud-core # google-cloud-spanner -google-auth==2.13.0 \ - --hash=sha256:9352dd6394093169157e6971526bab9a2799244d68a94a4a609f0dd751ef6f5e \ - --hash=sha256:99510e664155f1a3c0396a076b5deb6367c52ea04d280152c85ac7f51f50eb42 +google-auth==2.35.0 \ + --hash=sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f \ + --hash=sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a # via # google-api-core # google-cloud-core -google-cloud-core==2.3.3 \ - --hash=sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb \ - --hash=sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863 +google-cloud-core==2.4.1 \ + --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ + --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-spanner -google-cloud-spanner==3.22.2 \ - --hash=sha256:97c1c1d207d63340011e2204e448fa3ccbd9ecc45102e9943a3e65992a136e62 \ - --hash=sha256:e045f8c94d190c5d480cb149239fbb9d49153276cc30b967693f532c75bc1757 +google-cloud-spanner==3.49.1 \ + --hash=sha256:261eafb63b0dd55256afcb5f7149b7527e55b5c8aca8059f77771dfe935ab03b \ + --hash=sha256:c064d1175319f8c9b634a3888de226f4ec70493f7ec08a45321a4b17a47fc3ca # via -r requirements.in -googleapis-common-protos[grpc]==1.56.4 \ - --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ - --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 +googleapis-common-protos[grpc]==1.65.0 \ + --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ + --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 # via # google-api-core # grpc-google-iam-v1 # grpcio-status -greenlet==1.1.3.post0 \ - --hash=sha256:0120a879aa2b1ac5118bce959ea2492ba18783f65ea15821680a256dfad04754 \ - --hash=sha256:025b8de2273d2809f027d347aa2541651d2e15d593bbce0d5f502ca438c54136 \ - --hash=sha256:05ae7383f968bba4211b1fbfc90158f8e3da86804878442b4fb6c16ccbcaa519 \ - --hash=sha256:0914f02fcaa8f84f13b2df4a81645d9e82de21ed95633765dd5cc4d3af9d7403 \ - --hash=sha256:0971d37ae0eaf42344e8610d340aa0ad3d06cd2eee381891a10fe771879791f9 \ - --hash=sha256:0a954002064ee919b444b19c1185e8cce307a1f20600f47d6f4b6d336972c809 \ - --hash=sha256:0aa1845944e62f358d63fcc911ad3b415f585612946b8edc824825929b40e59e \ - --hash=sha256:104f29dd822be678ef6b16bf0035dcd43206a8a48668a6cae4d2fe9c7a7abdeb \ - --hash=sha256:11fc7692d95cc7a6a8447bb160d98671ab291e0a8ea90572d582d57361360f05 \ - --hash=sha256:17a69967561269b691747e7f436d75a4def47e5efcbc3c573180fc828e176d80 \ - --hash=sha256:2794eef1b04b5ba8948c72cc606aab62ac4b0c538b14806d9c0d88afd0576d6b \ - --hash=sha256:2c6e942ca9835c0b97814d14f78da453241837419e0d26f7403058e8db3e38f8 \ - --hash=sha256:2ccdc818cc106cc238ff7eba0d71b9c77be868fdca31d6c3b1347a54c9b187b2 \ - --hash=sha256:325f272eb997916b4a3fc1fea7313a8adb760934c2140ce13a2117e1b0a8095d \ - --hash=sha256:39464518a2abe9c505a727af7c0b4efff2cf242aa168be5f0daa47649f4d7ca8 \ - --hash=sha256:3a24f3213579dc8459e485e333330a921f579543a5214dbc935bc0763474ece3 \ - --hash=sha256:3aeac044c324c1a4027dca0cde550bd83a0c0fbff7ef2c98df9e718a5086c194 \ - --hash=sha256:3c22998bfef3fcc1b15694818fc9b1b87c6cc8398198b96b6d355a7bcb8c934e \ - --hash=sha256:467b73ce5dcd89e381292fb4314aede9b12906c18fab903f995b86034d96d5c8 \ - --hash=sha256:4a8b58232f5b72973350c2b917ea3df0bebd07c3c82a0a0e34775fc2c1f857e9 \ - --hash=sha256:4f74aa0092602da2069df0bc6553919a15169d77bcdab52a21f8c5242898f519 \ - --hash=sha256:5662492df0588a51d5690f6578f3bbbd803e7f8d99a99f3bf6128a401be9c269 \ - --hash=sha256:5c2d21c2b768d8c86ad935e404cc78c30d53dea009609c3ef3a9d49970c864b5 \ - --hash=sha256:5edf75e7fcfa9725064ae0d8407c849456553a181ebefedb7606bac19aa1478b \ - --hash=sha256:60839ab4ea7de6139a3be35b77e22e0398c270020050458b3d25db4c7c394df5 \ - --hash=sha256:62723e7eb85fa52e536e516ee2ac91433c7bb60d51099293671815ff49ed1c21 \ - --hash=sha256:64e10f303ea354500c927da5b59c3802196a07468332d292aef9ddaca08d03dd \ - --hash=sha256:66aa4e9a726b70bcbfcc446b7ba89c8cec40f405e51422c39f42dfa206a96a05 \ - --hash=sha256:695d0d8b5ae42c800f1763c9fce9d7b94ae3b878919379150ee5ba458a460d57 \ - --hash=sha256:70048d7b2c07c5eadf8393e6398595591df5f59a2f26abc2f81abca09610492f \ - --hash=sha256:7afa706510ab079fd6d039cc6e369d4535a48e202d042c32e2097f030a16450f \ - --hash=sha256:7cf37343e43404699d58808e51f347f57efd3010cc7cee134cdb9141bd1ad9ea \ - --hash=sha256:8149a6865b14c33be7ae760bcdb73548bb01e8e47ae15e013bf7ef9290ca309a \ - --hash=sha256:814f26b864ed2230d3a7efe0336f5766ad012f94aad6ba43a7c54ca88dd77cba \ - --hash=sha256:82a38d7d2077128a017094aff334e67e26194f46bd709f9dcdacbf3835d47ef5 \ - --hash=sha256:83a7a6560df073ec9de2b7cb685b199dfd12519bc0020c62db9d1bb522f989fa \ - --hash=sha256:8415239c68b2ec9de10a5adf1130ee9cb0ebd3e19573c55ba160ff0ca809e012 \ - --hash=sha256:88720794390002b0c8fa29e9602b395093a9a766b229a847e8d88349e418b28a \ - --hash=sha256:890f633dc8cb307761ec566bc0b4e350a93ddd77dc172839be122be12bae3e10 \ - --hash=sha256:8926a78192b8b73c936f3e87929931455a6a6c6c385448a07b9f7d1072c19ff3 \ - --hash=sha256:8c0581077cf2734569f3e500fab09c0ff6a2ab99b1afcacbad09b3c2843ae743 \ - --hash=sha256:8fda1139d87ce5f7bd80e80e54f9f2c6fe2f47983f1a6f128c47bf310197deb6 \ - --hash=sha256:91a84faf718e6f8b888ca63d0b2d6d185c8e2a198d2a7322d75c303e7097c8b7 \ - --hash=sha256:924df1e7e5db27d19b1359dc7d052a917529c95ba5b8b62f4af611176da7c8ad \ - --hash=sha256:949c9061b8c6d3e6e439466a9be1e787208dec6246f4ec5fffe9677b4c19fcc3 \ - --hash=sha256:9649891ab4153f217f319914455ccf0b86986b55fc0573ce803eb998ad7d6854 \ - --hash=sha256:96656c5f7c95fc02c36d4f6ef32f4e94bb0b6b36e6a002c21c39785a4eec5f5d \ - --hash=sha256:a812df7282a8fc717eafd487fccc5ba40ea83bb5b13eb3c90c446d88dbdfd2be \ - --hash=sha256:a8d24eb5cb67996fb84633fdc96dbc04f2d8b12bfcb20ab3222d6be271616b67 \ - --hash=sha256:bef49c07fcb411c942da6ee7d7ea37430f830c482bf6e4b72d92fd506dd3a427 \ - --hash=sha256:bffba15cff4802ff493d6edcf20d7f94ab1c2aee7cfc1e1c7627c05f1102eee8 \ - --hash=sha256:c0643250dd0756f4960633f5359884f609a234d4066686754e834073d84e9b51 \ - --hash=sha256:c6f90234e4438062d6d09f7d667f79edcc7c5e354ba3a145ff98176f974b8132 \ - --hash=sha256:c8c9301e3274276d3d20ab6335aa7c5d9e5da2009cccb01127bddb5c951f8870 \ - --hash=sha256:c8ece5d1a99a2adcb38f69af2f07d96fb615415d32820108cd340361f590d128 \ - --hash=sha256:cb863057bed786f6622982fb8b2c122c68e6e9eddccaa9fa98fd937e45ee6c4f \ - --hash=sha256:ccbe7129a282ec5797df0451ca1802f11578be018a32979131065565da89b392 \ - --hash=sha256:d25cdedd72aa2271b984af54294e9527306966ec18963fd032cc851a725ddc1b \ - --hash=sha256:d75afcbb214d429dacdf75e03a1d6d6c5bd1fa9c35e360df8ea5b6270fb2211c \ - --hash=sha256:d7815e1519a8361c5ea2a7a5864945906f8e386fa1bc26797b4d443ab11a4589 \ - --hash=sha256:eb6ac495dccb1520667cfea50d89e26f9ffb49fa28496dea2b95720d8b45eb54 \ - --hash=sha256:ec615d2912b9ad807afd3be80bf32711c0ff9c2b00aa004a45fd5d5dde7853d9 \ - --hash=sha256:f5e09dc5c6e1796969fd4b775ea1417d70e49a5df29aaa8e5d10675d9e11872c \ - --hash=sha256:f6661b58412879a2aa099abb26d3c93e91dedaba55a6394d1fb1512a77e85de9 \ - --hash=sha256:f7d20c3267385236b4ce54575cc8e9f43e7673fc761b069c820097092e318e3b \ - --hash=sha256:fe7c51f8a2ab616cb34bc33d810c887e89117771028e1e3d3b77ca25ddeace04 - # via sqlalchemy -grpc-google-iam-v1==0.12.6 \ - --hash=sha256:2bc4b8fdf22115a65d751c9317329322602c39b7c86a289c9b72d228d960ef5f \ - --hash=sha256:5c10f3d8dc2d88678ab1a9b0cb5482735c5efee71e6c0cd59f872eef22913f5c +grpc-google-iam-v1==0.13.1 \ + --hash=sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001 \ + --hash=sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e # via google-cloud-spanner -grpcio==1.53.0 \ - --hash=sha256:0698c094688a2dd4c7c2f2c0e3e142cac439a64d1cef6904c97f6cde38ba422f \ - --hash=sha256:104a2210edd3776c38448b4f76c2f16e527adafbde171fc72a8a32976c20abc7 \ - --hash=sha256:14817de09317dd7d3fbc8272864288320739973ef0f4b56bf2c0032349da8cdf \ - --hash=sha256:1948539ce78805d4e6256ab0e048ec793956d54787dc9d6777df71c1d19c7f81 \ - --hash=sha256:19caa5b7282a89b799e63776ff602bb39604f7ca98db6df27e2de06756ae86c3 \ - --hash=sha256:1b172e6d497191940c4b8d75b53de82dc252e15b61de2951d577ec5b43316b29 \ - --hash=sha256:1c734a2d4843e4e14ececf5600c3c4750990ec319e1299db7e4f0d02c25c1467 \ - --hash=sha256:2a912397eb8d23c177d6d64e3c8bc46b8a1c7680b090d9f13a640b104aaec77c \ - --hash=sha256:2eddaae8af625e45b5c8500dcca1043264d751a6872cde2eda5022df8a336959 \ - --hash=sha256:55930c56b8f5b347d6c8c609cc341949a97e176c90f5cbb01d148d778f3bbd23 \ - --hash=sha256:658ffe1e39171be00490db5bd3b966f79634ac4215a1eb9a85c6cd6783bf7f6e \ - --hash=sha256:6601d812105583948ab9c6e403a7e2dba6e387cc678c010e74f2d6d589d1d1b3 \ - --hash=sha256:6b6d60b0958be711bab047e9f4df5dbbc40367955f8651232bfdcdd21450b9ab \ - --hash=sha256:6beb84f83360ff29a3654f43f251ec11b809dcb5524b698d711550243debd289 \ - --hash=sha256:752d2949b40e12e6ad3ed8cc552a65b54d226504f6b1fb67cab2ccee502cc06f \ - --hash=sha256:7dc8584ca6c015ad82e186e82f4c0fe977394588f66b8ecfc4ec873285314619 \ - --hash=sha256:82434ba3a5935e47908bc861ce1ebc43c2edfc1001d235d6e31e5d3ed55815f7 \ - --hash=sha256:8270d1dc2c98ab57e6dbf36fa187db8df4c036f04a398e5d5e25b4e01a766d70 \ - --hash=sha256:8a48fd3a7222be226bb86b7b413ad248f17f3101a524018cdc4562eeae1eb2a3 \ - --hash=sha256:95952d3fe795b06af29bb8ec7bbf3342cdd867fc17b77cc25e6733d23fa6c519 \ - --hash=sha256:976a7f24eb213e8429cab78d5e120500dfcdeb01041f1f5a77b17b9101902615 \ - --hash=sha256:9c84a481451e7174f3a764a44150f93b041ab51045aa33d7b5b68b6979114e48 \ - --hash=sha256:a34d6e905f071f9b945cabbcc776e2055de1fdb59cd13683d9aa0a8f265b5bf9 \ - --hash=sha256:a4952899b4931a6ba12951f9a141ef3e74ff8a6ec9aa2dc602afa40f63595e33 \ - --hash=sha256:a96c3c7f564b263c5d7c0e49a337166c8611e89c4c919f66dba7b9a84abad137 \ - --hash=sha256:aef7d30242409c3aa5839b501e877e453a2c8d3759ca8230dd5a21cda029f046 \ - --hash=sha256:b5bd026ac928c96cc23149e6ef79183125542062eb6d1ccec34c0a37e02255e7 \ - --hash=sha256:b6a2ead3de3b2d53119d473aa2f224030257ef33af1e4ddabd4afee1dea5f04c \ - --hash=sha256:ba074af9ca268ad7b05d3fc2b920b5fb3c083da94ab63637aaf67f4f71ecb755 \ - --hash=sha256:c5fb6f3d7824696c1c9f2ad36ddb080ba5a86f2d929ef712d511b4d9972d3d27 \ - --hash=sha256:c705e0c21acb0e8478a00e7e773ad0ecdb34bd0e4adc282d3d2f51ba3961aac7 \ - --hash=sha256:c7ad9fbedb93f331c2e9054e202e95cf825b885811f1bcbbdfdc301e451442db \ - --hash=sha256:da95778d37be8e4e9afca771a83424f892296f5dfb2a100eda2571a1d8bbc0dc \ - --hash=sha256:dad5b302a4c21c604d88a5d441973f320134e6ff6a84ecef9c1139e5ffd466f6 \ - --hash=sha256:dbc1ba968639c1d23476f75c356e549e7bbf2d8d6688717dcab5290e88e8482b \ - --hash=sha256:ddb2511fbbb440ed9e5c9a4b9b870f2ed649b7715859fd6f2ebc585ee85c0364 \ - --hash=sha256:df9ba1183b3f649210788cf80c239041dddcb375d6142d8bccafcfdf549522cd \ - --hash=sha256:e4f513d63df6336fd84b74b701f17d1bb3b64e9d78a6ed5b5e8a198bbbe8bbfa \ - --hash=sha256:e6f90698b5d1c5dd7b3236cd1fa959d7b80e17923f918d5be020b65f1c78b173 \ - --hash=sha256:eaf8e3b97caaf9415227a3c6ca5aa8d800fecadd526538d2bf8f11af783f1550 \ - --hash=sha256:ee81349411648d1abc94095c68cd25e3c2812e4e0367f9a9355be1e804a5135c \ - --hash=sha256:f144a790f14c51b8a8e591eb5af40507ffee45ea6b818c2482f0457fec2e1a2e \ - --hash=sha256:f3e837d29f0e1b9d6e7b29d569e2e9b0da61889e41879832ea15569c251c303a \ - --hash=sha256:fa8eaac75d3107e3f5465f2c9e3bbd13db21790c6e45b7de1756eba16b050aca \ - --hash=sha256:fdc6191587de410a184550d4143e2b24a14df495c86ca15e59508710681690ac +grpc-interceptor==0.15.4 \ + --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ + --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 + # via google-cloud-spanner +grpcio==1.67.0 \ + --hash=sha256:014dfc020e28a0d9be7e93a91f85ff9f4a87158b7df9952fe23cc42d29d31e1e \ + --hash=sha256:0892dd200ece4822d72dd0952f7112c542a487fc48fe77568deaaa399c1e717d \ + --hash=sha256:0bb94e66cd8f0baf29bd3184b6aa09aeb1a660f9ec3d85da615c5003154bc2bf \ + --hash=sha256:0c69bf11894cad9da00047f46584d5758d6ebc9b5950c0dc96fec7e0bce5cde9 \ + --hash=sha256:15c05a26a0f7047f720da41dc49406b395c1470eef44ff7e2c506a47ac2c0591 \ + --hash=sha256:16724ffc956ea42967f5758c2f043faef43cb7e48a51948ab593570570d1e68b \ + --hash=sha256:227316b5631260e0bef8a3ce04fa7db4cc81756fea1258b007950b6efc90c05d \ + --hash=sha256:2b7183c80b602b0ad816315d66f2fb7887614ead950416d60913a9a71c12560d \ + --hash=sha256:2f55c1e0e2ae9bdd23b3c63459ee4c06d223b68aeb1961d83c48fb63dc29bc03 \ + --hash=sha256:30d47dbacfd20cbd0c8be9bfa52fdb833b395d4ec32fe5cff7220afc05d08571 \ + --hash=sha256:323741b6699cd2b04a71cb38f502db98f90532e8a40cb675393d248126a268af \ + --hash=sha256:3840994689cc8cbb73d60485c594424ad8adb56c71a30d8948d6453083624b52 \ + --hash=sha256:391df8b0faac84d42f5b8dfc65f5152c48ed914e13c522fd05f2aca211f8bfad \ + --hash=sha256:42199e704095b62688998c2d84c89e59a26a7d5d32eed86d43dc90e7a3bd04aa \ + --hash=sha256:54d16383044e681f8beb50f905249e4e7261dd169d4aaf6e52eab67b01cbbbe2 \ + --hash=sha256:5a1e03c3102b6451028d5dc9f8591131d6ab3c8a0e023d94c28cb930ed4b5f81 \ + --hash=sha256:62492bd534979e6d7127b8a6b29093161a742dee3875873e01964049d5250a74 \ + --hash=sha256:662c8e105c5e5cee0317d500eb186ed7a93229586e431c1bf0c9236c2407352c \ + --hash=sha256:682968427a63d898759474e3b3178d42546e878fdce034fd7474ef75143b64e3 \ + --hash=sha256:74b900566bdf68241118f2918d312d3bf554b2ce0b12b90178091ea7d0a17b3d \ + --hash=sha256:77196216d5dd6f99af1c51e235af2dd339159f657280e65ce7e12c1a8feffd1d \ + --hash=sha256:7f200aca719c1c5dc72ab68be3479b9dafccdf03df530d137632c534bb6f1ee3 \ + --hash=sha256:7fc1d2b9fd549264ae585026b266ac2db53735510a207381be509c315b4af4e8 \ + --hash=sha256:82e5bd4b67b17c8c597273663794a6a46a45e44165b960517fe6d8a2f7f16d23 \ + --hash=sha256:8c9a35b8bc50db35ab8e3e02a4f2a35cfba46c8705c3911c34ce343bd777813a \ + --hash=sha256:985b2686f786f3e20326c4367eebdaed3e7aa65848260ff0c6644f817042cb15 \ + --hash=sha256:9d75641a2fca9ae1ae86454fd25d4c298ea8cc195dbc962852234d54a07060ad \ + --hash=sha256:a4e95e43447a02aa603abcc6b5e727d093d161a869c83b073f50b9390ecf0fa8 \ + --hash=sha256:a6b9a5c18863fd4b6624a42e2712103fb0f57799a3b29651c0e5b8119a519d65 \ + --hash=sha256:aa8d025fae1595a207b4e47c2e087cb88d47008494db258ac561c00877d4c8f8 \ + --hash=sha256:ac11ecb34a86b831239cc38245403a8de25037b448464f95c3315819e7519772 \ + --hash=sha256:ae6de510f670137e755eb2a74b04d1041e7210af2444103c8c95f193340d17ee \ + --hash=sha256:b2a44e572fb762c668e4812156b81835f7aba8a721b027e2d4bb29fb50ff4d33 \ + --hash=sha256:b6eb68493a05d38b426604e1dc93bfc0137c4157f7ab4fac5771fd9a104bbaa6 \ + --hash=sha256:b9bca3ca0c5e74dea44bf57d27e15a3a3996ce7e5780d61b7c72386356d231db \ + --hash=sha256:bd79929b3bb96b54df1296cd3bf4d2b770bd1df6c2bdf549b49bab286b925cdc \ + --hash=sha256:c4c425f440fb81f8d0237c07b9322fc0fb6ee2b29fbef5f62a322ff8fcce240d \ + --hash=sha256:cb204a742997277da678611a809a8409657b1398aaeebf73b3d9563b7d154c13 \ + --hash=sha256:cf51d28063338608cd8d3cd64677e922134837902b70ce00dad7f116e3998210 \ + --hash=sha256:cfd9306511fdfc623a1ba1dc3bc07fbd24e6cfbe3c28b4d1e05177baa2f99617 \ + --hash=sha256:cff8e54d6a463883cda2fab94d2062aad2f5edd7f06ae3ed030f2a74756db365 \ + --hash=sha256:d01793653248f49cf47e5695e0a79805b1d9d4eacef85b310118ba1dfcd1b955 \ + --hash=sha256:d4ea4509d42c6797539e9ec7496c15473177ce9abc89bc5c71e7abe50fc25737 \ + --hash=sha256:d90cfdafcf4b45a7a076e3e2a58e7bc3d59c698c4f6470b0bb13a4d869cf2273 \ + --hash=sha256:e090b2553e0da1c875449c8e75073dd4415dd71c9bde6a406240fdf4c0ee467c \ + --hash=sha256:e91d154689639932305b6ea6f45c6e46bb51ecc8ea77c10ef25aa77f75443ad4 \ + --hash=sha256:eef1dce9d1a46119fd09f9a992cf6ab9d9178b696382439446ca5f399d7b96fe \ + --hash=sha256:efe32b45dd6d118f5ea2e5deaed417d8a14976325c93812dd831908522b402c9 \ + --hash=sha256:f4d613fbf868b2e2444f490d18af472ccb47660ea3df52f068c9c8801e1f3e85 \ + --hash=sha256:f55f077685f61f0fbd06ea355142b71e47e4a26d2d678b3ba27248abfe67163a \ + --hash=sha256:f623c57a5321461c84498a99dddf9d13dac0e40ee056d884d6ec4ebcab647a78 \ + --hash=sha256:f6bd2ab135c64a4d1e9e44679a616c9bc944547357c830fafea5c3caa3de5153 \ + --hash=sha256:f95e15db43e75a534420e04822df91f645664bf4ad21dfaad7d51773c80e6bb4 \ + --hash=sha256:fd6bc27861e460fe28e94226e3673d46e294ca4673d46b224428d197c5935e69 \ + --hash=sha256:fe89295219b9c9e47780a0f1c75ca44211e706d1c598242249fe717af3385ec8 # via # google-api-core # googleapis-common-protos # grpc-google-iam-v1 + # grpc-interceptor # grpcio-status -grpcio-status==1.50.0 \ - --hash=sha256:69be81c4317ec77983fb0eab80221a01e86e833e0fcf2f6acea0a62597c84b93 \ - --hash=sha256:6bcf86b1cb1a8929c9cb75c8593ea001a667f5167cf692627f4b3fc1ae0eded4 +grpcio-status==1.67.0 \ + --hash=sha256:0e79e2e01ba41a6ca6ed9d7a825323c511fe1653a646f8014c7e3c8132527acc \ + --hash=sha256:c3e5a86fa007e9e263cd5f988a8a907484da4caab582874ea2a4a6092734046b # via google-api-core -idna==3.4 \ - --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ - --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==6.8.0 \ - --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ - --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743 - # via alembic -importlib-resources==6.1.0 \ - --hash=sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9 \ - --hash=sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83 - # via alembic -Mako==1.2.4 \ - --hash=sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818 \ - --hash=sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34 +importlib-metadata==8.4.0 \ + --hash=sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1 \ + --hash=sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5 + # via opentelemetry-api +mako==1.3.6 \ + --hash=sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d \ + --hash=sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a # via alembic -MarkupSafe==2.1.3 \ - --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ - --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ - --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ - --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ - --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ - --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ - --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ - --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ - --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ - --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ - --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ - --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ - --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ - --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ - --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ - --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ - --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ - --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ - --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ - --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ - --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ - --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ - --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ - --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ - --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ - --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ - --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ - --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ - --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ - --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ - --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ - --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ - --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ - --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ - --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ - --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ - --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ - --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ - --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ - --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ - --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ - --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ - --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ - --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ - --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ - --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ - --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ - --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ - --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ - --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ - --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ - --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ - --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ - --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ - --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ - --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ - --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ - --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ - --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ - --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 +markupsafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.13.0 \ - --hash=sha256:2db1e8713f48a119bae457cd22304a7919d5e57190a380485c442c4f731a46dd \ - --hash=sha256:e683e869471b99e77238c8739d6ee2f368803329f3b808dfa86a02d0b519c682 +opentelemetry-api==1.27.0 \ + --hash=sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7 \ + --hash=sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342 # via # -r requirements.in # opentelemetry-instrumentation # opentelemetry-sdk -opentelemetry-instrumentation==0.41b0 \ - --hash=sha256:0ef9e5705ceca0205992a4a845ae4251ce6ec15a1206ca07c2b00afb0c5bd386 \ - --hash=sha256:214382ba10dfd29d4e24898a4c7ef18b7368178a6277a1aec95cdb75cabf4612 + # opentelemetry-semantic-conventions +opentelemetry-instrumentation==0.48b0 \ + --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ + --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.13.0 \ - --hash=sha256:0eddcacd5a484fe2918116b9a4e31867e3d10322ff8392b1c7b0dae1ac724d48 \ - --hash=sha256:c7b88e06ebedd22c226b374c207792d30b3f34074a6b8ad8c6dad04a8d16326b +opentelemetry-sdk==1.27.0 \ + --hash=sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d \ + --hash=sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f # via -r requirements.in -opentelemetry-semantic-conventions==0.34b0 \ - --hash=sha256:0c88a5d1f45b820272e0c421fd52ff2188b74582b1bab7ba0f57891dc2f31edf \ - --hash=sha256:b236bd027d2d470c5f7f7a466676182c7e02f486db8296caca25fae0649c3fa3 +opentelemetry-semantic-conventions==0.48b0 \ + --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ + --hash=sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f # via opentelemetry-sdk -packaging==21.3 \ - --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ - --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 - # via - # -r requirements.in - # build - # google-cloud-spanner -pep517==0.13.0 \ - --hash=sha256:4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b \ - --hash=sha256:ae69927c5c172be1add9203726d4b84cf3ebad1edcd5f71fcdc746e66e829f59 +packaging==24.1 \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 # via # -r requirements.in # build -pip-tools==6.12.0 \ - --hash=sha256:8e22fbc84ede7ca522ba4b033c4fcf6a6419adabc75d24747be3d8262504489a \ - --hash=sha256:f441603c63b16f4af0dd5026f7522a49eddec2bc8a4a4979af44e1f6b0a1c13e +pep517==0.13.1 \ + --hash=sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317 \ + --hash=sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721 # via -r requirements.in -proto-plus==1.22.3 \ - --hash=sha256:a49cd903bc0b6ab41f76bf65510439d56ca76f868adf0274e738bfdd096894df \ - --hash=sha256:fdcd09713cbd42480740d2fe29c990f7fbd885a67efc328aa8be6ee3e9f76a6b - # via google-cloud-spanner -protobuf==4.21.6 \ - --hash=sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9 \ - --hash=sha256:308173d3e5a3528787bb8c93abea81d5a950bdce62840d9760effc84127fb39c \ - --hash=sha256:4143513c766db85b9d7c18dbf8339673c8a290131b2a0fe73855ab20770f72b0 \ - --hash=sha256:49f88d56a9180dbb7f6199c920f5bb5c1dd0172f672983bb281298d57c2ac8eb \ - --hash=sha256:6b1040a5661cd5f6e610cbca9cfaa2a17d60e2bb545309bc1b278bb05be44bdd \ - --hash=sha256:77b355c8604fe285536155286b28b0c4cbc57cf81b08d8357bf34829ea982860 \ - --hash=sha256:7a6cc8842257265bdfd6b74d088b829e44bcac3cca234c5fdd6052730017b9ea \ - --hash=sha256:80e6540381080715fddac12690ee42d087d0d17395f8d0078dfd6f1181e7be4c \ - --hash=sha256:8f9e60f7d44592c66e7b332b6a7b4b6e8d8b889393c79dbc3a91f815118f8eac \ - --hash=sha256:9666da97129138585b26afcb63ad4887f602e169cafe754a8258541c553b8b5d \ - --hash=sha256:aa29113ec901281f29d9d27b01193407a98aa9658b8a777b0325e6d97149f5ce \ - --hash=sha256:b6cea204865595a92a7b240e4b65bcaaca3ad5d2ce25d9db3756eba06041138e \ - --hash=sha256:ba596b9ffb85c909fcfe1b1a23136224ed678af3faf9912d3fa483d5f9813c4e \ - --hash=sha256:c7c864148a237f058c739ae7a05a2b403c0dfa4ce7d1f3e5213f352ad52d57c6 +pip-tools==7.4.1 \ + --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \ + --hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9 + # via -r requirements.in +proto-plus==1.25.0 \ + --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ + --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 + # via + # google-api-core + # google-cloud-spanner +protobuf==5.28.3 \ + --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ + --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ + --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ + --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ + --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ + --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ + --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ + --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ + --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ + --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ + --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed # via # google-api-core # google-cloud-spanner # googleapis-common-protos + # grpc-google-iam-v1 # grpcio-status # proto-plus -pyasn1==0.4.8 \ - --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ - --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pyasn1==0.6.1 \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 # via # pyasn1-modules # rsa -pyasn1-modules==0.2.8 \ - --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ - --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 +pyasn1-modules==0.4.1 \ + --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ + --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c # via google-auth -pyparsing==3.0.9 \ - --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ - --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc +pyparsing==3.2.0 \ + --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ + --hash=sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c + # via -r requirements.in +pyproject-hooks==1.2.0 \ + --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ + --hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913 # via - # -r requirements.in - # packaging -requests==2.31.0 \ - --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ - --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 + # build + # pip-tools +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 # via google-api-core rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 # via google-auth -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 - # via google-auth -sqlalchemy==1.4.42 \ - --hash=sha256:04f2598c70ea4a29b12d429a80fad3a5202d56dce19dd4916cc46a965a5ca2e9 \ - --hash=sha256:0501f74dd2745ec38f44c3a3900fb38b9db1ce21586b691482a19134062bf049 \ - --hash=sha256:0ee377eb5c878f7cefd633ab23c09e99d97c449dd999df639600f49b74725b80 \ - --hash=sha256:11b2ec26c5d2eefbc3e6dca4ec3d3d95028be62320b96d687b6e740424f83b7d \ - --hash=sha256:15d878929c30e41fb3d757a5853b680a561974a0168cd33a750be4ab93181628 \ - --hash=sha256:177e41914c476ed1e1b77fd05966ea88c094053e17a85303c4ce007f88eff363 \ - --hash=sha256:1811a0b19a08af7750c0b69e38dec3d46e47c4ec1d74b6184d69f12e1c99a5e0 \ - --hash=sha256:1d0c23ecf7b3bc81e29459c34a3f4c68ca538de01254e24718a7926810dc39a6 \ - --hash=sha256:22459fc1718785d8a86171bbe7f01b5c9d7297301ac150f508d06e62a2b4e8d2 \ - --hash=sha256:28e881266a172a4d3c5929182fde6bb6fba22ac93f137d5380cc78a11a9dd124 \ - --hash=sha256:2e56dfed0cc3e57b2f5c35719d64f4682ef26836b81067ee6cfad062290fd9e2 \ - --hash=sha256:2fd49af453e590884d9cdad3586415922a8e9bb669d874ee1dc55d2bc425aacd \ - --hash=sha256:3ab7c158f98de6cb4f1faab2d12973b330c2878d0c6b689a8ca424c02d66e1b3 \ - --hash=sha256:4948b6c5f4e56693bbeff52f574279e4ff972ea3353f45967a14c30fb7ae2beb \ - --hash=sha256:4e1c5f8182b4f89628d782a183d44db51b5af84abd6ce17ebb9804355c88a7b5 \ - --hash=sha256:5ce6929417d5dce5ad1d3f147db81735a4a0573b8fb36e3f95500a06eaddd93e \ - --hash=sha256:5ede1495174e69e273fad68ad45b6d25c135c1ce67723e40f6cf536cb515e20b \ - --hash=sha256:5f966b64c852592469a7eb759615bbd351571340b8b344f1d3fa2478b5a4c934 \ - --hash=sha256:6045b3089195bc008aee5c273ec3ba9a93f6a55bc1b288841bd4cfac729b6516 \ - --hash=sha256:6c9d004eb78c71dd4d3ce625b80c96a827d2e67af9c0d32b1c1e75992a7916cc \ - --hash=sha256:6e39e97102f8e26c6c8550cb368c724028c575ec8bc71afbbf8faaffe2b2092a \ - --hash=sha256:723e3b9374c1ce1b53564c863d1a6b2f1dc4e97b1c178d9b643b191d8b1be738 \ - --hash=sha256:876eb185911c8b95342b50a8c4435e1c625944b698a5b4a978ad2ffe74502908 \ - --hash=sha256:9256563506e040daddccaa948d055e006e971771768df3bb01feeb4386c242b0 \ - --hash=sha256:934472bb7d8666727746a75670a1f8d91a9cae8c464bba79da30a0f6faccd9e1 \ - --hash=sha256:97ff50cd85bb907c2a14afb50157d0d5486a4b4639976b4a3346f34b6d1b5272 \ - --hash=sha256:9b01d9cd2f9096f688c71a3d0f33f3cd0af8549014e66a7a7dee6fc214a7277d \ - --hash=sha256:9e3a65ce9ed250b2f096f7b559fe3ee92e6605fab3099b661f0397a9ac7c8d95 \ - --hash=sha256:a7dd5b7b34a8ba8d181402d824b87c5cee8963cb2e23aa03dbfe8b1f1e417cde \ - --hash=sha256:a85723c00a636eed863adb11f1e8aaa36ad1c10089537823b4540948a8429798 \ - --hash=sha256:b42c59ffd2d625b28cdb2ae4cde8488543d428cba17ff672a543062f7caee525 \ - --hash=sha256:bd448b262544b47a2766c34c0364de830f7fb0772d9959c1c42ad61d91ab6565 \ - --hash=sha256:ca9389a00f639383c93ed00333ed763812f80b5ae9e772ea32f627043f8c9c88 \ - --hash=sha256:df76e9c60879fdc785a34a82bf1e8691716ffac32e7790d31a98d7dec6e81545 \ - --hash=sha256:e12c6949bae10f1012ab5c0ea52ab8db99adcb8c7b717938252137cdf694c775 \ - --hash=sha256:e4ef8cb3c5b326f839bfeb6af5f406ba02ad69a78c7aac0fbeeba994ad9bb48a \ - --hash=sha256:e7e740453f0149437c101ea4fdc7eea2689938c5760d7dcc436c863a12f1f565 \ - --hash=sha256:effc89e606165ca55f04f3f24b86d3e1c605e534bf1a96e4e077ce1b027d0b71 \ - --hash=sha256:f0f574465b78f29f533976c06b913e54ab4980b9931b69aa9d306afff13a9471 \ - --hash=sha256:fa5b7eb2051e857bf83bade0641628efe5a88de189390725d3e6033a1fff4257 \ - --hash=sha256:fdb94a3d1ba77ff2ef11912192c066f01e68416f554c194d769391638c8ad09a +sqlalchemy==2.0.36 \ + --hash=sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763 \ + --hash=sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436 \ + --hash=sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2 \ + --hash=sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588 \ + --hash=sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e \ + --hash=sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959 \ + --hash=sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d \ + --hash=sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575 \ + --hash=sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908 \ + --hash=sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8 \ + --hash=sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8 \ + --hash=sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545 \ + --hash=sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7 \ + --hash=sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971 \ + --hash=sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855 \ + --hash=sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c \ + --hash=sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71 \ + --hash=sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d \ + --hash=sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb \ + --hash=sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72 \ + --hash=sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f \ + --hash=sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5 \ + --hash=sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346 \ + --hash=sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24 \ + --hash=sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e \ + --hash=sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5 \ + --hash=sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08 \ + --hash=sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793 \ + --hash=sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88 \ + --hash=sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686 \ + --hash=sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b \ + --hash=sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2 \ + --hash=sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28 \ + --hash=sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d \ + --hash=sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5 \ + --hash=sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a \ + --hash=sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a \ + --hash=sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3 \ + --hash=sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf \ + --hash=sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5 \ + --hash=sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef \ + --hash=sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689 \ + --hash=sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c \ + --hash=sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b \ + --hash=sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07 \ + --hash=sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa \ + --hash=sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06 \ + --hash=sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1 \ + --hash=sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff \ + --hash=sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa \ + --hash=sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687 \ + --hash=sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4 \ + --hash=sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb \ + --hash=sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44 \ + --hash=sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c \ + --hash=sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e \ + --hash=sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53 # via # -r requirements.in # alembic -sqlparse==0.4.4 \ - --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \ - --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c +sqlparse==0.5.1 \ + --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ + --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e # via google-cloud-spanner -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f +tomli==2.0.2 \ + --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ + --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed + # via -r requirements.in +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via - # -r requirements.in - # build - # pep517 -typing-extensions==4.8.0 \ - --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ - --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef - # via opentelemetry-sdk -urllib3==1.26.18 \ - --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ - --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 + # alembic + # opentelemetry-sdk + # sqlalchemy +urllib3==2.2.3 \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 # via requests -wheel==0.38.1 \ - --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ - --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 +wheel==0.44.0 \ + --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ + --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 # via pip-tools -wrapt==1.14.1 \ - --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ - --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \ - --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \ - --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \ - --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \ - --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \ - --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \ - --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \ - --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \ - --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \ - --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \ - --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \ - --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \ - --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \ - --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \ - --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \ - --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \ - --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \ - --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \ - --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \ - --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \ - --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \ - --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \ - --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \ - --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \ - --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \ - --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \ - --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \ - --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \ - --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \ - --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \ - --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \ - --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \ - --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \ - --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \ - --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \ - --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \ - --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \ - --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \ - --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \ - --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \ - --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \ - --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \ - --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \ - --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \ - --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \ - --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \ - --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \ - --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \ - --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \ - --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \ - --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \ - --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \ - --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \ - --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \ - --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \ - --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \ - --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \ - --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \ - --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \ - --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \ - --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \ - --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \ - --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af +wrapt==1.16.0 \ + --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ + --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ + --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ + --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ + --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ + --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ + --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ + --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ + --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ + --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ + --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ + --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ + --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ + --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ + --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ + --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ + --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ + --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ + --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ + --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ + --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ + --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ + --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ + --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ + --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ + --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ + --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ + --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ + --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ + --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ + --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ + --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ + --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ + --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ + --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ + --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ + --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ + --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ + --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ + --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ + --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ + --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ + --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ + --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ + --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ + --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ + --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ + --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ + --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ + --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ + --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ + --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ + --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ + --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ + --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ + --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ + --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ + --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ + --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ + --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ + --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ + --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ + --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ + --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ + --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ + --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ + --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ + --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ + --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ + --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 # via # deprecated # opentelemetry-instrumentation -zipp==3.17.0 \ - --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ - --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 - # via - # importlib-metadata - # importlib-resources +zipp==3.20.2 \ + --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ + --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 + # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be # pinned when the requirements file includes hashes and the requirement is not diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 72fa56532f5b..d3d0f8c409ba 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -14,6 +14,8 @@ import io import os +import warnings + import setuptools @@ -59,24 +61,26 @@ if "google.cloud" in packages: namespaces.append("google.cloud") -setuptools.setup( - author="Google LLC", - author_email="cloud-spanner-developers@googlegroups.com", - classifiers=["Intended Audience :: Developers"], - description=description, - long_description=readme, - entry_points={ - "sqlalchemy.dialects": [ - "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" - ] - }, - install_requires=dependencies, - extras_require=extras, - name=name, - namespace_packages=namespaces, - packages=packages, - url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", - version=version, - include_package_data=True, - zip_safe=False, -) +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + setuptools.setup( + author="Google LLC", + author_email="cloud-spanner-developers@googlegroups.com", + classifiers=["Intended Audience :: Developers"], + description=description, + long_description=readme, + entry_points={ + "sqlalchemy.dialects": [ + "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" + ] + }, + install_requires=dependencies, + extras_require=extras, + name=name, + namespace_packages=namespaces, + packages=packages, + url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", + version=version, + include_package_data=True, + zip_safe=False, + ) diff --git a/packages/sqlalchemy-spanner/test/_helpers.py b/packages/sqlalchemy-spanner/test/_helpers.py index 2aae11c7b697..3dd57fd5d77d 100644 --- a/packages/sqlalchemy-spanner/test/_helpers.py +++ b/packages/sqlalchemy-spanner/test/_helpers.py @@ -82,7 +82,7 @@ def setup_class(cls): use_test_ot_exporter() cls.ot_exporter = get_test_ot_exporter() - def teardown(self): + def teardown_method(self): if HAS_OPENTELEMETRY_INSTALLED: self.ot_exporter.clear() diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 8d6d81130f70..cff1a30ddde3 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -80,7 +80,9 @@ from sqlalchemy.testing.suite.test_reflection import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_deprecations import * # noqa: F401, F403 from sqlalchemy.testing.suite.test_results import * # noqa: F401, F403 -from sqlalchemy.testing.suite.test_select import * # noqa: F401, F403 +from sqlalchemy.testing.suite.test_select import ( + BitwiseTest as _BitwiseTest, +) # noqa: F401, F403 from sqlalchemy.testing.suite.test_sequence import ( SequenceTest as _SequenceTest, HasSequenceTest as _HasSequenceTest, @@ -192,6 +194,12 @@ def test_whereclause(self): pass +class BitwiseTest(_BitwiseTest): + @pytest.mark.skip("Causes too many problems with other tests") + def test_bitwise(self, case, expected, connection): + pass + + class ComponentReflectionTestExtra(_ComponentReflectionTestExtra): @testing.requires.table_reflection def test_nullable_reflection(self, connection, metadata): @@ -1018,6 +1026,10 @@ def test_get_multi_columns( tables to be read, and in Spanner all the tables are real, expected results override is required. """ + _ignore_tables = [ + "bitwise", + ] + insp, kws, exp = get_multi_exp( schema, scope, @@ -1030,6 +1042,8 @@ def test_get_multi_columns( for kw in kws: insp.clear_cache() result = insp.get_multi_columns(**kw) + for t in _ignore_tables: + result.pop((schema, t), None) self._check_table_dict(result, exp, self._required_column_keys) @pytest.mark.skip( @@ -1097,6 +1111,7 @@ def test_get_table_names(self, connection, order_by, use_schema): _ignore_tables = [ "account", "alembic_version", + "bitwise", "bytes_table", "comment_test", "date_table", @@ -1306,6 +1321,7 @@ def _test_get_table_names(self, schema=None, table_type="table", order_by=None): expected results override is required. """ _ignore_tables = [ + "bitwise", "comment_test", "noncol_idx_test_pk", "noncol_idx_test_nopk", @@ -1688,7 +1704,7 @@ def test_round_trip(self): connection.execute(date_table.insert(), {"date_data": self.data, "id": 250}) row = connection.execute(select(date_table.c.date_data)).first() - compare = self.compare or self.data + compare = self.compare or self.data.astimezone(timezone.utc) compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") eq_(row[0].rfc3339(), compare) assert isinstance(row[0], DatetimeWithNanoseconds) @@ -1708,7 +1724,7 @@ def test_round_trip_decorated(self, connection): row = connection.execute(select(date_table.c.decorated_date_data)).first() - compare = self.compare or self.data + compare = self.compare or self.data.astimezone(timezone.utc) compare = compare.strftime("%Y-%m-%dT%H:%M:%S.%fZ") eq_(row[0].rfc3339(), compare) assert isinstance(row[0], DatetimeWithNanoseconds) @@ -2105,7 +2121,7 @@ def test_row_w_scalar_select(self, connection): eq_( row.somelabel, - DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0, tzinfo=timezone.utc), + DatetimeWithNanoseconds(2006, 5, 12, 12, 0, 0).astimezone(timezone.utc), ) diff --git a/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py index a8af61c647e9..21ea1bb78bc2 100644 --- a/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/test/unit/test_opentelemetry_tracing.py @@ -33,13 +33,14 @@ def _make_rpc_error(error_cls, trailing_metadata=None): if HAS_OPENTELEMETRY_INSTALLED: class NoTracingTest(OpenTelemetryBase): - def setup(self): + def setup_method(self): self._temp_opentelemetry = sys.modules["opentelemetry"] sys.modules["opentelemetry"] = None importlib.reload(_opentelemetry_tracing) - def teardown(self): + def teardown_method(self): + super(NoTracingTest, self).teardown_method() sys.modules["opentelemetry"] = self._temp_opentelemetry importlib.reload(_opentelemetry_tracing) From ca3169a01df646d590f6c6ef68ea8aaa8831661d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 09:27:35 +0100 Subject: [PATCH 237/582] chore(deps): update dependency requests to v2.32.2 [security] (#412) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3322b956390a..2de75aa841ec 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -531,9 +531,9 @@ readme-renderer==37.2 \ --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ --hash=sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923 # via twine -requests==2.31.0 \ - --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ - --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 +requests==2.32.2 \ + --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ + --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c # via # gcp-releasetool # google-api-core From 29d0b114a0c91fb0025d9cd327e0fa7f25664068 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:46:43 +0100 Subject: [PATCH 238/582] build(deps): bump cryptography from 41.0.5 to 43.0.1 in /.kokoro (#410) Bumps [cryptography](https://github.com/pyca/cryptography) from 41.0.5 to 43.0.1. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/41.0.5...43.0.1) --- updated-dependencies: - dependency-name: cryptography dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../.kokoro/requirements.txt | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 2de75aa841ec..9b7161d8ee2f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -198,30 +198,34 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==41.0.5 \ - --hash=sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf \ - --hash=sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84 \ - --hash=sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e \ - --hash=sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8 \ - --hash=sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7 \ - --hash=sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1 \ - --hash=sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88 \ - --hash=sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86 \ - --hash=sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179 \ - --hash=sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81 \ - --hash=sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20 \ - --hash=sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548 \ - --hash=sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d \ - --hash=sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d \ - --hash=sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5 \ - --hash=sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1 \ - --hash=sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147 \ - --hash=sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936 \ - --hash=sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797 \ - --hash=sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696 \ - --hash=sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72 \ - --hash=sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da \ - --hash=sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723 +cryptography==43.0.1 \ + --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ + --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ + --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ + --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ + --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ + --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ + --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ + --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ + --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ + --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ + --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ + --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ + --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ + --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ + --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ + --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ + --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ + --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ + --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ + --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ + --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ + --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ + --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ + --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ + --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ + --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ + --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 # via # gcp-releasetool # secretstorage @@ -240,11 +244,11 @@ filelock==3.8.0 \ gcp-docuploader==0.6.4 \ --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf - # via -r .kokoro/requirements.in + # via -r requirements.in gcp-releasetool==1.16.0 \ --hash=sha256:27bf19d2e87aaa884096ff941aa3c592c482be3d6a2bfe6f06afafa6af2353e3 \ --hash=sha256:a316b197a543fd036209d0caba7a8eb4d236d8e65381c80cbc6d7efaa7606d63 - # via -r .kokoro/requirements.in + # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e @@ -353,8 +357,7 @@ importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 # via - # -r .kokoro/requirements.in - # keyring + # -r requirements.in # twine jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ @@ -376,7 +379,7 @@ keyring==23.9.3 \ # via # gcp-releasetool # twine -MarkupSafe==2.1.3 \ +markupsafe==2.1.3 \ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ @@ -445,7 +448,7 @@ more-itertools==8.14.0 \ nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c - # via -r .kokoro/requirements.in + # via -r requirements.in packaging==21.3 \ --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 @@ -571,13 +574,11 @@ six==1.16.0 \ twine==4.0.1 \ --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 - # via -r .kokoro/requirements.in + # via -r requirements.in typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef - # via - # -r .kokoro/requirements.in - # rich + # via -r requirements.in urllib3==1.26.18 \ --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 @@ -595,7 +596,7 @@ webencodings==0.5.1 \ wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 - # via -r .kokoro/requirements.in + # via -r requirements.in zipp==3.8.1 \ --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 From addca9539186a078ac011236f4236352549415b1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 10:20:09 +0100 Subject: [PATCH 239/582] chore(deps): update dependency zipp to v3.19.1 [security] (#408) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 9b7161d8ee2f..c689c802a270 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -597,9 +597,9 @@ wheel==0.38.1 \ --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 # via -r requirements.in -zipp==3.8.1 \ - --hash=sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2 \ - --hash=sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009 +zipp==3.19.1 \ + --hash=sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091 \ + --hash=sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be From 6f0f4ccad6f9d83ac2522280613c7522226a12e0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 11:03:33 +0100 Subject: [PATCH 240/582] chore(deps): update dependency certifi to v2024 [security] (#406) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c689c802a270..3e8023f4dc62 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2023.7.22 \ - --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ - --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 +certifi==2024.7.4 \ + --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ + --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ From 6da30d9b7d07a203bd90a1f96ece4265c539bfd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 31 Oct 2024 11:25:51 +0100 Subject: [PATCH 241/582] test: add tests with mock server (#414) * deps: update all deps * chore: update tests * chore: run code formatter * chore: ignore warning * chore: make script work on Python 3.8 * chore: install setuptools * test: add tests with mock server * test: add more tests * fix: use base64 encoding for transaction id * fix: create mock server db config * fix: replace double with single quotes --- .../.github/workflows/test_suite.yml | 15 + .../sqlalchemy-spanner/create_test_config.py | 29 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 25 +- packages/sqlalchemy-spanner/noxfile.py | 24 + .../test/mockserver_tests/__init__.py | 0 .../mockserver_tests/mock_database_admin.py | 38 + .../mockserver_tests/mock_server_test_base.py | 125 ++ .../test/mockserver_tests/mock_spanner.py | 217 +++ .../test/mockserver_tests/quickstart_model.py | 50 + .../spanner_database_admin_pb2_grpc.py | 1269 +++++++++++++++++ .../test/mockserver_tests/spanner_pb2_grpc.py | 884 ++++++++++++ .../test/mockserver_tests/test_basics.py | 129 ++ .../test/mockserver_tests/test_quickstart.py | 125 ++ 13 files changed, 2923 insertions(+), 7 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/__init__.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/mock_database_admin.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/quickstart_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/spanner_database_admin_pb2_grpc.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/spanner_pb2_grpc.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 518325f03f75..d79b89dd163b 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -38,6 +38,21 @@ jobs: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + mockserver: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.12 + - name: Install nox + run: python -m pip install nox + - name: Run mockserver tests + run: nox -s mockserver + compliance_tests_13: runs-on: ubuntu-latest diff --git a/packages/sqlalchemy-spanner/create_test_config.py b/packages/sqlalchemy-spanner/create_test_config.py index 19b46d49bc5b..7ef6f2558535 100644 --- a/packages/sqlalchemy-spanner/create_test_config.py +++ b/packages/sqlalchemy-spanner/create_test_config.py @@ -18,12 +18,19 @@ import sys -def set_test_config(project, instance): +def set_test_config(project, instance, user=None, password=None, host=None, port=None): config = configparser.ConfigParser() - url = ( - f"spanner+spanner:///projects/{project}/instances/{instance}/" - "databases/compliance-test" - ) + if user is not None and password is not None and host is not None and port is not None: + url = ( + f"spanner+spanner://{user}:{password}@{host}:{port}" + f"/projects/{project}/instances/{instance}/" + "databases/compliance-test" + ) + else: + url = ( + f"spanner+spanner:///projects/{project}/instances/{instance}/" + "databases/compliance-test" + ) config.add_section("db") config["db"]["default"] = url @@ -34,7 +41,17 @@ def set_test_config(project, instance): def main(argv): project = argv[0] instance = argv[1] - set_test_config(project, instance) + if len(argv) == 6: + user = argv[2] + password = argv[3] + host = argv[4] + port = argv[5] + else: + user = None + password = None + host = None + port = None + set_test_config(project, instance, user, password, host, port) if __name__ == "__main__": diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 168de44d972d..6754931a3080 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -22,6 +22,9 @@ alter_table, format_type, ) +from google.api_core.client_options import ClientOptions +from google.auth.credentials import AnonymousCredentials +from google.cloud.spanner_v1 import Client from sqlalchemy.exc import NoSuchTableError from sqlalchemy.sql import elements from sqlalchemy import ForeignKeyConstraint, types @@ -709,9 +712,29 @@ def create_connect_args(self, url): url.database, ) dist = pkg_resources.get_distribution("sqlalchemy-spanner") + options = {"user_agent": f"gl-{dist.project_name}/{dist.version}"} + connect_opts = url.translate_connect_args() + if ( + "host" in connect_opts + and "port" in connect_opts + and "password" in connect_opts + ): + # Create a test client that connects to a local Spanner (mock) server. + if ( + connect_opts["host"] == "localhost" + and connect_opts["password"] == "AnonymousCredentials" + ): + client = Client( + project=match.group("project"), + credentials=AnonymousCredentials(), + client_options=ClientOptions( + api_endpoint=f"{connect_opts['host']}:{connect_opts['port']}", + ), + ) + options["client"] = client return ( [match.group("instance"), match.group("database"), match.group("project")], - {"user_agent": f"gl-{dist.project_name}/{dist.version}"}, + options, ) @engine_to_connection diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 80713b166c36..eff6bfc927f6 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -267,6 +267,30 @@ def unit(session): session.run("py.test", "--quiet", os.path.join("test/unit"), *session.posargs) +@nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) +def mockserver(session): + """Run mockserver tests.""" + # Run SQLAlchemy dialect tests using an in-mem mocked Spanner server. + session.install("setuptools") + session.install("pytest") + session.install("mock") + session.install(".") + session.install("sqlalchemy>=2.0") + session.run( + "python", + "create_test_config.py", + "my-project", + "my-instance", + "none", + "AnonymousCredentials", + "localhost", + "9999", + ) + session.run( + "py.test", "--quiet", os.path.join("test/mockserver_tests"), *session.posargs + ) + + @nox.session(python=DEFAULT_PYTHON_VERSION) def migration_test(session): """Test migrations with SQLAlchemy v1.3.11+ and Alembic""" diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/__init__.py b/packages/sqlalchemy-spanner/test/mockserver_tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_database_admin.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_database_admin.py new file mode 100644 index 000000000000..acd739c8de51 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_database_admin.py @@ -0,0 +1,38 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.protobuf import empty_pb2 +import test.mockserver_tests.spanner_database_admin_pb2_grpc as database_admin_grpc +from google.longrunning import operations_pb2 as operations_pb2 + + +# An in-memory mock DatabaseAdmin server that can be used for testing. +class DatabaseAdminServicer(database_admin_grpc.DatabaseAdminServicer): + def __init__(self): + self._requests = [] + + @property + def requests(self): + return self._requests + + def clear_requests(self): + self._requests = [] + + def UpdateDatabaseDdl(self, request, context): + self._requests.append(request) + operation = operations_pb2.Operation() + operation.done = True + operation.name = "projects/test-project/operations/test-operation" + operation.response.Pack(empty_pb2.Empty()) + return operation diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py new file mode 100644 index 000000000000..71e1bf1fa326 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py @@ -0,0 +1,125 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from sqlalchemy import Engine, create_engine +from sqlalchemy.testing.plugin.plugin_base import fixtures +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set +from google.api_core.client_options import ClientOptions +from google.auth.credentials import AnonymousCredentials +from google.cloud.spanner_v1 import ( + Client, + ResultSet, + PingingPool, +) +from google.cloud.spanner_v1.database import Database +from google.cloud.spanner_v1.instance import Instance +import grpc + +# TODO: Replace this with the mock server in the Spanner client lib +from test.mockserver_tests.mock_spanner import SpannerServicer, start_mock_server +from test.mockserver_tests.mock_database_admin import DatabaseAdminServicer + + +def add_result(sql: str, result: ResultSet): + MockServerTestBase.spanner_service.mock_spanner.add_result(sql, result) + + +def add_select1_result(): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="c", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ) + ] + ) + ) + ) + ), + ) + ) + result.rows.extend(["1"]) + MockServerTestBase.spanner_service.mock_spanner.add_result("select 1", result) + + +class MockServerTestBase(fixtures.TestBase): + server: grpc.Server = None + spanner_service: SpannerServicer = None + database_admin_service: DatabaseAdminServicer = None + port: int = None + + @classmethod + def setup_class(cls): + ( + MockServerTestBase.server, + MockServerTestBase.spanner_service, + MockServerTestBase.database_admin_service, + MockServerTestBase.port, + ) = start_mock_server() + + @classmethod + def teardown_class(cls): + if MockServerTestBase.server is not None: + MockServerTestBase.server.stop(grace=None) + MockServerTestBase.server = None + + def setup_method(self): + self._client = None + self._instance = None + self._database = None + + def teardown_method(self): + MockServerTestBase.spanner_service.clear_requests() + MockServerTestBase.database_admin_service.clear_requests() + + def create_engine(self) -> Engine: + return create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": PingingPool(size=10)}, + ) + + @property + def client(self) -> Client: + if self._client is None: + self._client = Client( + project="p", + credentials=AnonymousCredentials(), + client_options=ClientOptions( + api_endpoint="localhost:" + str(MockServerTestBase.port), + ), + ) + return self._client + + @property + def instance(self) -> Instance: + if self._instance is None: + self._instance = self.client.instance("test-instance") + return self._instance + + @property + def database(self) -> Database: + if self._database is None: + self._database = self.instance.database( + "test-database", pool=PingingPool(size=10) + ) + return self._database diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py new file mode 100644 index 000000000000..db1891448ade --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py @@ -0,0 +1,217 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud.spanner_v1 import TransactionOptions, ResultSetMetadata +from google.protobuf import empty_pb2 +import test.mockserver_tests.spanner_pb2_grpc as spanner_grpc +import test.mockserver_tests.spanner_database_admin_pb2_grpc as database_admin_grpc +from test.mockserver_tests.mock_database_admin import DatabaseAdminServicer +import google.cloud.spanner_v1.types.result_set as result_set +import google.cloud.spanner_v1.types.transaction as transaction +import google.cloud.spanner_v1.types.commit_response as commit +import google.cloud.spanner_v1.types.spanner as spanner +from concurrent import futures +import grpc +import base64 + + +class MockSpanner: + def __init__(self): + self.results = {} + + def add_result(self, sql: str, result: result_set.ResultSet): + self.results[sql.lower().strip()] = result + + def get_result(self, sql: str) -> result_set.ResultSet: + result = self.results.get(sql.lower().strip()) + if result is None: + raise ValueError(f"No result found for {sql}") + return result + + def get_result_as_partial_result_sets( + self, sql: str + ) -> [result_set.PartialResultSet]: + result: result_set.ResultSet = self.get_result(sql) + partials = [] + first = True + if len(result.rows) == 0: + partial = result_set.PartialResultSet() + partial.metadata = result.metadata + partials.append(partial) + else: + for row in result.rows: + partial = result_set.PartialResultSet() + if first: + partial.metadata = result.metadata + partial.values.extend(row) + partials.append(partial) + partials[len(partials) - 1].stats = result.stats + return partials + + +# An in-memory mock Spanner server that can be used for testing. +class SpannerServicer(spanner_grpc.SpannerServicer): + def __init__(self): + self._requests = [] + self.session_counter = 0 + self.sessions = {} + self.transaction_counter = 0 + self.transactions = {} + self._mock_spanner = MockSpanner() + + @property + def mock_spanner(self): + return self._mock_spanner + + @property + def requests(self): + return self._requests + + def clear_requests(self): + self._requests = [] + + def CreateSession(self, request, context): + self._requests.append(request) + return self.__create_session(request.database, request.session) + + def BatchCreateSessions(self, request, context): + self._requests.append(request) + sessions = [] + for i in range(request.session_count): + sessions.append( + self.__create_session(request.database, request.session_template) + ) + return spanner.BatchCreateSessionsResponse(dict(session=sessions)) + + def __create_session(self, database: str, session_template: spanner.Session): + self.session_counter += 1 + session = spanner.Session() + session.name = database + "/sessions/" + str(self.session_counter) + session.multiplexed = session_template.multiplexed + session.labels.MergeFrom(session_template.labels) + session.creator_role = session_template.creator_role + self.sessions[session.name] = session + return session + + def GetSession(self, request, context): + self._requests.append(request) + return spanner.Session() + + def ListSessions(self, request, context): + self._requests.append(request) + return [spanner.Session()] + + def DeleteSession(self, request, context): + self._requests.append(request) + return empty_pb2.Empty() + + def ExecuteSql(self, request, context): + self._requests.append(request) + return result_set.ResultSet() + + def ExecuteStreamingSql(self, request, context): + self._requests.append(request) + partials = self.mock_spanner.get_result_as_partial_result_sets(request.sql) + for result in partials: + yield result + + def ExecuteBatchDml(self, request, context): + self._requests.append(request) + response = spanner.ExecuteBatchDmlResponse() + started_transaction = None + if not request.transaction.begin == TransactionOptions(): + started_transaction = self.__create_transaction( + request.session, request.transaction.begin + ) + first = True + for statement in request.statements: + result = self.mock_spanner.get_result(statement.sql) + if first and started_transaction is not None: + result = result_set.ResultSet( + self.mock_spanner.get_result(statement.sql) + ) + result.metadata = ResultSetMetadata(result.metadata) + result.metadata.transaction = started_transaction + response.result_sets.append(result) + return response + + def Read(self, request, context): + self._requests.append(request) + return result_set.ResultSet() + + def StreamingRead(self, request, context): + self._requests.append(request) + for result in [result_set.PartialResultSet(), result_set.PartialResultSet()]: + yield result + + def BeginTransaction(self, request, context): + self._requests.append(request) + return self.__create_transaction(request.session, request.options) + + def __create_transaction( + self, session: str, options: TransactionOptions + ) -> transaction.Transaction: + session = self.sessions[session] + if session is None: + raise ValueError(f"Session not found: {session}") + self.transaction_counter += 1 + id_bytes = bytes( + f"{session.name}/transactions/{self.transaction_counter}", "UTF-8" + ) + transaction_id = base64.urlsafe_b64encode(id_bytes) + self.transactions[transaction_id] = options + return transaction.Transaction(dict(id=transaction_id)) + + def Commit(self, request, context): + self._requests.append(request) + tx = self.transactions[request.transaction_id] + if tx is None: + raise ValueError(f"Transaction not found: {request.transaction_id}") + del self.transactions[request.transaction_id] + return commit.CommitResponse() + + def Rollback(self, request, context): + self._requests.append(request) + return empty_pb2.Empty() + + def PartitionQuery(self, request, context): + self._requests.append(request) + return spanner.PartitionResponse() + + def PartitionRead(self, request, context): + self._requests.append(request) + return spanner.PartitionResponse() + + def BatchWrite(self, request, context): + self._requests.append(request) + for result in [spanner.BatchWriteResponse(), spanner.BatchWriteResponse()]: + yield result + + +def start_mock_server() -> (grpc.Server, SpannerServicer, DatabaseAdminServicer, int): + # Create a gRPC server. + spanner_server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + + # Add the Spanner services to the gRPC server. + spanner_servicer = SpannerServicer() + spanner_grpc.add_SpannerServicer_to_server(spanner_servicer, spanner_server) + database_admin_servicer = DatabaseAdminServicer() + database_admin_grpc.add_DatabaseAdminServicer_to_server( + database_admin_servicer, spanner_server + ) + + # Start the server on a random port. + port = spanner_server.add_insecure_port("[::]:0") + spanner_server.start() + return spanner_server, spanner_servicer, database_admin_servicer, port diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/quickstart_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/quickstart_model.py new file mode 100644 index 000000000000..ccfa22d7a44c --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/quickstart_model.py @@ -0,0 +1,50 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import List +from typing import Optional +from sqlalchemy import ForeignKey +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column +from sqlalchemy.orm import relationship + + +class Base(DeclarativeBase): + pass + + +class User(Base): + __tablename__ = "user_account" + id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(30)) + fullname: Mapped[Optional[str]] + addresses: Mapped[List["Address"]] = relationship( + back_populates="user", cascade="all, delete-orphan" + ) + + def __repr__(self) -> str: + return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})" + + +class Address(Base): + __tablename__ = "address" + id: Mapped[int] = mapped_column(primary_key=True) + email_address: Mapped[str] + user_id: Mapped[int] = mapped_column(ForeignKey("user_account.id")) + user: Mapped["User"] = relationship(back_populates="addresses") + + def __repr__(self) -> str: + return f"Address(id={self.id!r}, email_address={self.email_address!r})" diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_database_admin_pb2_grpc.py b/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_database_admin_pb2_grpc.py new file mode 100644 index 000000000000..6798f8d90ebb --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_database_admin_pb2_grpc.py @@ -0,0 +1,1269 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! + + +# Generated with the following commands: +# +# pip install grpcio-tools +# git clone git@github.com:googleapis/googleapis.git +# cd googleapis +# python -m grpc_tools.protoc \ +# -I . \ +# --python_out=. --pyi_out=. --grpc_python_out=. \ +# ./google/spanner/admin/database/v1/*.proto + +# flake8: noqa + +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from google.iam.v1 import iam_policy_pb2 as google_dot_iam_dot_v1_dot_iam__policy__pb2 +from google.iam.v1 import policy_pb2 as google_dot_iam_dot_v1_dot_policy__pb2 +from google.longrunning import ( + operations_pb2 as google_dot_longrunning_dot_operations__pb2, +) +from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 +from google.cloud.spanner_admin_database_v1.types import ( + backup as google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2, +) +from google.cloud.spanner_admin_database_v1.types import ( + backup_schedule as google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2, +) +from google.cloud.spanner_admin_database_v1.types import ( + spanner_database_admin as google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2, +) + +GRPC_GENERATED_VERSION = "1.67.0" +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + + _version_not_supported = first_version_is_lower( + GRPC_VERSION, GRPC_GENERATED_VERSION + ) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f"The grpc package installed is at version {GRPC_VERSION}," + + f" but the generated code in google/spanner/admin/database/v1/spanner_database_admin_pb2_grpc.py depends on" + + f" grpcio>={GRPC_GENERATED_VERSION}." + + f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}" + + f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}." + ) + + +class DatabaseAdminServicer(object): + """Cloud Spanner Database Admin API + + The Cloud Spanner Database Admin API can be used to: + * create, drop, and list databases + * update the schema of pre-existing databases + * create, delete, copy and list backups for a database + * restore a database from an existing backup + """ + + def ListDatabases(self, request, context): + """Lists Cloud Spanner databases.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CreateDatabase(self, request, context): + """Creates a new Cloud Spanner database and starts to prepare it for serving. + The returned [long-running operation][google.longrunning.Operation] will + have a name of the format `/operations/` and + can be used to track preparation of the database. The + [metadata][google.longrunning.Operation.metadata] field type is + [CreateDatabaseMetadata][google.spanner.admin.database.v1.CreateDatabaseMetadata]. + The [response][google.longrunning.Operation.response] field type is + [Database][google.spanner.admin.database.v1.Database], if successful. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetDatabase(self, request, context): + """Gets the state of a Cloud Spanner database.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def UpdateDatabase(self, request, context): + """Updates a Cloud Spanner database. The returned + [long-running operation][google.longrunning.Operation] can be used to track + the progress of updating the database. If the named database does not + exist, returns `NOT_FOUND`. + + While the operation is pending: + + * The database's + [reconciling][google.spanner.admin.database.v1.Database.reconciling] + field is set to true. + * Cancelling the operation is best-effort. If the cancellation succeeds, + the operation metadata's + [cancel_time][google.spanner.admin.database.v1.UpdateDatabaseMetadata.cancel_time] + is set, the updates are reverted, and the operation terminates with a + `CANCELLED` status. + * New UpdateDatabase requests will return a `FAILED_PRECONDITION` error + until the pending operation is done (returns successfully or with + error). + * Reading the database via the API continues to give the pre-request + values. + + Upon completion of the returned operation: + + * The new values are in effect and readable via the API. + * The database's + [reconciling][google.spanner.admin.database.v1.Database.reconciling] + field becomes false. + + The returned [long-running operation][google.longrunning.Operation] will + have a name of the format + `projects//instances//databases//operations/` + and can be used to track the database modification. The + [metadata][google.longrunning.Operation.metadata] field type is + [UpdateDatabaseMetadata][google.spanner.admin.database.v1.UpdateDatabaseMetadata]. + The [response][google.longrunning.Operation.response] field type is + [Database][google.spanner.admin.database.v1.Database], if successful. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def UpdateDatabaseDdl(self, request, context): + """Updates the schema of a Cloud Spanner database by + creating/altering/dropping tables, columns, indexes, etc. The returned + [long-running operation][google.longrunning.Operation] will have a name of + the format `/operations/` and can be used to + track execution of the schema change(s). The + [metadata][google.longrunning.Operation.metadata] field type is + [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata]. + The operation has no response. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def DropDatabase(self, request, context): + """Drops (aka deletes) a Cloud Spanner database. + Completed backups for the database will be retained according to their + `expire_time`. + Note: Cloud Spanner might continue to accept requests for a few seconds + after the database has been deleted. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetDatabaseDdl(self, request, context): + """Returns the schema of a Cloud Spanner database as a list of formatted + DDL statements. This method does not show pending schema updates, those may + be queried using the [Operations][google.longrunning.Operations] API. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def SetIamPolicy(self, request, context): + """Sets the access control policy on a database or backup resource. + Replaces any existing policy. + + Authorization requires `spanner.databases.setIamPolicy` + permission on [resource][google.iam.v1.SetIamPolicyRequest.resource]. + For backups, authorization requires `spanner.backups.setIamPolicy` + permission on [resource][google.iam.v1.SetIamPolicyRequest.resource]. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetIamPolicy(self, request, context): + """Gets the access control policy for a database or backup resource. + Returns an empty policy if a database or backup exists but does not have a + policy set. + + Authorization requires `spanner.databases.getIamPolicy` permission on + [resource][google.iam.v1.GetIamPolicyRequest.resource]. + For backups, authorization requires `spanner.backups.getIamPolicy` + permission on [resource][google.iam.v1.GetIamPolicyRequest.resource]. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def TestIamPermissions(self, request, context): + """Returns permissions that the caller has on the specified database or backup + resource. + + Attempting this RPC on a non-existent Cloud Spanner database will + result in a NOT_FOUND error if the user has + `spanner.databases.list` permission on the containing Cloud + Spanner instance. Otherwise returns an empty set of permissions. + Calling this method on a backup that does not exist will + result in a NOT_FOUND error if the user has + `spanner.backups.list` permission on the containing instance. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CreateBackup(self, request, context): + """Starts creating a new Cloud Spanner Backup. + The returned backup [long-running operation][google.longrunning.Operation] + will have a name of the format + `projects//instances//backups//operations/` + and can be used to track creation of the backup. The + [metadata][google.longrunning.Operation.metadata] field type is + [CreateBackupMetadata][google.spanner.admin.database.v1.CreateBackupMetadata]. + The [response][google.longrunning.Operation.response] field type is + [Backup][google.spanner.admin.database.v1.Backup], if successful. + Cancelling the returned operation will stop the creation and delete the + backup. There can be only one pending backup creation per database. Backup + creation of different databases can run concurrently. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CopyBackup(self, request, context): + """Starts copying a Cloud Spanner Backup. + The returned backup [long-running operation][google.longrunning.Operation] + will have a name of the format + `projects//instances//backups//operations/` + and can be used to track copying of the backup. The operation is associated + with the destination backup. + The [metadata][google.longrunning.Operation.metadata] field type is + [CopyBackupMetadata][google.spanner.admin.database.v1.CopyBackupMetadata]. + The [response][google.longrunning.Operation.response] field type is + [Backup][google.spanner.admin.database.v1.Backup], if successful. + Cancelling the returned operation will stop the copying and delete the + destination backup. Concurrent CopyBackup requests can run on the same + source backup. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetBackup(self, request, context): + """Gets metadata on a pending or completed + [Backup][google.spanner.admin.database.v1.Backup]. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def UpdateBackup(self, request, context): + """Updates a pending or completed + [Backup][google.spanner.admin.database.v1.Backup]. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def DeleteBackup(self, request, context): + """Deletes a pending or completed + [Backup][google.spanner.admin.database.v1.Backup]. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListBackups(self, request, context): + """Lists completed and pending backups. + Backups returned are ordered by `create_time` in descending order, + starting from the most recent `create_time`. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def RestoreDatabase(self, request, context): + """Create a new database by restoring from a completed backup. The new + database must be in the same project and in an instance with the same + instance configuration as the instance containing + the backup. The returned database [long-running + operation][google.longrunning.Operation] has a name of the format + `projects//instances//databases//operations/`, + and can be used to track the progress of the operation, and to cancel it. + The [metadata][google.longrunning.Operation.metadata] field type is + [RestoreDatabaseMetadata][google.spanner.admin.database.v1.RestoreDatabaseMetadata]. + The [response][google.longrunning.Operation.response] type + is [Database][google.spanner.admin.database.v1.Database], if + successful. Cancelling the returned operation will stop the restore and + delete the database. + There can be only one database being restored into an instance at a time. + Once the restore operation completes, a new restore operation can be + initiated, without waiting for the optimize operation associated with the + first restore to complete. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListDatabaseOperations(self, request, context): + """Lists database [longrunning-operations][google.longrunning.Operation]. + A database operation has a name of the form + `projects//instances//databases//operations/`. + The long-running operation + [metadata][google.longrunning.Operation.metadata] field type + `metadata.type_url` describes the type of the metadata. Operations returned + include those that have completed/failed/canceled within the last 7 days, + and pending operations. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListBackupOperations(self, request, context): + """Lists the backup [long-running operations][google.longrunning.Operation] in + the given instance. A backup operation has a name of the form + `projects//instances//backups//operations/`. + The long-running operation + [metadata][google.longrunning.Operation.metadata] field type + `metadata.type_url` describes the type of the metadata. Operations returned + include those that have completed/failed/canceled within the last 7 days, + and pending operations. Operations returned are ordered by + `operation.metadata.value.progress.start_time` in descending order starting + from the most recently started operation. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListDatabaseRoles(self, request, context): + """Lists Cloud Spanner database roles.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def CreateBackupSchedule(self, request, context): + """Creates a new backup schedule.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetBackupSchedule(self, request, context): + """Gets backup schedule for the input schedule name.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def UpdateBackupSchedule(self, request, context): + """Updates a backup schedule.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def DeleteBackupSchedule(self, request, context): + """Deletes a backup schedule.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListBackupSchedules(self, request, context): + """Lists all the backup schedules for the database.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_DatabaseAdminServicer_to_server(servicer, server): + rpc_method_handlers = { + "ListDatabases": grpc.unary_unary_rpc_method_handler( + servicer.ListDatabases, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabasesRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabasesResponse.serialize, + ), + "CreateDatabase": grpc.unary_unary_rpc_method_handler( + servicer.CreateDatabase, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.CreateDatabaseRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "GetDatabase": grpc.unary_unary_rpc_method_handler( + servicer.GetDatabase, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.Database.serialize, + ), + "UpdateDatabase": grpc.unary_unary_rpc_method_handler( + servicer.UpdateDatabase, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.UpdateDatabaseRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "UpdateDatabaseDdl": grpc.unary_unary_rpc_method_handler( + servicer.UpdateDatabaseDdl, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.UpdateDatabaseDdlRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "DropDatabase": grpc.unary_unary_rpc_method_handler( + servicer.DropDatabase, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.DropDatabaseRequest.deserialize, + response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, + ), + "GetDatabaseDdl": grpc.unary_unary_rpc_method_handler( + servicer.GetDatabaseDdl, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseDdlRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseDdlResponse.serialize, + ), + "SetIamPolicy": grpc.unary_unary_rpc_method_handler( + servicer.SetIamPolicy, + request_deserializer=google_dot_iam_dot_v1_dot_iam__policy__pb2.SetIamPolicyRequest.FromString, + response_serializer=google_dot_iam_dot_v1_dot_policy__pb2.Policy.SerializeToString, + ), + "GetIamPolicy": grpc.unary_unary_rpc_method_handler( + servicer.GetIamPolicy, + request_deserializer=google_dot_iam_dot_v1_dot_iam__policy__pb2.GetIamPolicyRequest.FromString, + response_serializer=google_dot_iam_dot_v1_dot_policy__pb2.Policy.SerializeToString, + ), + "TestIamPermissions": grpc.unary_unary_rpc_method_handler( + servicer.TestIamPermissions, + request_deserializer=google_dot_iam_dot_v1_dot_iam__policy__pb2.TestIamPermissionsRequest.FromString, + response_serializer=google_dot_iam_dot_v1_dot_iam__policy__pb2.TestIamPermissionsResponse.SerializeToString, + ), + "CreateBackup": grpc.unary_unary_rpc_method_handler( + servicer.CreateBackup, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.CreateBackupRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "CopyBackup": grpc.unary_unary_rpc_method_handler( + servicer.CopyBackup, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.CopyBackupRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "GetBackup": grpc.unary_unary_rpc_method_handler( + servicer.GetBackup, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.GetBackupRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.Backup.serialize, + ), + "UpdateBackup": grpc.unary_unary_rpc_method_handler( + servicer.UpdateBackup, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.UpdateBackupRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.Backup.serialize, + ), + "DeleteBackup": grpc.unary_unary_rpc_method_handler( + servicer.DeleteBackup, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.DeleteBackupRequest.deserialize, + response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, + ), + "ListBackups": grpc.unary_unary_rpc_method_handler( + servicer.ListBackups, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupsRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupsResponse.serialize, + ), + "RestoreDatabase": grpc.unary_unary_rpc_method_handler( + servicer.RestoreDatabase, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.RestoreDatabaseRequest.deserialize, + response_serializer=google_dot_longrunning_dot_operations__pb2.Operation.SerializeToString, + ), + "ListDatabaseOperations": grpc.unary_unary_rpc_method_handler( + servicer.ListDatabaseOperations, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseOperationsRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseOperationsResponse.serialize, + ), + "ListBackupOperations": grpc.unary_unary_rpc_method_handler( + servicer.ListBackupOperations, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupOperationsRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupOperationsResponse.serialize, + ), + "ListDatabaseRoles": grpc.unary_unary_rpc_method_handler( + servicer.ListDatabaseRoles, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseRolesRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseRolesResponse.serialize, + ), + "CreateBackupSchedule": grpc.unary_unary_rpc_method_handler( + servicer.CreateBackupSchedule, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.CreateBackupScheduleRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.serialize, + ), + "GetBackupSchedule": grpc.unary_unary_rpc_method_handler( + servicer.GetBackupSchedule, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.GetBackupScheduleRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.serialize, + ), + "UpdateBackupSchedule": grpc.unary_unary_rpc_method_handler( + servicer.UpdateBackupSchedule, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.UpdateBackupScheduleRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.serialize, + ), + "DeleteBackupSchedule": grpc.unary_unary_rpc_method_handler( + servicer.DeleteBackupSchedule, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.DeleteBackupScheduleRequest.deserialize, + response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, + ), + "ListBackupSchedules": grpc.unary_unary_rpc_method_handler( + servicer.ListBackupSchedules, + request_deserializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.ListBackupSchedulesRequest.deserialize, + response_serializer=google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.ListBackupSchedulesResponse.serialize, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "google.spanner.admin.database.v1.DatabaseAdmin", rpc_method_handlers + ) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers( + "google.spanner.admin.database.v1.DatabaseAdmin", rpc_method_handlers + ) + + +# This class is part of an EXPERIMENTAL API. +class DatabaseAdmin(object): + """Cloud Spanner Database Admin API + + The Cloud Spanner Database Admin API can be used to: + * create, drop, and list databases + * update the schema of pre-existing databases + * create, delete, copy and list backups for a database + * restore a database from an existing backup + """ + + @staticmethod + def ListDatabases( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabases", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabasesRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabasesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def CreateDatabase( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/CreateDatabase", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.CreateDatabaseRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetDatabase( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/GetDatabase", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.Database.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def UpdateDatabase( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateDatabase", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.UpdateDatabaseRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def UpdateDatabaseDdl( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateDatabaseDdl", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.UpdateDatabaseDdlRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def DropDatabase( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/DropDatabase", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.DropDatabaseRequest.SerializeToString, + google_dot_protobuf_dot_empty__pb2.Empty.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetDatabaseDdl( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/GetDatabaseDdl", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseDdlRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.GetDatabaseDdlResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def SetIamPolicy( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/SetIamPolicy", + google_dot_iam_dot_v1_dot_iam__policy__pb2.SetIamPolicyRequest.SerializeToString, + google_dot_iam_dot_v1_dot_policy__pb2.Policy.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetIamPolicy( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/GetIamPolicy", + google_dot_iam_dot_v1_dot_iam__policy__pb2.GetIamPolicyRequest.SerializeToString, + google_dot_iam_dot_v1_dot_policy__pb2.Policy.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def TestIamPermissions( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/TestIamPermissions", + google_dot_iam_dot_v1_dot_iam__policy__pb2.TestIamPermissionsRequest.SerializeToString, + google_dot_iam_dot_v1_dot_iam__policy__pb2.TestIamPermissionsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def CreateBackup( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/CreateBackup", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.CreateBackupRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def CopyBackup( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/CopyBackup", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.CopyBackupRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetBackup( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/GetBackup", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.GetBackupRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.Backup.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def UpdateBackup( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateBackup", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.UpdateBackupRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.Backup.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def DeleteBackup( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/DeleteBackup", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.DeleteBackupRequest.SerializeToString, + google_dot_protobuf_dot_empty__pb2.Empty.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListBackups( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackups", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupsRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def RestoreDatabase( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/RestoreDatabase", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.RestoreDatabaseRequest.SerializeToString, + google_dot_longrunning_dot_operations__pb2.Operation.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListDatabaseOperations( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabaseOperations", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseOperationsRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseOperationsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListBackupOperations( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackupOperations", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupOperationsRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__pb2.ListBackupOperationsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListDatabaseRoles( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListDatabaseRoles", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseRolesRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_spanner__database__admin__pb2.ListDatabaseRolesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def CreateBackupSchedule( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/CreateBackupSchedule", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.CreateBackupScheduleRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetBackupSchedule( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/GetBackupSchedule", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.GetBackupScheduleRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def UpdateBackupSchedule( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/UpdateBackupSchedule", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.UpdateBackupScheduleRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.BackupSchedule.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def DeleteBackupSchedule( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/DeleteBackupSchedule", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.DeleteBackupScheduleRequest.SerializeToString, + google_dot_protobuf_dot_empty__pb2.Empty.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListBackupSchedules( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.admin.database.v1.DatabaseAdmin/ListBackupSchedules", + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.ListBackupSchedulesRequest.SerializeToString, + google_dot_spanner_dot_admin_dot_database_dot_v1_dot_backup__schedule__pb2.ListBackupSchedulesResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_pb2_grpc.py b/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_pb2_grpc.py new file mode 100644 index 000000000000..da86ba18a3cc --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/spanner_pb2_grpc.py @@ -0,0 +1,884 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! + +# Generated with the following commands: +# +# pip install grpcio-tools +# git clone git@github.com:googleapis/googleapis.git +# cd googleapis +# python -m grpc_tools.protoc \ +# -I . \ +# --python_out=. --pyi_out=. --grpc_python_out=. \ +# ./google/spanner/v1/*.proto + +# flake8: noqa + +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 +from google.cloud.spanner_v1.types import ( + commit_response as google_dot_spanner_dot_v1_dot_commit__response__pb2, +) +from google.cloud.spanner_v1.types import ( + result_set as google_dot_spanner_dot_v1_dot_result__set__pb2, +) +from google.cloud.spanner_v1.types import ( + spanner as google_dot_spanner_dot_v1_dot_spanner__pb2, +) +from google.cloud.spanner_v1.types import ( + transaction as google_dot_spanner_dot_v1_dot_transaction__pb2, +) + +GRPC_GENERATED_VERSION = "1.67.0" +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + + _version_not_supported = first_version_is_lower( + GRPC_VERSION, GRPC_GENERATED_VERSION + ) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f"The grpc package installed is at version {GRPC_VERSION}," + + f" but the generated code in google/spanner/v1/spanner_pb2_grpc.py depends on" + + f" grpcio>={GRPC_GENERATED_VERSION}." + + f" Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}" + + f" or downgrade your generated code using grpcio-tools<={GRPC_VERSION}." + ) + + +class SpannerServicer(object): + """Cloud Spanner API + + The Cloud Spanner API can be used to manage sessions and execute + transactions on data stored in Cloud Spanner databases. + """ + + def CreateSession(self, request, context): + """Creates a new session. A session can be used to perform + transactions that read and/or modify data in a Cloud Spanner database. + Sessions are meant to be reused for many consecutive + transactions. + + Sessions can only execute one transaction at a time. To execute + multiple concurrent read-write/write-only transactions, create + multiple sessions. Note that standalone reads and queries use a + transaction internally, and count toward the one transaction + limit. + + Active sessions use additional server resources, so it is a good idea to + delete idle and unneeded sessions. + Aside from explicit deletes, Cloud Spanner may delete sessions for which no + operations are sent for more than an hour. If a session is deleted, + requests to it return `NOT_FOUND`. + + Idle sessions can be kept alive by sending a trivial SQL query + periodically, e.g., `"SELECT 1"`. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def BatchCreateSessions(self, request, context): + """Creates multiple new sessions. + + This API can be used to initialize a session cache on the clients. + See https://goo.gl/TgSFN2 for best practices on session cache management. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetSession(self, request, context): + """Gets a session. Returns `NOT_FOUND` if the session does not exist. + This is mainly useful for determining whether a session is still + alive. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ListSessions(self, request, context): + """Lists all sessions in a given database.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def DeleteSession(self, request, context): + """Ends a session, releasing server resources associated with it. This will + asynchronously trigger cancellation of any operations that are running with + this session. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ExecuteSql(self, request, context): + """Executes an SQL statement, returning all results in a single reply. This + method cannot be used to return a result set larger than 10 MiB; + if the query yields more data than that, the query fails with + a `FAILED_PRECONDITION` error. + + Operations inside read-write transactions might return `ABORTED`. If + this occurs, the application should restart the transaction from + the beginning. See [Transaction][google.spanner.v1.Transaction] for more + details. + + Larger result sets can be fetched in streaming fashion by calling + [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql] + instead. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ExecuteStreamingSql(self, request, context): + """Like [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql], except returns the + result set as a stream. Unlike + [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql], there is no limit on + the size of the returned result set. However, no individual row in the + result set can exceed 100 MiB, and no column value can exceed 10 MiB. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def ExecuteBatchDml(self, request, context): + """Executes a batch of SQL DML statements. This method allows many statements + to be run with lower latency than submitting them sequentially with + [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql]. + + Statements are executed in sequential order. A request can succeed even if + a statement fails. The + [ExecuteBatchDmlResponse.status][google.spanner.v1.ExecuteBatchDmlResponse.status] + field in the response provides information about the statement that failed. + Clients must inspect this field to determine whether an error occurred. + + Execution stops after the first failed statement; the remaining statements + are not executed. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def Read(self, request, context): + """Reads rows from the database using key lookups and scans, as a + simple key/value style alternative to + [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql]. This method cannot be + used to return a result set larger than 10 MiB; if the read matches more + data than that, the read fails with a `FAILED_PRECONDITION` + error. + + Reads inside read-write transactions might return `ABORTED`. If + this occurs, the application should restart the transaction from + the beginning. See [Transaction][google.spanner.v1.Transaction] for more + details. + + Larger result sets can be yielded in streaming fashion by calling + [StreamingRead][google.spanner.v1.Spanner.StreamingRead] instead. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def StreamingRead(self, request, context): + """Like [Read][google.spanner.v1.Spanner.Read], except returns the result set + as a stream. Unlike [Read][google.spanner.v1.Spanner.Read], there is no + limit on the size of the returned result set. However, no individual row in + the result set can exceed 100 MiB, and no column value can exceed + 10 MiB. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def BeginTransaction(self, request, context): + """Begins a new transaction. This step can often be skipped: + [Read][google.spanner.v1.Spanner.Read], + [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql] and + [Commit][google.spanner.v1.Spanner.Commit] can begin a new transaction as a + side-effect. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def Commit(self, request, context): + """Commits a transaction. The request includes the mutations to be + applied to rows in the database. + + `Commit` might return an `ABORTED` error. This can occur at any time; + commonly, the cause is conflicts with concurrent + transactions. However, it can also happen for a variety of other + reasons. If `Commit` returns `ABORTED`, the caller should re-attempt + the transaction from the beginning, re-using the same session. + + On very rare occasions, `Commit` might return `UNKNOWN`. This can happen, + for example, if the client job experiences a 1+ hour networking failure. + At that point, Cloud Spanner has lost track of the transaction outcome and + we recommend that you perform another read from the database to see the + state of things as they are now. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def Rollback(self, request, context): + """Rolls back a transaction, releasing any locks it holds. It is a good + idea to call this for any transaction that includes one or more + [Read][google.spanner.v1.Spanner.Read] or + [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql] requests and ultimately + decides not to commit. + + `Rollback` returns `OK` if it successfully aborts the transaction, the + transaction was already aborted, or the transaction is not + found. `Rollback` never returns `ABORTED`. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def PartitionQuery(self, request, context): + """Creates a set of partition tokens that can be used to execute a query + operation in parallel. Each of the returned partition tokens can be used + by [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql] to + specify a subset of the query result to read. The same session and + read-only transaction must be used by the PartitionQueryRequest used to + create the partition tokens and the ExecuteSqlRequests that use the + partition tokens. + + Partition tokens become invalid when the session used to create them + is deleted, is idle for too long, begins a new transaction, or becomes too + old. When any of these happen, it is not possible to resume the query, and + the whole operation must be restarted from the beginning. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def PartitionRead(self, request, context): + """Creates a set of partition tokens that can be used to execute a read + operation in parallel. Each of the returned partition tokens can be used + by [StreamingRead][google.spanner.v1.Spanner.StreamingRead] to specify a + subset of the read result to read. The same session and read-only + transaction must be used by the PartitionReadRequest used to create the + partition tokens and the ReadRequests that use the partition tokens. There + are no ordering guarantees on rows returned among the returned partition + tokens, or even within each individual StreamingRead call issued with a + partition_token. + + Partition tokens become invalid when the session used to create them + is deleted, is idle for too long, begins a new transaction, or becomes too + old. When any of these happen, it is not possible to resume the read, and + the whole operation must be restarted from the beginning. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def BatchWrite(self, request, context): + """Batches the supplied mutation groups in a collection of efficient + transactions. All mutations in a group are committed atomically. However, + mutations across groups can be committed non-atomically in an unspecified + order and thus, they must be independent of each other. Partial failure is + possible, i.e., some groups may have been committed successfully, while + some may have failed. The results of individual batches are streamed into + the response as the batches are applied. + + BatchWrite requests are not replay protected, meaning that each mutation + group may be applied more than once. Replays of non-idempotent mutations + may have undesirable effects. For example, replays of an insert mutation + may produce an already exists error or if you use generated or commit + timestamp-based keys, it may result in additional rows being added to the + mutation's table. We recommend structuring your mutation groups to be + idempotent to avoid this issue. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_SpannerServicer_to_server(servicer, server): + rpc_method_handlers = { + "CreateSession": grpc.unary_unary_rpc_method_handler( + servicer.CreateSession, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.CreateSessionRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.Session.serialize, + ), + "BatchCreateSessions": grpc.unary_unary_rpc_method_handler( + servicer.BatchCreateSessions, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.BatchCreateSessionsRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.BatchCreateSessionsResponse.serialize, + ), + "GetSession": grpc.unary_unary_rpc_method_handler( + servicer.GetSession, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.GetSessionRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.Session.serialize, + ), + "ListSessions": grpc.unary_unary_rpc_method_handler( + servicer.ListSessions, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ListSessionsRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ListSessionsResponse.serialize, + ), + "DeleteSession": grpc.unary_unary_rpc_method_handler( + servicer.DeleteSession, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.DeleteSessionRequest.deserialize, + response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, + ), + "ExecuteSql": grpc.unary_unary_rpc_method_handler( + servicer.ExecuteSql, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteSqlRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_result__set__pb2.ResultSet.serialize, + ), + "ExecuteStreamingSql": grpc.unary_stream_rpc_method_handler( + servicer.ExecuteStreamingSql, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteSqlRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_result__set__pb2.PartialResultSet.serialize, + ), + "ExecuteBatchDml": grpc.unary_unary_rpc_method_handler( + servicer.ExecuteBatchDml, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteBatchDmlRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteBatchDmlResponse.serialize, + ), + "Read": grpc.unary_unary_rpc_method_handler( + servicer.Read, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ReadRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_result__set__pb2.ResultSet.serialize, + ), + "StreamingRead": grpc.unary_stream_rpc_method_handler( + servicer.StreamingRead, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.ReadRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_result__set__pb2.PartialResultSet.serialize, + ), + "BeginTransaction": grpc.unary_unary_rpc_method_handler( + servicer.BeginTransaction, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.BeginTransactionRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_transaction__pb2.Transaction.serialize, + ), + "Commit": grpc.unary_unary_rpc_method_handler( + servicer.Commit, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.CommitRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_commit__response__pb2.CommitResponse.serialize, + ), + "Rollback": grpc.unary_unary_rpc_method_handler( + servicer.Rollback, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.RollbackRequest.deserialize, + response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, + ), + "PartitionQuery": grpc.unary_unary_rpc_method_handler( + servicer.PartitionQuery, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionQueryRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionResponse.serialize, + ), + "PartitionRead": grpc.unary_unary_rpc_method_handler( + servicer.PartitionRead, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionReadRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionResponse.serialize, + ), + "BatchWrite": grpc.unary_stream_rpc_method_handler( + servicer.BatchWrite, + request_deserializer=google_dot_spanner_dot_v1_dot_spanner__pb2.BatchWriteRequest.deserialize, + response_serializer=google_dot_spanner_dot_v1_dot_spanner__pb2.BatchWriteResponse.serialize, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "google.spanner.v1.Spanner", rpc_method_handlers + ) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers( + "google.spanner.v1.Spanner", rpc_method_handlers + ) + + +# This class is part of an EXPERIMENTAL API. +class Spanner(object): + """Cloud Spanner API + + The Cloud Spanner API can be used to manage sessions and execute + transactions on data stored in Cloud Spanner databases. + """ + + @staticmethod + def CreateSession( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/CreateSession", + google_dot_spanner_dot_v1_dot_spanner__pb2.CreateSessionRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.Session.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def BatchCreateSessions( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/BatchCreateSessions", + google_dot_spanner_dot_v1_dot_spanner__pb2.BatchCreateSessionsRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.BatchCreateSessionsResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def GetSession( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/GetSession", + google_dot_spanner_dot_v1_dot_spanner__pb2.GetSessionRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.Session.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ListSessions( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/ListSessions", + google_dot_spanner_dot_v1_dot_spanner__pb2.ListSessionsRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.ListSessionsResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def DeleteSession( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/DeleteSession", + google_dot_spanner_dot_v1_dot_spanner__pb2.DeleteSessionRequest.to_json, + google_dot_protobuf_dot_empty__pb2.Empty.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ExecuteSql( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/ExecuteSql", + google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteSqlRequest.to_json, + google_dot_spanner_dot_v1_dot_result__set__pb2.ResultSet.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ExecuteStreamingSql( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_stream( + request, + target, + "/google.spanner.v1.Spanner/ExecuteStreamingSql", + google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteSqlRequest.to_json, + google_dot_spanner_dot_v1_dot_result__set__pb2.PartialResultSet.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def ExecuteBatchDml( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/ExecuteBatchDml", + google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteBatchDmlRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.ExecuteBatchDmlResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def Read( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/Read", + google_dot_spanner_dot_v1_dot_spanner__pb2.ReadRequest.to_json, + google_dot_spanner_dot_v1_dot_result__set__pb2.ResultSet.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def StreamingRead( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_stream( + request, + target, + "/google.spanner.v1.Spanner/StreamingRead", + google_dot_spanner_dot_v1_dot_spanner__pb2.ReadRequest.to_json, + google_dot_spanner_dot_v1_dot_result__set__pb2.PartialResultSet.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def BeginTransaction( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/BeginTransaction", + google_dot_spanner_dot_v1_dot_spanner__pb2.BeginTransactionRequest.to_json, + google_dot_spanner_dot_v1_dot_transaction__pb2.Transaction.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def Commit( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/Commit", + google_dot_spanner_dot_v1_dot_spanner__pb2.CommitRequest.to_json, + google_dot_spanner_dot_v1_dot_commit__response__pb2.CommitResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def Rollback( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/Rollback", + google_dot_spanner_dot_v1_dot_spanner__pb2.RollbackRequest.to_json, + google_dot_protobuf_dot_empty__pb2.Empty.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def PartitionQuery( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/PartitionQuery", + google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionQueryRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def PartitionRead( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/google.spanner.v1.Spanner/PartitionRead", + google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionReadRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.PartitionResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) + + @staticmethod + def BatchWrite( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_stream( + request, + target, + "/google.spanner.v1.Spanner/BatchWrite", + google_dot_spanner_dot_v1_dot_spanner__pb2.BatchWriteRequest.to_json, + google_dot_spanner_dot_v1_dot_spanner__pb2.BatchWriteResponse.from_json, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True, + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py new file mode 100644 index 000000000000..b6c916c42bc4 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -0,0 +1,129 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +from sqlalchemy import create_engine, select, MetaData, Table, Column, Integer, String +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + ResultSet, + PingingPool, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_select1_result, + add_result, +) + + +class TestBasics(MockServerTestBase): + def verify_select1(self, results): + result_list = [] + for row in results: + result_list.append(row) + eq_(1, row[0]) + eq_(1, len(result_list)) + requests = self.spanner_service.requests + eq_(2, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + + def test_select1(self): + add_select1_result() + with self.database.snapshot() as snapshot: + results = snapshot.execute_sql("select 1") + self.verify_select1(results) + + def test_sqlalchemy_select1(self): + add_select1_result() + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": PingingPool(size=10)}, + ) + with engine.connect().execution_options( + isolation_level="AUTOCOMMIT" + ) as connection: + results = connection.execute(select(1)).fetchall() + self.verify_select1(results) + + def test_create_table(self): + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="users" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + metadata = MetaData() + Table( + "users", + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + ) + metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE users (\n" + "\tuser_id INT64 NOT NULL, \n" + "\tuser_name STRING(16) NOT NULL\n" + ") PRIMARY KEY (user_id)", + requests[0].statements[0], + ) + + def test_create_multiple_tables(self): + for i in range(2): + add_result( + f"""SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="table{i}" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + metadata = MetaData() + for i in range(2): + Table( + "table" + str(i), + metadata, + Column("id", Integer, primary_key=True), + Column("value", String(16), nullable=False), + ) + metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(2, len(requests[0].statements)) + for i in range(2): + eq_( + f"CREATE TABLE table{i} (\n" + "\tid INT64 NOT NULL, \n" + "\tvalue STRING(16) NOT NULL" + "\n) PRIMARY KEY (id)", + requests[0].statements[i], + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py new file mode 100644 index 000000000000..ce9711f7df07 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py @@ -0,0 +1,125 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +from google.cloud.spanner_v1 import ( + ResultSet, + ResultSetStats, + BatchCreateSessionsRequest, + ExecuteBatchDmlRequest, + CommitRequest, + BeginTransactionRequest, +) +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of, is_not_none +from test.mockserver_tests.mock_server_test_base import MockServerTestBase, add_result + + +class TestQuickStart(MockServerTestBase): + def test_create_tables(self): + from test.mockserver_tests.quickstart_model import Base + + # TODO: Fix the double quotes inside these SQL fragments. + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="user_account" +LIMIT 1""", + ResultSet(), + ) + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="address" +LIMIT 1""", + ResultSet(), + ) + + engine = self.create_engine() + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(2, len(requests[0].statements)) + eq_( + "CREATE TABLE user_account (\n" + "\tid INT64 NOT NULL, \n" + "\tname STRING(30) NOT NULL, \n" + "\tfullname STRING(MAX)\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + eq_( + "CREATE TABLE address (\n" + "\tid INT64 NOT NULL, \n" + "\temail_address STRING(MAX) NOT NULL, \n" + "\tuser_id INT64 NOT NULL, \n" + "\tFOREIGN KEY(user_id) REFERENCES user_account (id)\n" + ") PRIMARY KEY (id)", + requests[0].statements[1], + ) + + def test_insert_data(self): + from test.mockserver_tests.quickstart_model import User, Address + + # TODO: Use auto-generated primary keys. + update_count = ResultSet( + dict( + stats=ResultSetStats( + dict( + row_count_exact=1, + ) + ) + ) + ) + add_result( + "INSERT INTO user_account (id, name, fullname) VALUES (@a0, @a1, @a2)", + update_count, + ) + add_result( + "INSERT INTO address (id, email_address, user_id) VALUES (@a0, @a1, @a2)", + update_count, + ) + + engine = self.create_engine() + with Session(engine) as session: + spongebob = User( + id=1, + name="spongebob", + fullname="Spongebob Squarepants", + addresses=[Address(id=1, email_address="spongebob@sqlalchemy.org")], + ) + sandy = User( + id=2, + name="sandy", + fullname="Sandy Cheeks", + addresses=[ + Address(id=2, email_address="sandy@sqlalchemy.org"), + Address(id=3, email_address="sandy@squirrelpower.org"), + ], + ) + patrick = User(id=3, name="patrick", fullname="Patrick Star") + session.add_all([spongebob, sandy, patrick]) + session.commit() + + requests = self.spanner_service.requests + eq_(5, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + 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) From ca7dfd287646e5660c57715051d4c74a50fa70d2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 11:30:53 +0100 Subject: [PATCH 242/582] chore(deps): update dependency cryptography to v43.0.3 (#416) --- .../.kokoro/requirements.txt | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3e8023f4dc62..62927e5d966b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -198,34 +198,34 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==43.0.1 \ - --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \ - --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \ - --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \ - --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \ - --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \ - --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \ - --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \ - --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \ - --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \ - --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \ - --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \ - --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \ - --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \ - --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \ - --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \ - --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \ - --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \ - --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \ - --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \ - --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \ - --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \ - --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \ - --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \ - --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \ - --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \ - --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \ - --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289 +cryptography==43.0.3 \ + --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ + --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ + --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ + --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ + --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ + --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ + --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ + --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ + --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ + --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ + --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ + --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ + --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ + --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ + --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ + --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ + --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ + --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ + --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ + --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ + --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ + --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ + --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ + --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ + --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ + --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ + --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 # via # gcp-releasetool # secretstorage From 6d361405219d6c51d6a00b32df93944c56b4e79d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:04:03 +0100 Subject: [PATCH 243/582] chore(deps): update dependency urllib3 to v1.26.19 [security] (#403) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 62927e5d966b..390e2be394b7 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -579,9 +579,9 @@ typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via -r requirements.in -urllib3==1.26.18 \ - --hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \ - --hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0 +urllib3==1.26.19 \ + --hash=sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3 \ + --hash=sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429 # via # requests # twine From dd71dba04f410564cfd2113343be1cadf53d07c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:05:08 +0100 Subject: [PATCH 244/582] build(deps): bump jinja2 from 3.1.2 to 3.1.4 in /.kokoro (#396) Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.4. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.4) --- updated-dependencies: - dependency-name: jinja2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 390e2be394b7..916f3d9e529e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -369,9 +369,9 @@ jeepney==0.8.0 \ # via # keyring # secretstorage -jinja2==3.1.2 \ - --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ - --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d # via gcp-releasetool keyring==23.9.3 \ --hash=sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0 \ From 088ee8d9ffa334d5320044bd0ee74ad97c724b74 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:05:50 +0100 Subject: [PATCH 245/582] chore(deps): update dependency distlib to v0.3.9 (#417) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 916f3d9e529e..ddac7cc4fc81 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -229,9 +229,9 @@ cryptography==43.0.3 \ # via # gcp-releasetool # secretstorage -distlib==0.3.7 \ - --hash=sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057 \ - --hash=sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8 +distlib==0.3.9 \ + --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ + --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 # via virtualenv docutils==0.19 \ --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ From 71642d83f85480171519e3b70cb2dfe1c6afdae9 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:17:19 +0100 Subject: [PATCH 246/582] chore(deps): update dependency grpcio-status to v1.67.1 (#419) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 04fea757d921..0fb17ef05a26 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -238,9 +238,9 @@ grpcio==1.67.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.67.0 \ - --hash=sha256:0e79e2e01ba41a6ca6ed9d7a825323c511fe1653a646f8014c7e3c8132527acc \ - --hash=sha256:c3e5a86fa007e9e263cd5f988a8a907484da4caab582874ea2a4a6092734046b +grpcio-status==1.67.1 \ + --hash=sha256:16e6c085950bdacac97c779e6a502ea671232385e6e37f258884d6883392c2bd \ + --hash=sha256:2bf38395e028ceeecfd8866b081f61628114b384da7d51ae064ddc8d766a5d11 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 2f5ba0fabcad87ada3c2869ec6444bbaa2e990bd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:28:49 +0100 Subject: [PATCH 247/582] chore(deps): update dependency grpcio to v1.67.1 (#418) --- packages/sqlalchemy-spanner/requirements.txt | 112 +++++++++---------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0fb17ef05a26..ddcfad4e2cc3 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -176,62 +176,62 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.67.0 \ - --hash=sha256:014dfc020e28a0d9be7e93a91f85ff9f4a87158b7df9952fe23cc42d29d31e1e \ - --hash=sha256:0892dd200ece4822d72dd0952f7112c542a487fc48fe77568deaaa399c1e717d \ - --hash=sha256:0bb94e66cd8f0baf29bd3184b6aa09aeb1a660f9ec3d85da615c5003154bc2bf \ - --hash=sha256:0c69bf11894cad9da00047f46584d5758d6ebc9b5950c0dc96fec7e0bce5cde9 \ - --hash=sha256:15c05a26a0f7047f720da41dc49406b395c1470eef44ff7e2c506a47ac2c0591 \ - --hash=sha256:16724ffc956ea42967f5758c2f043faef43cb7e48a51948ab593570570d1e68b \ - --hash=sha256:227316b5631260e0bef8a3ce04fa7db4cc81756fea1258b007950b6efc90c05d \ - --hash=sha256:2b7183c80b602b0ad816315d66f2fb7887614ead950416d60913a9a71c12560d \ - --hash=sha256:2f55c1e0e2ae9bdd23b3c63459ee4c06d223b68aeb1961d83c48fb63dc29bc03 \ - --hash=sha256:30d47dbacfd20cbd0c8be9bfa52fdb833b395d4ec32fe5cff7220afc05d08571 \ - --hash=sha256:323741b6699cd2b04a71cb38f502db98f90532e8a40cb675393d248126a268af \ - --hash=sha256:3840994689cc8cbb73d60485c594424ad8adb56c71a30d8948d6453083624b52 \ - --hash=sha256:391df8b0faac84d42f5b8dfc65f5152c48ed914e13c522fd05f2aca211f8bfad \ - --hash=sha256:42199e704095b62688998c2d84c89e59a26a7d5d32eed86d43dc90e7a3bd04aa \ - --hash=sha256:54d16383044e681f8beb50f905249e4e7261dd169d4aaf6e52eab67b01cbbbe2 \ - --hash=sha256:5a1e03c3102b6451028d5dc9f8591131d6ab3c8a0e023d94c28cb930ed4b5f81 \ - --hash=sha256:62492bd534979e6d7127b8a6b29093161a742dee3875873e01964049d5250a74 \ - --hash=sha256:662c8e105c5e5cee0317d500eb186ed7a93229586e431c1bf0c9236c2407352c \ - --hash=sha256:682968427a63d898759474e3b3178d42546e878fdce034fd7474ef75143b64e3 \ - --hash=sha256:74b900566bdf68241118f2918d312d3bf554b2ce0b12b90178091ea7d0a17b3d \ - --hash=sha256:77196216d5dd6f99af1c51e235af2dd339159f657280e65ce7e12c1a8feffd1d \ - --hash=sha256:7f200aca719c1c5dc72ab68be3479b9dafccdf03df530d137632c534bb6f1ee3 \ - --hash=sha256:7fc1d2b9fd549264ae585026b266ac2db53735510a207381be509c315b4af4e8 \ - --hash=sha256:82e5bd4b67b17c8c597273663794a6a46a45e44165b960517fe6d8a2f7f16d23 \ - --hash=sha256:8c9a35b8bc50db35ab8e3e02a4f2a35cfba46c8705c3911c34ce343bd777813a \ - --hash=sha256:985b2686f786f3e20326c4367eebdaed3e7aa65848260ff0c6644f817042cb15 \ - --hash=sha256:9d75641a2fca9ae1ae86454fd25d4c298ea8cc195dbc962852234d54a07060ad \ - --hash=sha256:a4e95e43447a02aa603abcc6b5e727d093d161a869c83b073f50b9390ecf0fa8 \ - --hash=sha256:a6b9a5c18863fd4b6624a42e2712103fb0f57799a3b29651c0e5b8119a519d65 \ - --hash=sha256:aa8d025fae1595a207b4e47c2e087cb88d47008494db258ac561c00877d4c8f8 \ - --hash=sha256:ac11ecb34a86b831239cc38245403a8de25037b448464f95c3315819e7519772 \ - --hash=sha256:ae6de510f670137e755eb2a74b04d1041e7210af2444103c8c95f193340d17ee \ - --hash=sha256:b2a44e572fb762c668e4812156b81835f7aba8a721b027e2d4bb29fb50ff4d33 \ - --hash=sha256:b6eb68493a05d38b426604e1dc93bfc0137c4157f7ab4fac5771fd9a104bbaa6 \ - --hash=sha256:b9bca3ca0c5e74dea44bf57d27e15a3a3996ce7e5780d61b7c72386356d231db \ - --hash=sha256:bd79929b3bb96b54df1296cd3bf4d2b770bd1df6c2bdf549b49bab286b925cdc \ - --hash=sha256:c4c425f440fb81f8d0237c07b9322fc0fb6ee2b29fbef5f62a322ff8fcce240d \ - --hash=sha256:cb204a742997277da678611a809a8409657b1398aaeebf73b3d9563b7d154c13 \ - --hash=sha256:cf51d28063338608cd8d3cd64677e922134837902b70ce00dad7f116e3998210 \ - --hash=sha256:cfd9306511fdfc623a1ba1dc3bc07fbd24e6cfbe3c28b4d1e05177baa2f99617 \ - --hash=sha256:cff8e54d6a463883cda2fab94d2062aad2f5edd7f06ae3ed030f2a74756db365 \ - --hash=sha256:d01793653248f49cf47e5695e0a79805b1d9d4eacef85b310118ba1dfcd1b955 \ - --hash=sha256:d4ea4509d42c6797539e9ec7496c15473177ce9abc89bc5c71e7abe50fc25737 \ - --hash=sha256:d90cfdafcf4b45a7a076e3e2a58e7bc3d59c698c4f6470b0bb13a4d869cf2273 \ - --hash=sha256:e090b2553e0da1c875449c8e75073dd4415dd71c9bde6a406240fdf4c0ee467c \ - --hash=sha256:e91d154689639932305b6ea6f45c6e46bb51ecc8ea77c10ef25aa77f75443ad4 \ - --hash=sha256:eef1dce9d1a46119fd09f9a992cf6ab9d9178b696382439446ca5f399d7b96fe \ - --hash=sha256:efe32b45dd6d118f5ea2e5deaed417d8a14976325c93812dd831908522b402c9 \ - --hash=sha256:f4d613fbf868b2e2444f490d18af472ccb47660ea3df52f068c9c8801e1f3e85 \ - --hash=sha256:f55f077685f61f0fbd06ea355142b71e47e4a26d2d678b3ba27248abfe67163a \ - --hash=sha256:f623c57a5321461c84498a99dddf9d13dac0e40ee056d884d6ec4ebcab647a78 \ - --hash=sha256:f6bd2ab135c64a4d1e9e44679a616c9bc944547357c830fafea5c3caa3de5153 \ - --hash=sha256:f95e15db43e75a534420e04822df91f645664bf4ad21dfaad7d51773c80e6bb4 \ - --hash=sha256:fd6bc27861e460fe28e94226e3673d46e294ca4673d46b224428d197c5935e69 \ - --hash=sha256:fe89295219b9c9e47780a0f1c75ca44211e706d1c598242249fe717af3385ec8 +grpcio==1.67.1 \ + --hash=sha256:01f616a964e540638af5130469451cf580ba8c7329f45ca998ab66e0c7dcdb04 \ + --hash=sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292 \ + --hash=sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955 \ + --hash=sha256:0f3e49c738396e93b7ba9016e153eb09e0778e776df6090c1b8c91877cc1c426 \ + --hash=sha256:178f5db771c4f9a9facb2ab37a434c46cb9be1a75e820f187ee3d1e7805c4f65 \ + --hash=sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970 \ + --hash=sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e \ + --hash=sha256:24e8a26dbfc5274d7474c27759b54486b8de23c709d76695237515bc8b5baeab \ + --hash=sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953 \ + --hash=sha256:299b3d8c4f790c6bcca485f9963b4846dd92cf6f1b65d3697145d005c80f9fe8 \ + --hash=sha256:3b6c16489326d79ead41689c4b84bc40d522c9a7617219f4ad94bc7f448c5085 \ + --hash=sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732 \ + --hash=sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f \ + --hash=sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af \ + --hash=sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78 \ + --hash=sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc \ + --hash=sha256:5db70d32d6703b89912af16d6d45d78406374a8b8ef0d28140351dd0ec610e98 \ + --hash=sha256:5ed601c4c6008429e3d247ddb367fe8c7259c355757448d7c1ef7bd4a6739e8e \ + --hash=sha256:60336bff760fbb47d7e86165408126f1dded184448e9a4c892189eb7c9d3f90f \ + --hash=sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e \ + --hash=sha256:60e6a4dcf5af7bbc36fd9f81c9f372e8ae580870a9e4b6eafe948cd334b81cf3 \ + --hash=sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed \ + --hash=sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38 \ + --hash=sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb \ + --hash=sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5 \ + --hash=sha256:804c6457c3cd3ec04fe6006c739579b8d35c86ae3298ffca8de57b493524b771 \ + --hash=sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc \ + --hash=sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb \ + --hash=sha256:85f862069b86a305497e74d0dc43c02de3d1d184fc2c180993aa8aa86fbd19b8 \ + --hash=sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75 \ + --hash=sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f \ + --hash=sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f \ + --hash=sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb \ + --hash=sha256:95b5f2b857856ed78d72da93cd7d09b6db8ef30102e5e7fe0961fe4d9f7d48e8 \ + --hash=sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8 \ + --hash=sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311 \ + --hash=sha256:a25bdea92b13ff4d7790962190bf6bf5c4639876e01c0f3dda70fc2769616335 \ + --hash=sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62 \ + --hash=sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af \ + --hash=sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b \ + --hash=sha256:b49359977c6ec9f5d0573ea4e0071ad278ef905aa74e420acc73fd28ce39e9ce \ + --hash=sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1 \ + --hash=sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f \ + --hash=sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0 \ + --hash=sha256:cdc491ae35a13535fd9196acb5afe1af37c8237df2e54427be3eecda3653127e \ + --hash=sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121 \ + --hash=sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744 \ + --hash=sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa \ + --hash=sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e \ + --hash=sha256:ec74ef02010186185de82cc594058a3ccd8d86821842bbac9873fd4a2cf8be8d \ + --hash=sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0 \ + --hash=sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d \ + --hash=sha256:f5b76ff64aaac53fede0cc93abf57894ab2a7362986ba22243d06218b93efe46 \ + --hash=sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96 \ + --hash=sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba # via # google-api-core # googleapis-common-protos From e817f921d2d7f24f233933b837a218a3a6d450ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:29:35 +0100 Subject: [PATCH 248/582] build(deps): bump idna from 3.4 to 3.7 in /.kokoro (#392) Bumps [idna](https://github.com/kjd/idna) from 3.4 to 3.7. - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v3.4...v3.7) --- updated-dependencies: - dependency-name: idna dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ddac7cc4fc81..adc292a8e582 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -349,9 +349,9 @@ googleapis-common-protos==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 # via google-api-core -idna==3.4 \ - --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ - --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 +idna==3.7 \ + --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ + --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 # via requests importlib-metadata==5.0.0 \ --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ From 99c85e30f976862a6d918a86cdb93bfb1142a8b2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:41:46 +0100 Subject: [PATCH 249/582] chore(deps): update dependency twine to v4.0.2 (#372) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index adc292a8e582..fee641e8b956 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -571,9 +571,9 @@ six==1.16.0 \ # gcp-docuploader # google-auth # python-dateutil -twine==4.0.1 \ - --hash=sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e \ - --hash=sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0 +twine==4.0.2 \ + --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ + --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via -r requirements.in typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ From 5a97c7388aa847b8850eaedfa0dc515c22a471bf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:42:00 +0100 Subject: [PATCH 250/582] chore(deps): update dependency gcp-docuploader to v0.6.5 (#359) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index fee641e8b956..d73b16d53342 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -241,9 +241,9 @@ filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 # via virtualenv -gcp-docuploader==0.6.4 \ - --hash=sha256:01486419e24633af78fd0167db74a2763974765ee8078ca6eb6964d0ebd388af \ - --hash=sha256:70861190c123d907b3b067da896265ead2eeb9263969d6955c9e0bb091b5ccbf +gcp-docuploader==0.6.5 \ + --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ + --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea # via -r requirements.in gcp-releasetool==1.16.0 \ --hash=sha256:27bf19d2e87aaa884096ff941aa3c592c482be3d6a2bfe6f06afafa6af2353e3 \ From 69c707424d9948b5751153804523d5a2ad32902f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 12:53:47 +0100 Subject: [PATCH 251/582] chore(deps): update dependency importlib-metadata to v5.2.0 (#298) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d73b16d53342..38cfb4772c80 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -353,9 +353,9 @@ idna==3.7 \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 # via requests -importlib-metadata==5.0.0 \ - --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \ - --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43 +importlib-metadata==5.2.0 \ + --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \ + --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd # via # -r requirements.in # twine From 7556211df1ca54e05c4e8c9ea414d21664609d6f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 14:36:38 +0100 Subject: [PATCH 252/582] chore(deps): update dependency markupsafe to v2.1.5 (#421) --- .../.kokoro/requirements.txt | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 38cfb4772c80..912a6b02547b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -379,67 +379,67 @@ keyring==23.9.3 \ # via # gcp-releasetool # twine -markupsafe==2.1.3 \ - --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \ - --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \ - --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \ - --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \ - --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \ - --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \ - --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \ - --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \ - --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \ - --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \ - --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \ - --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \ - --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \ - --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \ - --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \ - --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \ - --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \ - --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \ - --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \ - --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \ - --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \ - --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \ - --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \ - --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \ - --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \ - --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \ - --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \ - --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \ - --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \ - --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \ - --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \ - --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \ - --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \ - --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \ - --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \ - --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \ - --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \ - --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \ - --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \ - --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \ - --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \ - --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \ - --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \ - --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \ - --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \ - --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \ - --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \ - --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \ - --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \ - --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \ - --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \ - --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \ - --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \ - --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \ - --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \ - --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \ - --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \ - --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \ - --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \ - --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11 +MarkupSafe==2.1.5 \ + --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ + --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ + --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ + --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ + --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ + --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ + --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ + --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ + --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ + --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ + --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ + --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ + --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ + --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ + --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ + --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ + --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ + --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ + --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ + --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ + --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ + --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ + --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ + --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ + --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ + --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ + --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ + --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ + --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ + --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ + --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ + --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ + --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ + --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ + --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ + --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ + --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ + --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ + --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ + --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ + --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ + --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ + --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ + --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ + --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ + --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ + --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ + --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ + --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ + --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ + --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ + --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ + --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ + --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ + --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ + --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ + --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ + --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ + --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ + --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 # via jinja2 more-itertools==8.14.0 \ --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ From 76c6d886d8bed26f2e3e63a34c2bbe2eed0e3830 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 14:36:50 +0100 Subject: [PATCH 253/582] chore(deps): update dependency requests to v2.32.3 (#422) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 912a6b02547b..3e7adf4c37e8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -534,9 +534,9 @@ readme-renderer==37.2 \ --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ --hash=sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923 # via twine -requests==2.32.2 \ - --hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \ - --hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 # via # gcp-releasetool # google-api-core From 14d5bc1429de69d19167e76598af0e0fd4632ee7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 15:40:51 +0100 Subject: [PATCH 254/582] chore(deps): update dependency urllib3 to v1.26.20 (#424) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3e7adf4c37e8..61992e098705 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -579,9 +579,9 @@ typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via -r requirements.in -urllib3==1.26.19 \ - --hash=sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3 \ - --hash=sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429 +urllib3==1.26.20 \ + --hash=sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e \ + --hash=sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32 # via # requests # twine From 3d9a9bb64d4c3dd469db9db723fbeb98a08a9d81 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 15:57:53 +0100 Subject: [PATCH 255/582] chore(deps): update dependency argcomplete to v2.1.2 (#426) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 61992e098705..b4772a2b8272 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes requirements.in # -argcomplete==2.0.0 \ - --hash=sha256:6372ad78c89d662035101418ae253668445b391755cfe94ea52f1b9d22425b20 \ - --hash=sha256:cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e +argcomplete==2.1.2 \ + --hash=sha256:4ba9cdaa28c361d251edce884cd50b4b1215d65cdc881bd204426cdde9f52731 \ + --hash=sha256:fc82ef070c607b1559b5c720529d63b54d9dcf2dcfc2632b10e6372314a34457 # via nox attrs==22.1.0 \ --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ From f4fb0efc06e2fdee617479d3c71c682ac8571414 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 15:58:05 +0100 Subject: [PATCH 256/582] chore(deps): update dependency attrs to v22.2.0 (#427) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b4772a2b8272..f7c7ce10510b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -8,9 +8,9 @@ argcomplete==2.1.2 \ --hash=sha256:4ba9cdaa28c361d251edce884cd50b4b1215d65cdc881bd204426cdde9f52731 \ --hash=sha256:fc82ef070c607b1559b5c720529d63b54d9dcf2dcfc2632b10e6372314a34457 # via nox -attrs==22.1.0 \ - --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \ - --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c +attrs==22.2.0 \ + --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \ + --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99 # via gcp-releasetool bleach==5.0.1 \ --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ From c1703d2a5a4b791673b88493d5ba27e40fbe6cf4 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 19:07:40 +0100 Subject: [PATCH 257/582] chore(deps): update dependency cachetools to v5.5.0 (#428) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f7c7ce10510b..90ea71b81293 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -16,9 +16,9 @@ bleach==5.0.1 \ --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c # via readme-renderer -cachetools==5.2.0 \ - --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ - --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db +cachetools==5.5.0 \ + --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ + --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via google-auth certifi==2024.7.4 \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ From cc46a5012746d1f22013431b725a909d706cf806 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 19:07:52 +0100 Subject: [PATCH 258/582] chore(deps): update dependency certifi to v2024.8.30 (#429) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 90ea71b81293..686c77147078 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via google-auth -certifi==2024.7.4 \ - --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ - --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 +certifi==2024.8.30 \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ From d5dd77d0c8cd3699f7844a9e77ac703b2013487b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 19:14:36 +0100 Subject: [PATCH 259/582] chore(deps): update dependency charset-normalizer to v3.4.0 (#431) --- .../.kokoro/requirements.txt | 197 ++++++++++-------- 1 file changed, 106 insertions(+), 91 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 686c77147078..e4c3632bf15b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -90,97 +90,112 @@ cffi==1.15.1 \ --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 # via cryptography -charset-normalizer==3.3.2 \ - --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ - --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ - --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ - --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ - --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ - --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ - --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ - --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ - --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ - --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ - --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ - --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ - --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ - --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ - --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ - --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ - --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ - --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ - --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ - --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ - --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ - --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ - --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ - --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ - --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ - --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ - --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ - --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ - --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ - --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ - --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ - --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ - --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ - --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ - --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ - --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ - --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ - --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ - --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ - --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ - --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ - --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ - --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ - --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ - --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ - --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ - --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ - --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ - --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ - --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ - --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ - --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ - --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ - --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ - --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ - --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ - --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ - --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ - --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ - --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ - --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ - --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ - --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ - --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ - --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ - --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ - --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ - --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ - --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ - --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ - --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ - --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ - --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ - --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ - --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ - --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ - --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ - --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ - --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ - --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ - --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ - --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ - --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ - --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ - --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ - --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ - --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ - --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ - --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ - --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 +charset-normalizer==3.4.0 \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 # via requests click==8.0.4 \ --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ From 46c1e93c76a4ff34bcb63a18040d7c05b394d508 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 19:14:48 +0100 Subject: [PATCH 260/582] chore(deps): update dependency cffi to v1.17.1 (#430) --- .../.kokoro/requirements.txt | 133 +++++++++--------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e4c3632bf15b..d5d459fff344 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -24,71 +24,74 @@ certifi==2024.8.30 \ --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 # via requests -cffi==1.15.1 \ - --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ - --hash=sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef \ - --hash=sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104 \ - --hash=sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426 \ - --hash=sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405 \ - --hash=sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375 \ - --hash=sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a \ - --hash=sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e \ - --hash=sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc \ - --hash=sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf \ - --hash=sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185 \ - --hash=sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497 \ - --hash=sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3 \ - --hash=sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35 \ - --hash=sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c \ - --hash=sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83 \ - --hash=sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21 \ - --hash=sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca \ - --hash=sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984 \ - --hash=sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac \ - --hash=sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd \ - --hash=sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee \ - --hash=sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a \ - --hash=sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2 \ - --hash=sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192 \ - --hash=sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7 \ - --hash=sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585 \ - --hash=sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f \ - --hash=sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e \ - --hash=sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27 \ - --hash=sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b \ - --hash=sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e \ - --hash=sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e \ - --hash=sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d \ - --hash=sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c \ - --hash=sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415 \ - --hash=sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82 \ - --hash=sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02 \ - --hash=sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314 \ - --hash=sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325 \ - --hash=sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c \ - --hash=sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3 \ - --hash=sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914 \ - --hash=sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045 \ - --hash=sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d \ - --hash=sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9 \ - --hash=sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5 \ - --hash=sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2 \ - --hash=sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c \ - --hash=sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3 \ - --hash=sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2 \ - --hash=sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8 \ - --hash=sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d \ - --hash=sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d \ - --hash=sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9 \ - --hash=sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162 \ - --hash=sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76 \ - --hash=sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4 \ - --hash=sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e \ - --hash=sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9 \ - --hash=sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6 \ - --hash=sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b \ - --hash=sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01 \ - --hash=sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0 +cffi==1.17.1 \ + --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ + --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ + --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ + --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ + --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ + --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ + --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ + --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ + --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ + --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ + --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ + --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ + --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ + --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ + --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ + --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ + --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ + --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ + --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ + --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ + --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ + --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ + --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ + --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ + --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ + --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ + --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ + --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ + --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ + --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ + --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ + --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ + --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ + --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ + --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ + --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ + --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ + --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ + --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ + --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ + --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ + --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ + --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ + --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ + --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ + --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ + --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ + --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ + --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ + --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ + --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ + --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ + --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ + --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ + --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ + --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ + --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ + --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ + --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ + --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ + --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ + --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ + --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ + --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ + --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ + --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b # via cryptography charset-normalizer==3.4.0 \ --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ From 10e7b9f1e215a5a3c086a45cd5ffa86c908d745c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH <57220027+harshachinta@users.noreply.github.com> Date: Thu, 31 Oct 2024 23:48:06 +0530 Subject: [PATCH 261/582] feat: support dml returning (#335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support dml returning * feat: add tests for dml returning * feat: update tests * feat: support dml returning * feat: add test in sqlalchemy 2.0 * feat: add returning support for sqlalchemy 2.0 --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy-spanner/test/test_suite_13.py | 43 +++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite_14.py | 43 +++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite_20.py | 43 +++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index ca11979b6bb6..b0cddf5945e6 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -2065,6 +2065,49 @@ def test_create_engine_wo_database(self): assert connection.connection.database is None +class ReturningTest(fixtures.TestBase): + def setUp(self): + self._engine = create_engine(get_db_url()) + metadata = MetaData() + + self._table = Table( + "returning_test", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + + def test_returning_for_insert_and_update(self): + random_id = random.randint(1, 1000) + with self._engine.begin() as connection: + stmt = ( + self._table.insert() + .values(id=random_id, data="some % value") + .returning(self._table.c.id) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(random_id,)], + ) + + with self._engine.begin() as connection: + update_text = "some + value" + stmt = ( + self._table.update() + .values(data=update_text) + .where(self._table.c.id == random_id) + .returning(self._table.c.data) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(update_text,)], + ) + + @pytest.mark.skipif( bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" ) diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 87437b83c792..e4183821f2ca 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -2399,6 +2399,49 @@ def test_create_engine_wo_database(self): assert connection.connection.database is None +class ReturningTest(fixtures.TestBase): + def setUp(self): + self._engine = create_engine(get_db_url()) + metadata = MetaData() + + self._table = Table( + "returning_test", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + + def test_returning_for_insert_and_update(self): + random_id = random.randint(1, 1000) + with self._engine.begin() as connection: + stmt = ( + self._table.insert() + .values(id=random_id, data="some % value") + .returning(self._table.c.id) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(random_id,)], + ) + + with self._engine.begin() as connection: + update_text = "some + value" + stmt = ( + self._table.update() + .values(data=update_text) + .where(self._table.c.id == random_id) + .returning(self._table.c.data) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(update_text,)], + ) + + @pytest.mark.skipif( bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" ) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index cff1a30ddde3..4902b3ab6def 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -3113,6 +3113,49 @@ def test_create_engine_wo_database(self): assert connection.connection.database is None +class ReturningTest(fixtures.TestBase): + def setUp(self): + self._engine = create_engine(get_db_url()) + metadata = MetaData() + + self._table = Table( + "returning_test", + metadata, + Column("id", Integer, primary_key=True), + Column("data", String(16), nullable=False), + ) + + metadata.create_all(self._engine) + + def test_returning_for_insert_and_update(self): + random_id = random.randint(1, 1000) + with self._engine.begin() as connection: + stmt = ( + self._table.insert() + .values(id=random_id, data="some % value") + .returning(self._table.c.id) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(random_id,)], + ) + + with self._engine.begin() as connection: + update_text = "some + value" + stmt = ( + self._table.update() + .values(data=update_text) + .where(self._table.c.id == random_id) + .returning(self._table.c.data) + ) + row = connection.execute(stmt).fetchall() + eq_( + row, + [(update_text,)], + ) + + @pytest.mark.skipif( bool(os.environ.get("SPANNER_EMULATOR_HOST")), reason="Skipped on emulator" ) From a067477b9de4f0ef925b483c2c7408784ea48599 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 20:08:16 +0100 Subject: [PATCH 262/582] chore(deps): update dependency colorlog to v6.9.0 (#432) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d5d459fff344..dedc8191caf3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -206,9 +206,9 @@ click==8.0.4 \ # via # gcp-docuploader # gcp-releasetool -colorlog==6.7.0 \ - --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ - --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 +colorlog==6.9.0 \ + --hash=sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff \ + --hash=sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2 # via # gcp-docuploader # nox From 6d271e04858c80f31051bd7673bf6336cf04ac2a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 31 Oct 2024 20:08:28 +0100 Subject: [PATCH 263/582] chore(deps): update dependency docutils to v0.21.2 (#433) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index dedc8191caf3..563837a89589 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -251,9 +251,9 @@ distlib==0.3.9 \ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 # via virtualenv -docutils==0.19 \ - --hash=sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6 \ - --hash=sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc +docutils==0.21.2 \ + --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ + --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # via readme-renderer filelock==3.8.0 \ --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ From bf7f97c1de66443ccab96d51c7099e58becbfa61 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 06:46:19 +0100 Subject: [PATCH 264/582] chore(deps): update dependency filelock to v3.16.1 (#434) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [filelock](https://redirect.github.com/tox-dev/py-filelock) | `==3.8.0` -> `==3.16.1` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/filelock/3.16.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/filelock/3.16.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/filelock/3.8.0/3.16.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/filelock/3.8.0/3.16.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
tox-dev/py-filelock (filelock) ### [`v3.16.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.16.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.16.0...3.16.1) #### What's Changed - CI improvements by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/362](https://redirect.github.com/tox-dev/filelock/pull/362) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.16.0...3.16.1 ### [`v3.16.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.16.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.15.4...3.16.0) #### What's Changed - Test Python 3.13 by [@​hugovk](https://redirect.github.com/hugovk) in [https://togithub.com/tox-dev/filelock/pull/352](https://redirect.github.com/tox-dev/filelock/pull/352) - Add 3.13 to CI by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/359](https://redirect.github.com/tox-dev/filelock/pull/359) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.15.4...3.16.0 ### [`v3.15.4`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.15.4) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.15.3...3.15.4) #### What's Changed - Pass `file_lock` as positional argument by [@​kwist-sgr](https://redirect.github.com/kwist-sgr) in [https://togithub.com/tox-dev/filelock/pull/347](https://redirect.github.com/tox-dev/filelock/pull/347) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.15.3...3.15.4 ### [`v3.15.3`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.15.3) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.15.2...3.15.3) #### What's Changed - Add test for virtualenv stability by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/344](https://redirect.github.com/tox-dev/filelock/pull/344) - Fix `TypeError: _CountedFileLock.__init__() got an unexpected keyword argument 'timeout'` by [@​kwist-sgr](https://redirect.github.com/kwist-sgr) in [https://togithub.com/tox-dev/filelock/pull/345](https://redirect.github.com/tox-dev/filelock/pull/345) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.15.2...3.15.3 ### [`v3.15.2`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.15.2) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.15.1...3.15.2) #### What's Changed - Use a metaclass to implement the singleton pattern by [@​kwist-sgr](https://redirect.github.com/kwist-sgr) in [https://togithub.com/tox-dev/filelock/pull/340](https://redirect.github.com/tox-dev/filelock/pull/340) #### New Contributors - [@​kwist-sgr](https://redirect.github.com/kwist-sgr) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/340](https://redirect.github.com/tox-dev/filelock/pull/340) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.15.1...3.15.2 ### [`v3.15.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.15.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.15.0...3.15.1) #### What's Changed - Hotfix: Restore **init** method; more robust initialization for singleton locks by [@​ethanbb](https://redirect.github.com/ethanbb) in [https://togithub.com/tox-dev/filelock/pull/338](https://redirect.github.com/tox-dev/filelock/pull/338) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.15.0...3.15.1 ### [`v3.15.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.15.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.14.0...3.15.0) #### What's Changed - asyncio support by [@​Ovizro](https://redirect.github.com/Ovizro) in [https://togithub.com/tox-dev/filelock/pull/332](https://redirect.github.com/tox-dev/filelock/pull/332) - Don't initialize BaseFileLock when just returning existing instance by [@​ethanbb](https://redirect.github.com/ethanbb) in [https://togithub.com/tox-dev/filelock/pull/334](https://redirect.github.com/tox-dev/filelock/pull/334) #### New Contributors - [@​Ovizro](https://redirect.github.com/Ovizro) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/332](https://redirect.github.com/tox-dev/filelock/pull/332) - [@​ethanbb](https://redirect.github.com/ethanbb) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/334](https://redirect.github.com/tox-dev/filelock/pull/334) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.14.0...3.15.0 ### [`v3.14.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.14.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.13.4...3.14.0) #### What's Changed - feat: `blocking` parameter on lock constructor with tests and docs by [@​iamkhav](https://redirect.github.com/iamkhav) in [https://togithub.com/tox-dev/filelock/pull/325](https://redirect.github.com/tox-dev/filelock/pull/325) #### New Contributors - [@​iamkhav](https://redirect.github.com/iamkhav) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/325](https://redirect.github.com/tox-dev/filelock/pull/325) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.13.4...3.14.0 ### [`v3.13.4`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.13.4) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.13.3...3.13.4) #### What's Changed - Raise error on incompatible singleton timeout and mode args by [@​nefrob](https://redirect.github.com/nefrob) in [https://togithub.com/tox-dev/filelock/pull/320](https://redirect.github.com/tox-dev/filelock/pull/320) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.13.3...3.13.4 ### [`v3.13.3`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.13.3) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.13.2...3.13.3) #### What's Changed - Make singleton class instance dict unique per subclass by [@​nefrob](https://redirect.github.com/nefrob) in [https://togithub.com/tox-dev/filelock/pull/318](https://redirect.github.com/tox-dev/filelock/pull/318) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.13.2...3.13.3 ### [`v3.13.2`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.13.2) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.13.1...3.13.2) #### What's Changed - Fixed small typo in \_unix.py by [@​snemes](https://redirect.github.com/snemes) in [https://togithub.com/tox-dev/filelock/pull/302](https://redirect.github.com/tox-dev/filelock/pull/302) - Update SECURITY.md to reflect Python 3.7 support dropoff by [@​kemzeb](https://redirect.github.com/kemzeb) in [https://togithub.com/tox-dev/filelock/pull/304](https://redirect.github.com/tox-dev/filelock/pull/304) - Update index.rst to improve the demo usage by [@​youkaichao](https://redirect.github.com/youkaichao) in [https://togithub.com/tox-dev/filelock/pull/314](https://redirect.github.com/tox-dev/filelock/pull/314) - \[BugFix] fix permission denied error when lock file is placed in `/tmp` by [@​kota-iizuka](https://redirect.github.com/kota-iizuka) in [https://togithub.com/tox-dev/filelock/pull/317](https://redirect.github.com/tox-dev/filelock/pull/317) #### New Contributors - [@​snemes](https://redirect.github.com/snemes) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/302](https://redirect.github.com/tox-dev/filelock/pull/302) - [@​kemzeb](https://redirect.github.com/kemzeb) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/304](https://redirect.github.com/tox-dev/filelock/pull/304) - [@​youkaichao](https://redirect.github.com/youkaichao) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/314](https://redirect.github.com/tox-dev/filelock/pull/314) - [@​kota-iizuka](https://redirect.github.com/kota-iizuka) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/317](https://redirect.github.com/tox-dev/filelock/pull/317) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.13.1...3.13.2 ### [`v3.13.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.13.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.13.0...3.13.1) #### What's Changed - Allow users to subclass FileLock with custom keyword arguments by [@​hmaarrfk](https://redirect.github.com/hmaarrfk) in [https://togithub.com/tox-dev/filelock/pull/284](https://redirect.github.com/tox-dev/filelock/pull/284) #### New Contributors - [@​hmaarrfk](https://redirect.github.com/hmaarrfk) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/284](https://redirect.github.com/tox-dev/filelock/pull/284) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.13.0...3.13.1 ### [`v3.13.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.13.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.12.4...3.13.0) #### What's Changed - Support reentrant locking on lock file path via optional singleton instance by [@​nefrob](https://redirect.github.com/nefrob) in [https://togithub.com/tox-dev/filelock/pull/283](https://redirect.github.com/tox-dev/filelock/pull/283) #### New Contributors - [@​nefrob](https://redirect.github.com/nefrob) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/283](https://redirect.github.com/tox-dev/filelock/pull/283) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.12.4...3.13.0 ### [`v3.12.4`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.12.4) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.12.3...3.12.4) #### What's Changed - change typing-extensions to be installed only with the \[typing] extra by [@​asottile](https://redirect.github.com/asottile) in [https://togithub.com/tox-dev/filelock/pull/276](https://redirect.github.com/tox-dev/filelock/pull/276) #### New Contributors - [@​asottile](https://redirect.github.com/asottile) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/276](https://redirect.github.com/tox-dev/filelock/pull/276) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.12.3...3.12.4 ### [`v3.12.3`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.12.3) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.12.2...3.12.3) ##### What's Changed - Fix import ordering by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/246](https://redirect.github.com/tox-dev/filelock/pull/246) - Exclude dependabot and pre-commit ci from release notes by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/251](https://redirect.github.com/tox-dev/filelock/pull/251) - Create parent directories if necessary by [@​gerlero](https://redirect.github.com/gerlero) in [https://togithub.com/tox-dev/filelock/pull/254](https://redirect.github.com/tox-dev/filelock/pull/254) - fix ci 08 21 by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/filelock/pull/263](https://redirect.github.com/tox-dev/filelock/pull/263) - lock_file type-hint by [@​keller00](https://redirect.github.com/keller00) in [https://togithub.com/tox-dev/filelock/pull/267](https://redirect.github.com/tox-dev/filelock/pull/267) - adding tox.ini to sdist by [@​keller00](https://redirect.github.com/keller00) in [https://togithub.com/tox-dev/filelock/pull/265](https://redirect.github.com/tox-dev/filelock/pull/265) ##### New Contributors - [@​gerlero](https://redirect.github.com/gerlero) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/254](https://redirect.github.com/tox-dev/filelock/pull/254) - [@​keller00](https://redirect.github.com/keller00) made their first contribution in [https://togithub.com/tox-dev/filelock/pull/267](https://redirect.github.com/tox-dev/filelock/pull/267) **Full Changelog**: https://togithub.com/tox-dev/filelock/compare/3.12.2...3.12.3 ### [`v3.12.2`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.12.2) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.12.1...3.12.2) #### What's Changed - Restore 'if TYPE_CHECKING' syntax for FileLock definition by [@​dlax](https://redirect.github.com/dlax) in [https://togithub.com/tox-dev/py-filelock/pull/245](https://redirect.github.com/tox-dev/py-filelock/pull/245) #### New Contributors - [@​dlax](https://redirect.github.com/dlax) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/245](https://redirect.github.com/tox-dev/py-filelock/pull/245) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.12.1...3.12.2 ### [`v3.12.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.12.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.12.0...3.12.1) ##### What's Changed - Add trusted-publish by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/236](https://redirect.github.com/tox-dev/py-filelock/pull/236) - Add 3.12 support by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/237](https://redirect.github.com/tox-dev/py-filelock/pull/237) - Bump pypa/gh-action-pypi-publish from 1.8.5 to 1.8.6 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/239](https://redirect.github.com/tox-dev/py-filelock/pull/239) - git ls-files -z -- .github/workflows/check.yml | xargs -0 sed -i 's|3.12.0-alpha.7|3.12.0-beta.1|g' by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/243](https://redirect.github.com/tox-dev/py-filelock/pull/243) - Use ruff by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/244](https://redirect.github.com/tox-dev/py-filelock/pull/244) - Fix test_bad_lock_file for other OSes by [@​TheMatt2](https://redirect.github.com/TheMatt2) in [https://togithub.com/tox-dev/py-filelock/pull/242](https://redirect.github.com/tox-dev/py-filelock/pull/242) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.12.0...3.12.1 ### [`v3.12.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.12.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.11.0...3.12.0) #### What's Changed - Fix: [#​225](https://redirect.github.com/tox-dev/py-filelock/issues/225) :Get rid of warning about inability to link to \_thread.\_local. by [@​csm10495](https://redirect.github.com/csm10495) in [https://togithub.com/tox-dev/py-filelock/pull/226](https://redirect.github.com/tox-dev/py-filelock/pull/226) - Bump deps and tools by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/228](https://redirect.github.com/tox-dev/py-filelock/pull/228) - Add umask check to tests so umask 002 is valid by [@​TheMatt2](https://redirect.github.com/TheMatt2) in [https://togithub.com/tox-dev/py-filelock/pull/227](https://redirect.github.com/tox-dev/py-filelock/pull/227) - Fix lock hang on Windows by [@​TheMatt2](https://redirect.github.com/TheMatt2) in [https://togithub.com/tox-dev/py-filelock/pull/231](https://redirect.github.com/tox-dev/py-filelock/pull/231) - Conditionally disable/enable thread-local lock behavior. by [@​csm10495](https://redirect.github.com/csm10495) in [https://togithub.com/tox-dev/py-filelock/pull/232](https://redirect.github.com/tox-dev/py-filelock/pull/232) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.11.0...3.12.0 ### [`v3.11.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.11.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.7...3.11.0) #### What's Changed - Bump pypa/gh-action-pypi-publish from 1.8.3 to 1.8.5 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/218](https://redirect.github.com/tox-dev/py-filelock/pull/218) - Fix [#​220](https://redirect.github.com/tox-dev/py-filelock/issues/220): Allow filelock test thread to catch any exceptions by [@​TheMatt2](https://redirect.github.com/TheMatt2) in [https://togithub.com/tox-dev/py-filelock/pull/221](https://redirect.github.com/tox-dev/py-filelock/pull/221) - Bump deps and tools by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/222](https://redirect.github.com/tox-dev/py-filelock/pull/222) - Run more pypy versions in CI but without coverage by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/224](https://redirect.github.com/tox-dev/py-filelock/pull/224) - Make the lock a thread local variable by [@​csm10495](https://redirect.github.com/csm10495) in [https://togithub.com/tox-dev/py-filelock/pull/219](https://redirect.github.com/tox-dev/py-filelock/pull/219) #### New Contributors - [@​csm10495](https://redirect.github.com/csm10495) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/219](https://redirect.github.com/tox-dev/py-filelock/pull/219) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.7...3.11.0 ### [`v3.10.7`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.7) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.6...3.10.7) #### What's Changed - use fchmod by [@​jfennick](https://redirect.github.com/jfennick) in [https://togithub.com/tox-dev/py-filelock/pull/214](https://redirect.github.com/tox-dev/py-filelock/pull/214) #### New Contributors - [@​jfennick](https://redirect.github.com/jfennick) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/214](https://redirect.github.com/tox-dev/py-filelock/pull/214) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.6...3.10.7 ### [`v3.10.6`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.6) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.5...3.10.6) #### What's Changed - Bugfix/147 by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/213](https://redirect.github.com/tox-dev/py-filelock/pull/213) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.5...3.10.6 ### [`v3.10.5`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.5) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.4...3.10.5) #### What's Changed - proposed fix for issue [#​67](https://redirect.github.com/tox-dev/py-filelock/issues/67) by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/212](https://redirect.github.com/tox-dev/py-filelock/pull/212) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.4...3.10.5 ### [`v3.10.4`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.4) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.3...3.10.4) #### What's Changed - updated os.open to preserve mode by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/211](https://redirect.github.com/tox-dev/py-filelock/pull/211) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.3...3.10.4 ### [`v3.10.3`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.3) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.2...3.10.3) #### What's Changed - Bump pypa/gh-action-pypi-publish from 1.8.1 to 1.8.3 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/207](https://redirect.github.com/tox-dev/py-filelock/pull/207) - bug fix by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/209](https://redirect.github.com/tox-dev/py-filelock/pull/209) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.2...3.10.3 ### [`v3.10.2`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.2) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.1...3.10.2) ##### What's Changed - changed from os.umask to os.chmod by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/206](https://redirect.github.com/tox-dev/py-filelock/pull/206) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.1...3.10.2 ### [`v3.10.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.10.0...3.10.1) #### What's Changed - Bump pypa/gh-action-pypi-publish from 1.7.1 to 1.8.1 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/200](https://redirect.github.com/tox-dev/py-filelock/pull/200) - Bump deps and tools by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/201](https://redirect.github.com/tox-dev/py-filelock/pull/201) - Properly pickle of Timeout objects + test cases by [@​TheMatt2](https://redirect.github.com/TheMatt2) in [https://togithub.com/tox-dev/py-filelock/pull/203](https://redirect.github.com/tox-dev/py-filelock/pull/203) #### New Contributors - [@​TheMatt2](https://redirect.github.com/TheMatt2) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/203](https://redirect.github.com/tox-dev/py-filelock/pull/203) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.10.0...3.10.1 ### [`v3.10.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.10.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.9.1...3.10.0) #### What's Changed - added multiuser support and associated tests by [@​jahrules](https://redirect.github.com/jahrules) in [https://togithub.com/tox-dev/py-filelock/pull/192](https://redirect.github.com/tox-dev/py-filelock/pull/192) #### New Contributors - [@​jahrules](https://redirect.github.com/jahrules) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/192](https://redirect.github.com/tox-dev/py-filelock/pull/192) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.9.1...3.10.0 ### [`v3.9.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.9.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.9.0...3.9.1) #### What's Changed - \[pre-commit.ci] pre-commit autoupdate by [@​pre-commit-ci](https://redirect.github.com/pre-commit-ci) in [https://togithub.com/tox-dev/py-filelock/pull/188](https://redirect.github.com/tox-dev/py-filelock/pull/188) - Bump deps and tools by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/193](https://redirect.github.com/tox-dev/py-filelock/pull/193) - Bump deps and tools by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/197](https://redirect.github.com/tox-dev/py-filelock/pull/197) - Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.7.1 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/198](https://redirect.github.com/tox-dev/py-filelock/pull/198) - use time.perf_counter instead of time.monotonic by [@​zpz](https://redirect.github.com/zpz) in [https://togithub.com/tox-dev/py-filelock/pull/194](https://redirect.github.com/tox-dev/py-filelock/pull/194) #### New Contributors - [@​zpz](https://redirect.github.com/zpz) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/194](https://redirect.github.com/tox-dev/py-filelock/pull/194) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.9.0...3.9.1 ### [`v3.9.0`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.9.0) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.8.2...3.9.0) ##### What's Changed - Move to hatchling build backend by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/185](https://redirect.github.com/tox-dev/py-filelock/pull/185) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.8.2...3.9.0 ### [`v3.8.2`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.8.2) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.8.1...3.8.2) ##### What's Changed - Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.6.1 by [@​dependabot](https://redirect.github.com/dependabot) in [https://togithub.com/tox-dev/py-filelock/pull/178](https://redirect.github.com/tox-dev/py-filelock/pull/178) - Update the license classifier to "Unlicense" by [@​jond01](https://redirect.github.com/jond01) in [https://togithub.com/tox-dev/py-filelock/pull/180](https://redirect.github.com/tox-dev/py-filelock/pull/180) ##### New Contributors - [@​jond01](https://redirect.github.com/jond01) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/180](https://redirect.github.com/tox-dev/py-filelock/pull/180) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.8.1...3.8.2 ### [`v3.8.1`](https://redirect.github.com/tox-dev/filelock/releases/tag/3.8.1) [Compare Source](https://redirect.github.com/tox-dev/py-filelock/compare/3.8.0...3.8.1) ##### What's Changed - \[pre-commit.ci] pre-commit autoupdate by [@​pre-commit-ci](https://redirect.github.com/pre-commit-ci) in [https://togithub.com/tox-dev/py-filelock/pull/166](https://redirect.github.com/tox-dev/py-filelock/pull/166) - link to flufl.lock by [@​dholth](https://redirect.github.com/dholth) in [https://togithub.com/tox-dev/py-filelock/pull/167](https://redirect.github.com/tox-dev/py-filelock/pull/167) - \[pre-commit.ci] pre-commit autoupdate by [@​pre-commit-ci](https://redirect.github.com/pre-commit-ci) in [https://togithub.com/tox-dev/py-filelock/pull/168](https://redirect.github.com/tox-dev/py-filelock/pull/168) - \[pre-commit.ci] pre-commit autoupdate by [@​pre-commit-ci](https://redirect.github.com/pre-commit-ci) in [https://togithub.com/tox-dev/py-filelock/pull/169](https://redirect.github.com/tox-dev/py-filelock/pull/169) - \[pre-commit.ci] pre-commit autoupdate by [@​pre-commit-ci](https://redirect.github.com/pre-commit-ci) in [https://togithub.com/tox-dev/py-filelock/pull/170](https://redirect.github.com/tox-dev/py-filelock/pull/170) - fix BaseFileLock.timeout's getter/setter being obscured by itself by [@​dearfl](https://redirect.github.com/dearfl) in [https://togithub.com/tox-dev/py-filelock/pull/172](https://redirect.github.com/tox-dev/py-filelock/pull/172) - Fix mypy fails understanding FileLock by [@​gaborbernat](https://redirect.github.com/gaborbernat) in [https://togithub.com/tox-dev/py-filelock/pull/177](https://redirect.github.com/tox-dev/py-filelock/pull/177) ##### New Contributors - [@​dholth](https://redirect.github.com/dholth) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/167](https://redirect.github.com/tox-dev/py-filelock/pull/167) - [@​dearfl](https://redirect.github.com/dearfl) made their first contribution in [https://togithub.com/tox-dev/py-filelock/pull/172](https://redirect.github.com/tox-dev/py-filelock/pull/172) **Full Changelog**: https://togithub.com/tox-dev/py-filelock/compare/3.8.0...3.8.1
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 563837a89589..f5349c7a0ad7 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -255,9 +255,9 @@ docutils==0.21.2 \ --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # via readme-renderer -filelock==3.8.0 \ - --hash=sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc \ - --hash=sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4 +filelock==3.16.1 \ + --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ + --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 # via virtualenv gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ From cd111ce2c2b5bd61ffc483a49ed343a3f184d9df Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 07:54:33 +0100 Subject: [PATCH 265/582] chore(deps): update dependency urllib3 to v2 (#479) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f5349c7a0ad7..4a3b5b9a33ad 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -597,9 +597,9 @@ typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef # via -r requirements.in -urllib3==1.26.20 \ - --hash=sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e \ - --hash=sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32 +urllib3==2.2.3 \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 # via # requests # twine From ee994176dd152f003010dd62b4da56615b1ffbaf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 07:57:06 +0100 Subject: [PATCH 266/582] chore(deps): update dependency twine to v5 (#478) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 4a3b5b9a33ad..b82afa8538be 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -589,9 +589,9 @@ six==1.16.0 \ # gcp-docuploader # google-auth # python-dateutil -twine==4.0.2 \ - --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ - --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 +twine==5.1.1 \ + --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ + --hash=sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db # via -r requirements.in typing-extensions==4.8.0 \ --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ From eff8c4f3d53182f5b90efe4fa24105fd29e93809 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 07:57:20 +0100 Subject: [PATCH 267/582] chore(deps): update dependency requests-toolbelt to v1 (#476) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b82afa8538be..ec46784efc1a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -561,9 +561,9 @@ requests==2.32.3 \ # google-cloud-storage # requests-toolbelt # twine -requests-toolbelt==0.10.1 \ - --hash=sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7 \ - --hash=sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d +requests-toolbelt==1.0.0 \ + --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ + --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ From 5e62ae8051e7135fbdaf71fb22ef5aad03f1390d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 07:57:46 +0100 Subject: [PATCH 268/582] chore(deps): update dependency packaging to v24 (#472) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ec46784efc1a..dac0586f35d3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -467,9 +467,9 @@ nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c # via -r requirements.in -packaging==21.3 \ - --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ - --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 +packaging==24.1 \ + --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ + --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 # via # gcp-releasetool # nox From 70203045973d68be04aa11851bf5a353064ad4fe Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 07:58:19 +0100 Subject: [PATCH 269/582] chore(deps): update dependency bleach to v6 (#465) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [bleach](https://redirect.github.com/mozilla/bleach) | `==5.0.1` -> `==6.2.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/bleach/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/bleach/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/bleach/5.0.1/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/bleach/5.0.1/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
mozilla/bleach (bleach) ### [`v6.2.0`](https://redirect.github.com/mozilla/bleach/blob/HEAD/CHANGES#Version-620-October-29th-2024) [Compare Source](https://redirect.github.com/mozilla/bleach/compare/v6.1.0...v6.2.0) **Backwards incompatible changes** - Dropped support for Python 3.8. ([#​737](https://redirect.github.com/mozilla/bleach/issues/737)) **Security fixes** None **Bug fixes** - Add support for Python 3.13. ([#​736](https://redirect.github.com/mozilla/bleach/issues/736)) - Remove six depdenncy. ([#​618](https://redirect.github.com/mozilla/bleach/issues/618)) - Update known-good versions for tinycss2. ([#​732](https://redirect.github.com/mozilla/bleach/issues/732)) - Fix additional < followed by characters and EOF issues. ([#​728](https://redirect.github.com/mozilla/bleach/issues/728)) ### [`v6.1.0`](https://redirect.github.com/mozilla/bleach/blob/HEAD/CHANGES#Version-610-October-6th-2023) [Compare Source](https://redirect.github.com/mozilla/bleach/compare/v6.0.0...v6.1.0) **Backwards incompatible changes** - Dropped support for Python 3.7. ([#​709](https://redirect.github.com/mozilla/bleach/issues/709)) **Security fixes** None **Bug fixes** - Add support for Python 3.12. ([#​710](https://redirect.github.com/mozilla/bleach/issues/710)) - Fix linkify with arrays in querystring ([#​436](https://redirect.github.com/mozilla/bleach/issues/436)) - Handle more cases with < followed by character data ([#​705](https://redirect.github.com/mozilla/bleach/issues/705)) - Fix entities inside a tags in linkification ([#​704](https://redirect.github.com/mozilla/bleach/issues/704)) - Update cap for tinycss2 to <1.3 ([#​702](https://redirect.github.com/mozilla/bleach/issues/702)) - Updated Sphinx requirement - Add dependabot for github actions and update github actions ### [`v6.0.0`](https://redirect.github.com/mozilla/bleach/blob/HEAD/CHANGES#Version-600-January-23rd-2023) [Compare Source](https://redirect.github.com/mozilla/bleach/compare/v5.0.1...v6.0.0) **Backwards incompatible changes** - `bleach.clean`, `bleach.sanitizer.Cleaner`, `bleach.html5lib_shim.BleachHTMLParser`: the `tags` and `protocols` arguments were changed from lists to sets. Old pre-6.0.0: .. code-block:: python bleach.clean( "some text", tags=\["a", "p", "img"], ### ^ ^ list protocols=["http", "https"], ### ^ ^ list ) New 6.0.0 and later: .. code-block:: python bleach.clean( "some text", tags={"a", "p", "img"}, ### ^ ^ set protocols={"http", "https"}, ### ^ ^ set ) - `bleach.linkify`, `bleach.linkifier.Linker`: the `skip_tags` and `recognized_tags` arguments were changed from lists to sets. Old pre-6.0.0: .. code-block:: python bleach.linkify( "some text", skip_tags=\["pre"], ### ^ ^ list ) linker = Linker( skip_tags=["pre"], ### ^ ^ list recognized_tags=html5lib_shim.HTML_TAGS + ["custom-element"], ### ^ ^ ^ list ### | ### | list concatenation ) New 6.0.0 and later: .. code-block:: python bleach.linkify( "some text", skip_tags={"pre"}, ### ^ ^ set ) linker = Linker( skip_tags={"pre"}, ### ^ ^ set recognized_tags=html5lib_shim.HTML_TAGS | {"custom-element"}, ### ^ ^ ^ set ### | ### | union operator ) - `bleach.sanitizer.BleachSanitizerFilter`: `strip_allowed_elements` is now `strip_allowed_tags`. We now use "tags" everywhere rather than a mishmash of "tags" in some places and "elements" in others. **Security fixes** None **Bug fixes** - Add support for Python 3.11. ([#​675](https://redirect.github.com/mozilla/bleach/issues/675)) - Fix API weirness in `BleachSanitizerFilter`. ([#​649](https://redirect.github.com/mozilla/bleach/issues/649)) We're using "tags" instead of "elements" everywhere--no more weird overloading of "elements" anymore. Also, it no longer calls the superclass constructor. - Add warning when `css_sanitizer` isn't set, but the `style` attribute is allowed. ([#​676](https://redirect.github.com/mozilla/bleach/issues/676)) - Fix linkify handling of character entities. ([#​501](https://redirect.github.com/mozilla/bleach/issues/501)) - Rework dev dependencies to use `requirements-dev.txt` and `requirements-flake8.txt` instead of extras. - Fix project infrastructure to be tox-based so it's easier to have CI run the same things we're running in development and with flake8 in an isolated environment. - Update action versions in CI. - Switch to f-strings where possible. Make tests parametrized to be easier to read/maintain.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index dac0586f35d3..b93316625e8e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -12,9 +12,9 @@ attrs==22.2.0 \ --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \ --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99 # via gcp-releasetool -bleach==5.0.1 \ - --hash=sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a \ - --hash=sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c +bleach==6.2.0 \ + --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e \ + --hash=sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f # via readme-renderer cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ From 76b7b1e00d6561371520f6362836650c652270fc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:00:31 +0100 Subject: [PATCH 270/582] chore(deps): update dependency attrs to v24 (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [attrs](https://redirect.github.com/python-attrs/attrs) ([changelog](https://www.attrs.org/en/stable/changelog.html)) | `==22.2.0` -> `==24.2.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/attrs/24.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/attrs/24.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/attrs/22.2.0/24.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/attrs/22.2.0/24.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
python-attrs/attrs (attrs) ### [`v24.2.0`](https://redirect.github.com/python-attrs/attrs/blob/HEAD/CHANGELOG.md#2420---2024-08-06) [Compare Source](https://redirect.github.com/python-attrs/attrs/compare/24.1.0...24.2.0) ##### Deprecations - Given the amount of warnings raised in the broader ecosystem, we've decided to only soft-deprecate the *hash* argument to `@define` / `@attr.s`. Please don't use it in new code, but we don't intend to remove it anymore. [#​1330](https://redirect.github.com/python-attrs/attrs/issues/1330) ##### Changes - `attrs.converters.pipe()` (and its syntactic sugar of passing a list for `attrs.field()`'s / `attr.ib()`'s *converter* argument) works again when passing `attrs.setters.convert` to *on_setattr* (which is default for `attrs.define`). [#​1328](https://redirect.github.com/python-attrs/attrs/issues/1328) - Restored support for PEP [649](https://peps.python.org/pep-0649/) / [749](https://peps.python.org/pep-0749/)-implementing Pythons -- currently 3.14-dev. [#​1329](https://redirect.github.com/python-attrs/attrs/issues/1329) ### [`v24.1.0`](https://redirect.github.com/python-attrs/attrs/blob/HEAD/CHANGELOG.md#2410---2024-08-03) [Compare Source](https://redirect.github.com/python-attrs/attrs/compare/23.2.0...24.1.0) ##### Backwards-incompatible Changes - `attrs.evolve()` doesn't accept the *inst* argument as a keyword argument anymore. Pass it as the first positional argument instead. [#​1264](https://redirect.github.com/python-attrs/attrs/issues/1264) - `attrs.validators.provides()` has been removed. The removed code is available as a [gist](https://gist.github.com/hynek/9eaaaeb659808f3519870dfa16d2b6b2) for convenient copy and pasting. [#​1265](https://redirect.github.com/python-attrs/attrs/issues/1265) - All packaging metadata except from `__version__` and `__version_info__` has been removed from the `attr` and `attrs` modules (for example, `attrs.__url__`). Please use [`importlib.metadata`](https://docs.python.org/3/library/importlib.metadata.html) or [*importlib-metadata*](https://pypi.org/project/importlib-metadata/) instead. [#​1268](https://redirect.github.com/python-attrs/attrs/issues/1268) - The generated `__eq__` methods have been sped up significantly by generating a chain of attribute comparisons instead of constructing and comparing tuples. This change arguably makes the behavior more correct, but changes it if an attribute compares equal by identity but not value, like `float('nan')`. [#​1310](https://redirect.github.com/python-attrs/attrs/issues/1310) ##### Deprecations - The *repr_ns* argument to `attr.s` is now deprecated. It was a workaround for nested classes in Python 2 and is pointless in Python 3. [#​1263](https://redirect.github.com/python-attrs/attrs/issues/1263) - The *hash* argument to `@attr.s`, `@attrs.define`, and `make_class()` is now deprecated in favor of *unsafe_hash*, as defined by PEP 681. [#​1323](https://redirect.github.com/python-attrs/attrs/issues/1323) ##### Changes - Allow original slotted `functools.cached_property` classes to be cleaned by garbage collection. Allow `super()` calls in slotted cached properties. [#​1221](https://redirect.github.com/python-attrs/attrs/issues/1221) - Our type stubs now use modern type notation and are organized such that VS Code's quick-fix prefers the `attrs` namespace. [#​1234](https://redirect.github.com/python-attrs/attrs/issues/1234) - Preserve `AttributeError` raised by properties of slotted classes with `functools.cached_properties`. [#​1253](https://redirect.github.com/python-attrs/attrs/issues/1253) - It is now possible to wrap a converter into an `attrs.Converter` and get the current instance and/or the current field definition passed into the converter callable. Note that this is not supported by any type checker, yet. [#​1267](https://redirect.github.com/python-attrs/attrs/issues/1267) - `attrs.make_class()` now populates the `__annotations__` dict of the generated class, so that `attrs.resolve_types()` can resolve them. [#​1285](https://redirect.github.com/python-attrs/attrs/issues/1285) - Added the `attrs.validators.or_()` validator. [#​1303](https://redirect.github.com/python-attrs/attrs/issues/1303) - The combination of a `__attrs_pre_init__` that takes arguments, a kw-only field, and a default on that field does not crash anymore. [#​1319](https://redirect.github.com/python-attrs/attrs/issues/1319) - `attrs.validators.in_()` now transforms certain unhashable options to tuples to keep the field hashable. This allows fields that use this validator to be used with, for example, `attrs.filters.include()`. [#​1320](https://redirect.github.com/python-attrs/attrs/issues/1320) - If a class has an *inherited* method called `__attrs_init_subclass__`, it is now called once the class is done assembling. This is a replacement for Python's `__init_subclass__` and useful for registering classes, and similar. [#​1321](https://redirect.github.com/python-attrs/attrs/issues/1321) ### [`v23.2.0`](https://redirect.github.com/python-attrs/attrs/blob/HEAD/CHANGELOG.md#2320---2023-12-31) [Compare Source](https://redirect.github.com/python-attrs/attrs/compare/23.1.0...23.2.0) ##### Changes - The type annotation for `attrs.resolve_types()` is now correct. [#​1141](https://redirect.github.com/python-attrs/attrs/issues/1141) - Type stubs now use `typing.dataclass_transform` to decorate dataclass-like decorators, instead of the non-standard `__dataclass_transform__` special form, which is only supported by Pyright. [#​1158](https://redirect.github.com/python-attrs/attrs/issues/1158) - Fixed serialization of namedtuple fields using `attrs.asdict/astuple()` with `retain_collection_types=True`. [#​1165](https://redirect.github.com/python-attrs/attrs/issues/1165) - `attrs.AttrsInstance` is now a `typing.Protocol` in both type hints and code. This allows you to subclass it along with another `Protocol`. [#​1172](https://redirect.github.com/python-attrs/attrs/issues/1172) - If *attrs* detects that `__attrs_pre_init__` accepts more than just `self`, it will call it with the same arguments as `__init__` was called. This allows you to, for example, pass arguments to `super().__init__()`. [#​1187](https://redirect.github.com/python-attrs/attrs/issues/1187) - Slotted classes now transform `functools.cached_property` decorated methods to support equivalent semantics. [#​1200](https://redirect.github.com/python-attrs/attrs/issues/1200) - Added *class_body* argument to `attrs.make_class()` to provide additional attributes for newly created classes. It is, for example, now possible to attach methods. [#​1203](https://redirect.github.com/python-attrs/attrs/issues/1203) ### [`v23.1.0`](https://redirect.github.com/python-attrs/attrs/blob/HEAD/CHANGELOG.md#2310---2023-04-16) [Compare Source](https://redirect.github.com/python-attrs/attrs/compare/22.2.0...23.1.0) ##### Backwards-incompatible Changes - Python 3.6 has been dropped and packaging switched to static package data using [Hatch](https://hatch.pypa.io/latest/). [#​993](https://redirect.github.com/python-attrs/attrs/issues/993) ##### Deprecations - The support for *zope-interface* via the `attrs.validators.provides` validator is now deprecated and will be removed in, or after, April 2024. The presence of a C-based package in our developement dependencies has caused headaches and we're not under the impression it's used a lot. Let us know if you're using it and we might publish it as a separate package. [#​1120](https://redirect.github.com/python-attrs/attrs/issues/1120) ##### Changes - `attrs.filters.exclude()` and `attrs.filters.include()` now support the passing of attribute names as strings. [#​1068](https://redirect.github.com/python-attrs/attrs/issues/1068) - `attrs.has()` and `attrs.fields()` now handle generic classes correctly. [#​1079](https://redirect.github.com/python-attrs/attrs/issues/1079) - Fix frozen exception classes when raised within e.g. `contextlib.contextmanager`, which mutates their `__traceback__` attributes. [#​1081](https://redirect.github.com/python-attrs/attrs/issues/1081) - `@frozen` now works with type checkers that implement [PEP-681](https://peps.python.org/pep-0681/) (ex. [pyright](https://redirect.github.com/microsoft/pyright/)). [#​1084](https://redirect.github.com/python-attrs/attrs/issues/1084) - Restored ability to unpickle instances pickled before 22.2.0. [#​1085](https://redirect.github.com/python-attrs/attrs/issues/1085) - `attrs.asdict()`'s and `attrs.astuple()`'s type stubs now accept the `attrs.AttrsInstance` protocol. [#​1090](https://redirect.github.com/python-attrs/attrs/issues/1090) - Fix slots class cellvar updating closure in CPython 3.8+ even when `__code__` introspection is unavailable. [#​1092](https://redirect.github.com/python-attrs/attrs/issues/1092) - `attrs.resolve_types()` can now pass `include_extras` to `typing.get_type_hints()` on Python 3.9+, and does so by default. [#​1099](https://redirect.github.com/python-attrs/attrs/issues/1099) - Added instructions for pull request workflow to `CONTRIBUTING.md`. [#​1105](https://redirect.github.com/python-attrs/attrs/issues/1105) - Added *type* parameter to `attrs.field()` function for use with `attrs.make_class()`. Please note that type checkers ignore type metadata passed into `make_class()`, but it can be useful if you're wrapping *attrs*. [#​1107](https://redirect.github.com/python-attrs/attrs/issues/1107) - It is now possible for `attrs.evolve()` (and `attr.evolve()`) to change fields named `inst` if the instance is passed as a positional argument. Passing the instance using the `inst` keyword argument is now deprecated and will be removed in, or after, April 2024. [#​1117](https://redirect.github.com/python-attrs/attrs/issues/1117) - `attrs.validators.optional()` now also accepts a tuple of validators (in addition to lists of validators). [#​1122](https://redirect.github.com/python-attrs/attrs/issues/1122)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b93316625e8e..342c6696b432 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -8,9 +8,9 @@ argcomplete==2.1.2 \ --hash=sha256:4ba9cdaa28c361d251edce884cd50b4b1215d65cdc881bd204426cdde9f52731 \ --hash=sha256:fc82ef070c607b1559b5c720529d63b54d9dcf2dcfc2632b10e6372314a34457 # via nox -attrs==22.2.0 \ - --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \ - --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99 +attrs==24.2.0 \ + --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ + --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 # via gcp-releasetool bleach==6.2.0 \ --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e \ From a64fed365e300c59a0bbf67c729a952b6ac2206f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:02:19 +0100 Subject: [PATCH 271/582] chore(deps): update dependency more-itertools to v10 (#470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [more-itertools](https://redirect.github.com/more-itertools/more-itertools) | `==8.14.0` -> `==10.5.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/more-itertools/10.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/more-itertools/10.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/more-itertools/8.14.0/10.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/more-itertools/8.14.0/10.5.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
more-itertools/more-itertools (more-itertools) ### [`v10.5.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.5.0) [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v10.4.0...v10.5.0) ##### What's Changed - Optimize all_equal recipe by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/899](https://redirect.github.com/more-itertools/more-itertools/pull/899) - Reduce groupby.**next** calls in all_equal by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/903](https://redirect.github.com/more-itertools/more-itertools/pull/903) - Fix types.UnionType by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/905](https://redirect.github.com/more-itertools/more-itertools/pull/905) - Version 10.5.0 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/906](https://redirect.github.com/more-itertools/more-itertools/pull/906) **Full Changelog**: https://togithub.com/more-itertools/more-itertools/compare/v10.4.0...v10.5.0 ### [`v10.4.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.4.0): Version 10.4.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v10.3.0...v10.4.0) ##### What's Changed - Issue 854: sample improvements by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/855](https://redirect.github.com/more-itertools/more-itertools/pull/855) - Issue 858: Use chain and starmap in run_length.decode by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/861](https://redirect.github.com/more-itertools/more-itertools/pull/861) - Issue 859: Update totient recipe by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/860](https://redirect.github.com/more-itertools/more-itertools/pull/860) - Distinct permutations of incomparable items by [@​JamesParrott](https://redirect.github.com/JamesParrott) in [https://togithub.com/more-itertools/more-itertools/pull/834](https://redirect.github.com/more-itertools/more-itertools/pull/834) - Clarify seekable.relative_seek behavior by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/863](https://redirect.github.com/more-itertools/more-itertools/pull/863) - Issue 864: Improve \_sample_unweighted by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/865](https://redirect.github.com/more-itertools/more-itertools/pull/865) - Use log1p for \_sample_unweighted by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/868](https://redirect.github.com/more-itertools/more-itertools/pull/868) - Issue 862: change relative_seek() behaviour by [@​dkrikun](https://redirect.github.com/dkrikun) in [https://togithub.com/more-itertools/more-itertools/pull/866](https://redirect.github.com/more-itertools/more-itertools/pull/866) - Issue 876: is_sorted clarifications by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/877](https://redirect.github.com/more-itertools/more-itertools/pull/877) - Issue 870: counts parameter for sample by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/875](https://redirect.github.com/more-itertools/more-itertools/pull/875) - Issue 869: Add a steps argument to circular_shifts by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/874](https://redirect.github.com/more-itertools/more-itertools/pull/874) - Issue 871: Add a fast path for sliding_window by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/873](https://redirect.github.com/more-itertools/more-itertools/pull/873) - type annotation of `windowed_complete` corrected by [@​m472](https://redirect.github.com/m472) in [https://togithub.com/more-itertools/more-itertools/pull/881](https://redirect.github.com/more-itertools/more-itertools/pull/881) - \[Docs] Fix strictly_n missing the n parameter by [@​fakuivan](https://redirect.github.com/fakuivan) in [https://togithub.com/more-itertools/more-itertools/pull/886](https://redirect.github.com/more-itertools/more-itertools/pull/886) - Standardize type hints for isinstance's second argument by [@​jbosboom](https://redirect.github.com/jbosboom) in [https://togithub.com/more-itertools/more-itertools/pull/887](https://redirect.github.com/more-itertools/more-itertools/pull/887) - Issue 883: change type hint by [@​akisatoon1](https://redirect.github.com/akisatoon1) in [https://togithub.com/more-itertools/more-itertools/pull/884](https://redirect.github.com/more-itertools/more-itertools/pull/884) - Add type overloads for `zip_broadcast` by [@​Pandede](https://redirect.github.com/Pandede) in [https://togithub.com/more-itertools/more-itertools/pull/888](https://redirect.github.com/more-itertools/more-itertools/pull/888) - Issue 889: Optimize triplewise by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/891](https://redirect.github.com/more-itertools/more-itertools/pull/891) - Add option `strict` to `sort_together` by [@​Pandede](https://redirect.github.com/Pandede) in [https://togithub.com/more-itertools/more-itertools/pull/892](https://redirect.github.com/more-itertools/more-itertools/pull/892) - Updates for version 10.4.0 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/893](https://redirect.github.com/more-itertools/more-itertools/pull/893) ##### New Contributors - [@​JamesParrott](https://redirect.github.com/JamesParrott) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/834](https://redirect.github.com/more-itertools/more-itertools/pull/834) - [@​dkrikun](https://redirect.github.com/dkrikun) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/866](https://redirect.github.com/more-itertools/more-itertools/pull/866) - [@​m472](https://redirect.github.com/m472) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/881](https://redirect.github.com/more-itertools/more-itertools/pull/881) - [@​fakuivan](https://redirect.github.com/fakuivan) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/886](https://redirect.github.com/more-itertools/more-itertools/pull/886) - [@​jbosboom](https://redirect.github.com/jbosboom) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/887](https://redirect.github.com/more-itertools/more-itertools/pull/887) - [@​akisatoon1](https://redirect.github.com/akisatoon1) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/884](https://redirect.github.com/more-itertools/more-itertools/pull/884) - [@​Pandede](https://redirect.github.com/Pandede) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/888](https://redirect.github.com/more-itertools/more-itertools/pull/888) **Full Changelog**: https://togithub.com/more-itertools/more-itertools/compare/v10.3.0...v10.4.0 ### [`v10.3.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.3.0): Version 10.3.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v10.2.0...v10.3.0) #### What's Changed - 100% Code Coverage by [@​haukex](https://redirect.github.com/haukex) in [https://togithub.com/more-itertools/more-itertools/pull/792](https://redirect.github.com/more-itertools/more-itertools/pull/792) - Remove recursion from `collapse` by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/796](https://redirect.github.com/more-itertools/more-itertools/pull/796) - Closes [#​780](https://redirect.github.com/more-itertools/more-itertools/issues/780): add pre/postpend examples in value_chain doc by [@​bjrtx](https://redirect.github.com/bjrtx) in [https://togithub.com/more-itertools/more-itertools/pull/802](https://redirect.github.com/more-itertools/more-itertools/pull/802) - Increase performance of `padded` by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/805](https://redirect.github.com/more-itertools/more-itertools/pull/805) - Update table of contents by [@​bjrtx](https://redirect.github.com/bjrtx) in [https://togithub.com/more-itertools/more-itertools/pull/808](https://redirect.github.com/more-itertools/more-itertools/pull/808) - Add exactly size of n doc to padded by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/807](https://redirect.github.com/more-itertools/more-itertools/pull/807) - Speed up `ichunked` by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/793](https://redirect.github.com/more-itertools/more-itertools/pull/793) - Optimize `chunked_even` itertool by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/816](https://redirect.github.com/more-itertools/more-itertools/pull/816) - Optimize windowed itertool by [@​james-wasson](https://redirect.github.com/james-wasson) in [https://togithub.com/more-itertools/more-itertools/pull/810](https://redirect.github.com/more-itertools/more-itertools/pull/810) - Issue 822: update iter_index docs by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/827](https://redirect.github.com/more-itertools/more-itertools/pull/827) - Issue 823: improve totient by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/826](https://redirect.github.com/more-itertools/more-itertools/pull/826) - Issue 821: key argument for all_equal by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/825](https://redirect.github.com/more-itertools/more-itertools/pull/825) - Update roundrobin implementation by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/829](https://redirect.github.com/more-itertools/more-itertools/pull/829) - Issue 820: add powerset_of_sets by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/828](https://redirect.github.com/more-itertools/more-itertools/pull/828) - Fix a typo found by codespell by [@​DimitriPapadopoulos](https://redirect.github.com/DimitriPapadopoulos) in [https://togithub.com/more-itertools/more-itertools/pull/830](https://redirect.github.com/more-itertools/more-itertools/pull/830) - Add typing for countable.items_seen attribute. by [@​aidanholm](https://redirect.github.com/aidanholm) in [https://togithub.com/more-itertools/more-itertools/pull/836](https://redirect.github.com/more-itertools/more-itertools/pull/836) - Add join_mappings by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/841](https://redirect.github.com/more-itertools/more-itertools/pull/841) - Add doublestarmap (closes [#​679](https://redirect.github.com/more-itertools/more-itertools/issues/679)) by [@​monk-time](https://redirect.github.com/monk-time) in [https://togithub.com/more-itertools/more-itertools/pull/845](https://redirect.github.com/more-itertools/more-itertools/pull/845) - Add dft and idft by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/847](https://redirect.github.com/more-itertools/more-itertools/pull/847) - Changes for version 10.3.0 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/851](https://redirect.github.com/more-itertools/more-itertools/pull/851) - Add unique() by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/850](https://redirect.github.com/more-itertools/more-itertools/pull/850) #### New Contributors - [@​james-wasson](https://redirect.github.com/james-wasson) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/796](https://redirect.github.com/more-itertools/more-itertools/pull/796) - [@​bjrtx](https://redirect.github.com/bjrtx) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/802](https://redirect.github.com/more-itertools/more-itertools/pull/802) - [@​aidanholm](https://redirect.github.com/aidanholm) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/836](https://redirect.github.com/more-itertools/more-itertools/pull/836) - [@​monk-time](https://redirect.github.com/monk-time) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/845](https://redirect.github.com/more-itertools/more-itertools/pull/845) **Full Changelog**: https://togithub.com/more-itertools/more-itertools/compare/v10.2.0...v10.3.0 ### [`v10.2.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.2.0): Version 10.2.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v10.1.0...v10.2.0) - New functions - `iter_suppress` (thanks to jaraco, pochmann, and rhettinger) - `filter_map` (thanks to struktured) - `classify_unique` (thanks to haukex) - `totient` (from the itertools docs) - `reshape` (from the itertools docs) - Changes to existing functions - `factor`, `iter_index`, `sieve`, and `unique_justseen` were updated to match the itertools docs - `first` was was optimized (thanks to pochmann) - `takewhile_inclusive` was was refactored (thanks to eltoder) - `combination_with_replacement_index` was was optimized (thanks to elliotwutingfeng and rhettinger) - `nth_permutation`, `nth_combination_with_replacement`, `combination_index`, and `combination_with_replacement_index` were optimized (thanks to rhettinger) - `batched` now accepts a `strict` argument (adapted from itertools docs) - `time_limited` was improved for Windows (thanks to haukex) - Other changes - Several typing updates were made (thanks to obaltian and ilai-deutel) - Some documentation issues were fixed (thanks to F-park, DimitriPapadopoulos, peterbygrave, shuuji3, eltoder, and homeworkprod) ### [`v10.1.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.1.0): Version 10.1.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v10.0.0...v10.1.0) #### What's Changed - Add more tests for `zip_broadcast()` by [@​kalekundert](https://redirect.github.com/kalekundert) in [https://togithub.com/more-itertools/more-itertools/pull/739](https://redirect.github.com/more-itertools/more-itertools/pull/739) - Added takewhile_inclusive by [@​OlegAlexander](https://redirect.github.com/OlegAlexander) in [https://togithub.com/more-itertools/more-itertools/pull/736](https://redirect.github.com/more-itertools/more-itertools/pull/736) - Speed up `zip_broadcast()` by pre-filling the scalar elements by [@​kalekundert](https://redirect.github.com/kalekundert) in [https://togithub.com/more-itertools/more-itertools/pull/740](https://redirect.github.com/more-itertools/more-itertools/pull/740) - Added outer_product. by [@​OlegAlexander](https://redirect.github.com/OlegAlexander) in [https://togithub.com/more-itertools/more-itertools/pull/743](https://redirect.github.com/more-itertools/more-itertools/pull/743) - Simplify `zip_broadcast` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/742](https://redirect.github.com/more-itertools/more-itertools/pull/742) - Simplify `_zip_equal` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/744](https://redirect.github.com/more-itertools/more-itertools/pull/744) - fix consume() type annotation by [@​obaltian](https://redirect.github.com/obaltian) in [https://togithub.com/more-itertools/more-itertools/pull/746](https://redirect.github.com/more-itertools/more-itertools/pull/746) - Version 10.1.0 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/747](https://redirect.github.com/more-itertools/more-itertools/pull/747) #### New Contributors - [@​OlegAlexander](https://redirect.github.com/OlegAlexander) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/736](https://redirect.github.com/more-itertools/more-itertools/pull/736) - [@​obaltian](https://redirect.github.com/obaltian) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/746](https://redirect.github.com/more-itertools/more-itertools/pull/746) **Full Changelog**: https://togithub.com/more-itertools/more-itertools/compare/v10.0.1...v10.1.0 ### [`v10.0.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v10.0.0): Version 10.0.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v9.1.0...v10.0.0) #### What's Changed - Update recipes.iter_index to match CPython PR 102360 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/690](https://redirect.github.com/more-itertools/more-itertools/pull/690) - fixup - add missing commas to the readme function table by [@​lonnen](https://redirect.github.com/lonnen) in [https://togithub.com/more-itertools/more-itertools/pull/692](https://redirect.github.com/more-itertools/more-itertools/pull/692) - fixup remove 3.6 from tox by [@​lonnen](https://redirect.github.com/lonnen) in [https://togithub.com/more-itertools/more-itertools/pull/693](https://redirect.github.com/more-itertools/more-itertools/pull/693) - seekable: Add relative_seek by [@​karlb](https://redirect.github.com/karlb) in [https://togithub.com/more-itertools/more-itertools/pull/694](https://redirect.github.com/more-itertools/more-itertools/pull/694) - Optimize \_chunked_even_finite() by [@​elliotwutingfeng](https://redirect.github.com/elliotwutingfeng) in [https://togithub.com/more-itertools/more-itertools/pull/699](https://redirect.github.com/more-itertools/more-itertools/pull/699) - Indexing of combinations with replacement by [@​Schoyen](https://redirect.github.com/Schoyen) in [https://togithub.com/more-itertools/more-itertools/pull/689](https://redirect.github.com/more-itertools/more-itertools/pull/689) - Add notes for transposing empty inputs by [@​XuehaiPan](https://redirect.github.com/XuehaiPan) in [https://togithub.com/more-itertools/more-itertools/pull/700](https://redirect.github.com/more-itertools/more-itertools/pull/700) - Add the polynomial_eval recipe by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/703](https://redirect.github.com/more-itertools/more-itertools/pull/703) - Add nth_combination_with_replacement by [@​Schoyen](https://redirect.github.com/Schoyen) in [https://togithub.com/more-itertools/more-itertools/pull/704](https://redirect.github.com/more-itertools/more-itertools/pull/704) - Add sum_of_squares, sync with itertools by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/706](https://redirect.github.com/more-itertools/more-itertools/pull/706) - Issue [#​707](https://redirect.github.com/more-itertools/more-itertools/issues/707): fix `iterate()` to enable `func` to raise StopIteration + 3 unittests by [@​jrebiffe](https://redirect.github.com/jrebiffe) in [https://togithub.com/more-itertools/more-itertools/pull/708](https://redirect.github.com/more-itertools/more-itertools/pull/708) - Update polynomial_from roots and convolve by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/709](https://redirect.github.com/more-itertools/more-itertools/pull/709) - Issue [#​677](https://redirect.github.com/more-itertools/more-itertools/issues/677): Improve `partition` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/710](https://redirect.github.com/more-itertools/more-itertools/pull/710) - Issue [#​713](https://redirect.github.com/more-itertools/more-itertools/issues/713): Fix `partial_product` (also simplify and clean up) by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/714](https://redirect.github.com/more-itertools/more-itertools/pull/714) - Issue [#​711](https://redirect.github.com/more-itertools/more-itertools/issues/711): Optimize `pairwise` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/712](https://redirect.github.com/more-itertools/more-itertools/pull/712) - Issue [#​715](https://redirect.github.com/more-itertools/more-itertools/issues/715): Simplify/optimize `partial_product` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/716](https://redirect.github.com/more-itertools/more-itertools/pull/716) - Issue [#​717](https://redirect.github.com/more-itertools/more-itertools/issues/717): Improve `duplicates_justseen` by [@​pochmann](https://redirect.github.com/pochmann) in [https://togithub.com/more-itertools/more-itertools/pull/718](https://redirect.github.com/more-itertools/more-itertools/pull/718) - Fix unique_in_window to match described behavior by [@​elliotwutingfeng](https://redirect.github.com/elliotwutingfeng) in [https://togithub.com/more-itertools/more-itertools/pull/720](https://redirect.github.com/more-itertools/more-itertools/pull/720) - Add polynomial_derivative recipe by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/723](https://redirect.github.com/more-itertools/more-itertools/pull/723) - Update recipes with CPython PRs: 105403 and 106371 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/731](https://redirect.github.com/more-itertools/more-itertools/pull/731) - Changes for version 10.0.0 by [@​bbayles](https://redirect.github.com/bbayles) in [https://togithub.com/more-itertools/more-itertools/pull/734](https://redirect.github.com/more-itertools/more-itertools/pull/734) - Delay computation of numeric_range len until needed by [@​eltoder](https://redirect.github.com/eltoder) in [https://togithub.com/more-itertools/more-itertools/pull/674](https://redirect.github.com/more-itertools/more-itertools/pull/674) #### New Contributors - [@​karlb](https://redirect.github.com/karlb) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/694](https://redirect.github.com/more-itertools/more-itertools/pull/694) - [@​elliotwutingfeng](https://redirect.github.com/elliotwutingfeng) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/699](https://redirect.github.com/more-itertools/more-itertools/pull/699) - [@​Schoyen](https://redirect.github.com/Schoyen) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/689](https://redirect.github.com/more-itertools/more-itertools/pull/689) - [@​XuehaiPan](https://redirect.github.com/XuehaiPan) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/700](https://redirect.github.com/more-itertools/more-itertools/pull/700) - [@​jrebiffe](https://redirect.github.com/jrebiffe) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/708](https://redirect.github.com/more-itertools/more-itertools/pull/708) - [@​pochmann](https://redirect.github.com/pochmann) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/710](https://redirect.github.com/more-itertools/more-itertools/pull/710) - [@​eltoder](https://redirect.github.com/eltoder) made their first contribution in [https://togithub.com/more-itertools/more-itertools/pull/674](https://redirect.github.com/more-itertools/more-itertools/pull/674) **Full Changelog**: https://togithub.com/more-itertools/more-itertools/compare/v9.1.1...v10.0.0 ### [`v9.1.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v9.1.0): Version 9.1.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v9.0.0...v9.1.0) See PR [#​678](https://redirect.github.com/more-itertools/more-itertools/issues/678) for details. ### [`v9.0.0`](https://redirect.github.com/more-itertools/more-itertools/releases/tag/v9.0.0): Version 9.0.0 [Compare Source](https://redirect.github.com/more-itertools/more-itertools/compare/v8.14.0...v9.0.0) See PR [#​647](https://redirect.github.com/more-itertools/more-itertools/issues/647) for details
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 342c6696b432..5a7a096f36e4 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -459,9 +459,9 @@ MarkupSafe==2.1.5 \ --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 # via jinja2 -more-itertools==8.14.0 \ - --hash=sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2 \ - --hash=sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750 +more-itertools==10.5.0 \ + --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ + --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 # via jaraco-classes nox==2022.8.7 \ --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ From 78f4a9a419fd33eb2d8456814f4c73415d5e4763 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:02:22 +0100 Subject: [PATCH 272/582] chore(deps): update dependency wheel to v0.44.0 (#459) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [wheel](https://redirect.github.com/pypa/wheel) ([changelog](https://wheel.readthedocs.io/en/stable/news.html)) | `==0.38.1` -> `==0.44.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/wheel/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/wheel/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/wheel/0.38.1/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/wheel/0.38.1/0.44.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
pypa/wheel (wheel) ### [`v0.44.0`](https://redirect.github.com/pypa/wheel/releases/tag/0.44.0) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.43.0...0.44.0) - Canonicalized requirements in METADATA file (PR by Wim Jeantine-Glenn) - Deprecated the `bdist_wheel` module, as the code was migrated to `setuptools` itself ### [`v0.43.0`](https://redirect.github.com/pypa/wheel/releases/tag/0.43.0) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.42.0...0.43.0) - Dropped support for Python 3.7 - Updated vendored `packaging` to 24.0 ### [`v0.42.0`](https://redirect.github.com/pypa/wheel/releases/tag/0.42.0) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.41.3...0.42.0) - Allowed removing build tag with `wheel tags --build ""` - Fixed `wheel pack` and `wheel tags` writing updated `WHEEL` fields after a blank line, causing other tools to ignore them - Fixed `wheel pack` and `wheel tags` writing `WHEEL` with CRLF line endings or a mix of CRLF and LF - Fixed `wheel pack --build-number ""` not removing build tag from `WHEEL` (above changes by Benjamin Gilbert) ### [`v0.41.3`](https://redirect.github.com/pypa/wheel/releases/tag/0.41.3) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.41.2...0.41.3) - Updated vendored `packaging` to 23.2 - Fixed ABI tag generation for CPython 3.13a1 on Windows (PR by Sam Gross) ### [`v0.41.2`](https://redirect.github.com/pypa/wheel/compare/0.41.1...0.41.2) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.41.1...0.41.2) ### [`v0.41.1`](https://redirect.github.com/pypa/wheel/compare/0.41.0...0.41.1) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.41.0...0.41.1) ### [`v0.41.0`](https://redirect.github.com/pypa/wheel/compare/0.40.0...0.41.0) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.40.0...0.41.0) ### [`v0.40.0`](https://redirect.github.com/pypa/wheel/compare/0.38.4...0.40.0) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.38.4...0.40.0) ### [`v0.38.4`](https://redirect.github.com/pypa/wheel/compare/0.38.3...0.38.4) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.38.3...0.38.4) ### [`v0.38.3`](https://redirect.github.com/pypa/wheel/compare/0.38.2...0.38.3) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.38.2...0.38.3) ### [`v0.38.2`](https://redirect.github.com/pypa/wheel/compare/0.38.1...0.38.2) [Compare Source](https://redirect.github.com/pypa/wheel/compare/0.38.1...0.38.2)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 5a7a096f36e4..fca26acecb34 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -611,9 +611,9 @@ webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach -wheel==0.38.1 \ - --hash=sha256:7a95f9a8dc0924ef318bd55b616112c70903192f524d120acc614f59547a9e1f \ - --hash=sha256:ea041edf63f4ccba53ad6e035427997b3bb10ee88a4cd014ae82aeb9eea77bb9 +wheel==0.44.0 \ + --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ + --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 # via -r requirements.in zipp==3.19.1 \ --hash=sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091 \ From 8a17269830fe78d01ef5ae32c78a03471ad90794 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:02:25 +0100 Subject: [PATCH 273/582] chore(deps): update dependency python-dateutil to v2.9.0.post0 (#455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [python-dateutil](https://redirect.github.com/dateutil/dateutil) | `==2.8.2` -> `==2.9.0.post0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/python-dateutil/2.9.0.post0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/python-dateutil/2.9.0.post0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/python-dateutil/2.8.2/2.9.0.post0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/python-dateutil/2.8.2/2.9.0.post0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
dateutil/dateutil (python-dateutil) ### [`v2.9.0.post0`](https://redirect.github.com/dateutil/dateutil/releases/tag/2.9.0.post0) [Compare Source](https://redirect.github.com/dateutil/dateutil/compare/2.9.0...2.9.0.post0) ### Version 2.9.0.post0 (2024-03-01) #### Bugfixes - Pinned `setuptools_scm` to `<8`, which should make the generated `_version.py` file compatible with all supported versions of Python. ### [`v2.9.0`](https://redirect.github.com/dateutil/dateutil/releases/tag/2.9.0) [Compare Source](https://redirect.github.com/dateutil/dateutil/compare/2.8.2...2.9.0) ### Version 2.9.0 (2024-02-29) #### Data updates - Updated tzdata version to 2024a. (gh pr [#​1342](https://redirect.github.com/dateutil/dateutil/issues/1342)) #### Features - Made all `dateutil` submodules lazily imported using [PEP 562](https://www.python.org/dev/peps/pep-0562/). On Python 3.7+, things like `import dateutil; dateutil.tz.gettz("America/New_York")` will now work without explicitly importing `dateutil.tz`, with the import occurring behind the scenes on first use. The old behavior remains on Python 3.6 and earlier. Fixed by Orson Adams. (gh issue [#​771](https://redirect.github.com/dateutil/dateutil/issues/771), gh pr [#​1007](https://redirect.github.com/dateutil/dateutil/issues/1007)) #### Bugfixes - Removed a call to `datetime.utcfromtimestamp`, which is deprecated as of Python 3.12. Reported by Hugo van Kemenade (gh pr [#​1284](https://redirect.github.com/dateutil/dateutil/issues/1284)), fixed by Thomas Grainger (gh pr [#​1285](https://redirect.github.com/dateutil/dateutil/issues/1285)). #### Documentation changes - Added note into docs and tests where relativedelta would return last day of the month only if the same day on a different month resolves to a date that doesn't exist. Reported by [@​hawkEye-01](https://redirect.github.com/hawkEye-01) (gh issue [#​1167](https://redirect.github.com/dateutil/dateutil/issues/1167)). Fixed by [@​Mifrill](https://redirect.github.com/Mifrill) (gh pr [#​1168](https://redirect.github.com/dateutil/dateutil/issues/1168))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index fca26acecb34..3c7491088e6d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -544,9 +544,9 @@ pyparsing==3.0.9 \ pyperclip==1.8.2 \ --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 # via gcp-releasetool -python-dateutil==2.8.2 \ - --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ - --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 +python-dateutil==2.9.0.post0 \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 # via gcp-releasetool readme-renderer==37.2 \ --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ From 9f9f1416baf768d116867d6528f45764907e56ce Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:03:07 +0100 Subject: [PATCH 274/582] chore(deps): update dependency markupsafe to v3 (#469) --- .../.kokoro/requirements.txt | 123 +++++++++--------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3c7491088e6d..3fbfe292411a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -397,67 +397,68 @@ keyring==23.9.3 \ # via # gcp-releasetool # twine -MarkupSafe==2.1.5 \ - --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ - --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ - --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ - --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ - --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ - --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ - --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ - --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ - --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ - --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ - --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ - --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ - --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ - --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ - --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ - --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ - --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ - --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ - --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ - --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ - --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ - --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ - --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ - --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ - --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ - --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ - --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ - --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ - --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ - --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ - --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ - --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ - --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ - --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ - --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ - --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ - --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ - --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ - --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ - --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ - --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ - --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ - --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ - --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ - --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ - --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ - --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ - --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ - --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ - --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ - --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ - --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ - --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ - --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ - --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ - --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ - --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ - --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ - --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ - --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 +MarkupSafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via jinja2 more-itertools==10.5.0 \ --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ From e210c784da6881e19bd282e909eaf920616dc660 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:03:24 +0100 Subject: [PATCH 275/582] chore(deps): update actions/setup-python action to v5 (#462) --- .../.github/workflows/test_suite.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index d79b89dd163b..21606df0f8d1 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install nox @@ -27,7 +27,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install nox @@ -45,7 +45,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install nox @@ -66,7 +66,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install nox @@ -90,7 +90,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install nox @@ -115,7 +115,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install nox @@ -139,7 +139,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install nox @@ -163,7 +163,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install nox From eede1e16c8b7b208b2a0416687198efdd46ed869 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:03:38 +0100 Subject: [PATCH 276/582] chore(deps): update actions/checkout action to v4 (#461) --- .../.github/workflows/test_suite.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 21606df0f8d1..748378abc1c3 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -64,7 +64,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -88,7 +88,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -137,7 +137,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: @@ -161,7 +161,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: From 6643f4e66ce0adb1a3a2f2163d2e049746781c0e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:03:51 +0100 Subject: [PATCH 277/582] chore(deps): update dependency zipp to v3.20.2 (#460) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3fbfe292411a..3b9cbb7fe586 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -616,9 +616,9 @@ wheel==0.44.0 \ --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 # via -r requirements.in -zipp==3.19.1 \ - --hash=sha256:2828e64edb5386ea6a52e7ba7cdb17bb30a73a858f5eb6eb93d8d36f5ea26091 \ - --hash=sha256:35427f6d5594f4acf82d25541438348c26736fa9b3afa2754bcd63cdb99d8e8f +zipp==3.20.2 \ + --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ + --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be From 7cfd1aa5a53dc9c9d389f2dea702c77f3c2fa72a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:04:12 +0100 Subject: [PATCH 278/582] chore(deps): update dependency typing-extensions to v4.12.2 (#457) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3b9cbb7fe586..e5f35457b2da 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -594,9 +594,9 @@ twine==5.1.1 \ --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ --hash=sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db # via -r requirements.in -typing-extensions==4.8.0 \ - --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \ - --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via -r requirements.in urllib3==2.2.3 \ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ From c2328db2139d5b49ec9cafc0da7dafa835273230 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:04:23 +0100 Subject: [PATCH 279/582] chore(deps): update dependency pyperclip to v1.9.0 (#454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [pyperclip](https://redirect.github.com/asweigart/pyperclip) | `==1.8.2` -> `==1.9.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/pyperclip/1.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/pyperclip/1.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/pyperclip/1.8.2/1.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pyperclip/1.8.2/1.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e5f35457b2da..cc6d1840cd6e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -542,8 +542,8 @@ pyparsing==3.0.9 \ --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc # via packaging -pyperclip==1.8.2 \ - --hash=sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57 +pyperclip==1.9.0 \ + --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 # via gcp-releasetool python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ From 151441c064b3fbebf72bf641c71b81f44d83af49 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:04:26 +0100 Subject: [PATCH 280/582] chore(deps): update dependency pyjwt to v2.9.0 (#452) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [pyjwt](https://redirect.github.com/jpadilla/pyjwt) | `==2.6.0` -> `==2.9.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/pyjwt/2.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/pyjwt/2.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/pyjwt/2.6.0/2.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pyjwt/2.6.0/2.9.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
jpadilla/pyjwt (pyjwt) ### [`v2.9.0`](https://redirect.github.com/jpadilla/pyjwt/blob/HEAD/CHANGELOG.rst#Unreleased-httpsgithubcomjpadillapyjwtcompare290HEAD) [Compare Source](https://redirect.github.com/jpadilla/pyjwt/compare/2.8.0...2.9.0) Changed ``` Fixed ~~~~~ Added ~~~~~ ``` ### [`v2.8.0`](https://redirect.github.com/jpadilla/pyjwt/blob/HEAD/CHANGELOG.rst#v280-httpsgithubcomjpadillapyjwtcompare270280) [Compare Source](https://redirect.github.com/jpadilla/pyjwt/compare/2.7.0...2.8.0) Changed ``` - Update python version test matrix by @​auvipy in `#​895 `__ Fixed ~~~~~ Added ~~~~~ - Add ``strict_aud`` as an option to ``jwt.decode`` by @​woodruffw in `#​902 `__ - Export PyJWKClientConnectionError class by @​daviddavis in `#​887 `__ - Allows passing of ssl.SSLContext to PyJWKClient by @​juur in `#​891 `__ ``` ### [`v2.7.0`](https://redirect.github.com/jpadilla/pyjwt/blob/HEAD/CHANGELOG.rst#Unreleased-httpsgithubcomjpadillapyjwtcompare270HEAD) [Compare Source](https://redirect.github.com/jpadilla/pyjwt/compare/2.6.0...2.7.0) Changed ``` Fixed ~~~~~ Added ~~~~~ ```
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index cc6d1840cd6e..dd5866957a9b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -534,9 +534,9 @@ pygments==2.15.0 \ # via # readme-renderer # rich -pyjwt==2.6.0 \ - --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ - --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 +PyJWT==2.9.0 \ + --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ + --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c # via gcp-releasetool pyparsing==3.0.9 \ --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ From 16f4ca4ff53fb4112a2a447977d68ae0d80ccdca Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:04:36 +0100 Subject: [PATCH 281/582] chore(deps): update dependency readme-renderer to v37.3 (#456) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index dd5866957a9b..3c297c7a47dc 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -549,9 +549,9 @@ python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 # via gcp-releasetool -readme-renderer==37.2 \ - --hash=sha256:d3f06a69e8c40fca9ab3174eca48f96d9771eddb43517b17d96583418427b106 \ - --hash=sha256:e8ad25293c98f781dbc2c5a36a309929390009f902f99e1798c761aaf04a7923 +readme-renderer==37.3 \ + --hash=sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273 \ + --hash=sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343 # via twine requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ From ab379b5a79c0ecfd0e421a5affb39d1112f1ec45 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:04:50 +0100 Subject: [PATCH 282/582] chore(deps): update dependency pyparsing to v3.2.0 (#453) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3c297c7a47dc..f5738e0fdb59 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -538,9 +538,9 @@ PyJWT==2.9.0 \ --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c # via gcp-releasetool -pyparsing==3.0.9 \ - --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ - --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc +pyparsing==3.2.0 \ + --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ + --hash=sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c # via packaging pyperclip==1.9.0 \ --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 From 8d1b73f07714ad8945a1e0b3bf04ecdcff9342aa Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:05:06 +0100 Subject: [PATCH 283/582] chore(deps): update dependency pygments to v2.18.0 (#451) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f5738e0fdb59..87a318e316c7 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -528,9 +528,9 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pygments==2.15.0 \ - --hash=sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094 \ - --hash=sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500 +Pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via # readme-renderer # rich From 6ba76d2d7b97af0ed16f786f388217c1013c11c1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:05:22 +0100 Subject: [PATCH 284/582] chore(deps): update dependency platformdirs to v2.6.2 (#447) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 87a318e316c7..caabaaf09114 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -478,9 +478,9 @@ pkginfo==1.8.3 \ --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c # via twine -platformdirs==2.5.2 \ - --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ - --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 +platformdirs==2.6.2 \ + --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ + --hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2 # via virtualenv protobuf==3.20.3 \ --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ From 807a8a29d0a6d2a2559ec158b62854328f9aac89 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:08:24 +0100 Subject: [PATCH 285/582] chore(deps): update dependency pyasn1-modules to v0.4.1 (#449) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [pyasn1-modules](https://redirect.github.com/pyasn1/pyasn1-modules) ([changelog](https://redirect.github.com/pyasn1/pyasn1-modules/blob/master/CHANGES.txt)) | `==0.2.8` -> `==0.4.1` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/pyasn1-modules/0.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/pyasn1-modules/0.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/pyasn1-modules/0.2.8/0.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pyasn1-modules/0.2.8/0.4.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
pyasn1/pyasn1-modules (pyasn1-modules) ### [`v0.4.1`](https://redirect.github.com/pyasn1/pyasn1-modules/blob/HEAD/CHANGES.txt#Revision-041-released-10-09-2024) [Compare Source](https://redirect.github.com/pyasn1/pyasn1-modules/compare/v0.4.0...v0.4.1) - Added support for Python 3.13 ### [`v0.4.0`](https://redirect.github.com/pyasn1/pyasn1-modules/blob/HEAD/CHANGES.txt#Revision-040-released-26-03-2024) [Compare Source](https://redirect.github.com/pyasn1/pyasn1-modules/compare/v0.3.0...v0.4.0) - Added support for Python 3.11, 3.12 - Removed support for EOL Pythons 2.7, 3.6, 3.7 ### [`v0.3.0`](https://redirect.github.com/pyasn1/pyasn1-modules/blob/HEAD/CHANGES.txt#Revision-030-released-19-04-2023) [Compare Source](https://redirect.github.com/pyasn1/pyasn1-modules/compare/v0.2.8...v0.3.0) - Added support for Python 3.8, 3.9, 3.10, 3.11 - Removed support for EOL Pythons 2.4, 2.5, 2.6, 3.2, 3.3, 3.4, 3.5 - Added support for PyPy 3.7, 3.8, 3.9 - Modernized packaging and testing. pyasn1-modules now uses `setup.cfg`, `pyproject.toml`, [build](https://pypi.org/project/build/), and GitHub Actions. - PyPI package ownership for `pyasn1` and `pyasn1-module` has been transfered to *Christian Heimes* and *Simon Pichugin* in [PyPI support ticket #​2090](https://redirect.github.com/pypa/pypi-support/issues/2090). - The upstream repositories for `pyasn1` and `pyasn1-modules` are now in the GitHub organization https://togithub.com/pyasn1/. - Added tox runner with a handful of basic jobs - Add RFC3125 providing Electronic Signature Policies - Add RFC5126 providing CMS Advanced Electronic Signatures (CAdES) - Removed support for EOL Pythons 2.4, 2.5, 2.6, 3.2, 3.3 and 3.4. - Improve test routines for RFC5126 - Add RFC4387 providing Certificate Store Access via HTTP - Changed assertion in unit tests from Python built-in to `unittest` provided - Add RFC8692 providing Algorithm Identifiers for RSASSA-PSS and ECDSA Using SHAKEs - Add RFC5753 providing CMS Elliptic Curve Cryptography Algorithms - Add RFC3820 providing Proxy Certificates - Add RFC3370 providing Cryptographic Message Syntax (CMS) Algorithms - Add RFC3537 providing HMAC Key Wrapping - Add RFC3739 providing Qualified Certificates - Add RFC2876 providing KEA and SKIPJACK for CMS - Add RFC3058 providing IDEA Encryption Algorithm for CMS - Add RFC3657 providing Camellia Encryption Algorithm for CMS - Add RFC4010 providing SEED Encryption Algorithm for CMS - Add RFC4357 providing Additional Cryptographic Algorithms for Use with GOST 28147-89, GOST R 34.10-94, GOST R 34.10-2001, and GOST R 34.11-94 - Add RFC4490 providing GOST 28147-89, GOST R 34.11-94, GOST R 34.10-94, and GOST R 34.10-2001 Algorithms for CMS - Add RFC4491 providing GOST R 34.10-94, GOST R 34.10-2001, and GOST R 34.11-94 Algorithms for certificates and CRLs - Add RFC8696 providing using Pre-Shared Key (PSK) in the CMS - Add RFC5639 providing identifiers for the Brainpool curves in Elliptic Curve Cryptography - Add RFC5697 providing Other Certificates Extension - Add RFC4683 providing Subject Identification Method (SIM) - Add RFC4476 providing Attribute Certificate Policies Extension - Add RFC5636 providing Traceable Anonymous Certificate - Add RFC5752 providing Multiple Signatures attribute for CMS - Add RFC5275 providing CMS Symmetric Key Management and Distribution - Add RFC8702 providing SHAKE One-way Hash Functions in the CMS - Add RFC8708 providing HSS/LMS Hash-based Signature Algorithm for CMS - Advance copyright statement to year 2020 - Add RFC8769 providing CBOR and CBOR Sequence content types for CMS
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index caabaaf09114..6959d91661a7 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -520,9 +520,9 @@ pyasn1==0.4.8 \ # via # pyasn1-modules # rsa -pyasn1-modules==0.2.8 \ - --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ - --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 +pyasn1-modules==0.4.1 \ + --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ + --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c # via google-auth pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ From 1cacbd842e3d1c3a0eb261d30e054ae3202a6451 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:10:01 +0100 Subject: [PATCH 286/582] chore(deps): update dependency google-auth to v2.35.0 (#436) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 6959d91661a7..d1edafb431ec 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -273,9 +273,9 @@ google-api-core==2.10.2 \ # via # google-cloud-core # google-cloud-storage -google-auth==2.13.0 \ - --hash=sha256:9352dd6394093169157e6971526bab9a2799244d68a94a4a609f0dd751ef6f5e \ - --hash=sha256:99510e664155f1a3c0396a076b5deb6367c52ea04d280152c85ac7f51f50eb42 +google-auth==2.35.0 \ + --hash=sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f \ + --hash=sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a # via # gcp-releasetool # google-api-core From b9fe52a1f8997ec23f2c307f5b13ef2511c7e67c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:10:19 +0100 Subject: [PATCH 287/582] chore(deps): update dependency pycparser to v2.22 (#450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [pycparser](https://redirect.github.com/eliben/pycparser) | `==2.21` -> `==2.22` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/pycparser/2.22?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/pycparser/2.22?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/pycparser/2.21/2.22?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pycparser/2.21/2.22?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
eliben/pycparser (pycparser) ### [`v2.22`](https://redirect.github.com/eliben/pycparser/compare/release_v2.21...release_v2.22) [Compare Source](https://redirect.github.com/eliben/pycparser/compare/release_v2.21...release_v2.22)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d1edafb431ec..ec41f8e56b03 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -524,9 +524,9 @@ pyasn1-modules==0.4.1 \ --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c # via google-auth -pycparser==2.21 \ - --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ - --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 +pycparser==2.22 \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi Pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ From 545134b373bd6b136296fb130f7c1c68002291d8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:10:22 +0100 Subject: [PATCH 288/582] chore(deps): update dependency keyring to v23.13.1 (#444) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [keyring](https://redirect.github.com/jaraco/keyring) | `==23.9.3` -> `==23.13.1` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/keyring/23.13.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/keyring/23.13.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/keyring/23.9.3/23.13.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/keyring/23.9.3/23.13.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
jaraco/keyring (keyring) ### [`v23.13.1`](https://redirect.github.com/jaraco/keyring/compare/v23.13.0...v23.13.1) [Compare Source](https://redirect.github.com/jaraco/keyring/compare/v23.13.0...v23.13.1) ### [`v23.13.0`](https://redirect.github.com/jaraco/keyring/compare/v23.12.1...v23.13.0) [Compare Source](https://redirect.github.com/jaraco/keyring/compare/v23.12.1...v23.13.0) ### [`v23.12.1`](https://redirect.github.com/jaraco/keyring/compare/v23.11.0...v23.12.1) [Compare Source](https://redirect.github.com/jaraco/keyring/compare/v23.11.0...v23.12.1) ### [`v23.11.0`](https://redirect.github.com/jaraco/keyring/compare/v23.10.0...v23.11.0) [Compare Source](https://redirect.github.com/jaraco/keyring/compare/v23.10.0...v23.11.0) ### [`v23.10.0`](https://redirect.github.com/jaraco/keyring/compare/v23.9.3...v23.10.0) [Compare Source](https://redirect.github.com/jaraco/keyring/compare/v23.9.3...v23.10.0)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ec41f8e56b03..c331d0e56e4b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -391,9 +391,9 @@ jinja2==3.1.4 \ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d # via gcp-releasetool -keyring==23.9.3 \ - --hash=sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0 \ - --hash=sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5 +keyring==23.13.1 \ + --hash=sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd \ + --hash=sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678 # via # gcp-releasetool # twine From 65f517e9628a6c426843e454b2025ee3d5523bbc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:10:47 +0100 Subject: [PATCH 289/582] chore(deps): update dependency pkginfo to v1.11.2 (#446) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c331d0e56e4b..92c767569da3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -474,9 +474,9 @@ packaging==24.1 \ # via # gcp-releasetool # nox -pkginfo==1.8.3 \ - --hash=sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594 \ - --hash=sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c +pkginfo==1.11.2 \ + --hash=sha256:9ec518eefccd159de7ed45386a6bb4c6ca5fa2cb3bd9b71154fae44f6f1b36a3 \ + --hash=sha256:c6bc916b8298d159e31f2c216e35ee5b86da7da18874f879798d0a1983537c86 # via twine platformdirs==2.6.2 \ --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ From c92f8c46cbc5499af4264f7da83656f050749b40 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:10:59 +0100 Subject: [PATCH 290/582] chore(deps): update dependency nox to v2022.11.21 (#445) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 92c767569da3..1cdd41e8ced1 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -464,9 +464,9 @@ more-itertools==10.5.0 \ --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 # via jaraco-classes -nox==2022.8.7 \ - --hash=sha256:1b894940551dc5c389f9271d197ca5d655d40bdc6ccf93ed6880e4042760a34b \ - --hash=sha256:96cca88779e08282a699d672258ec01eb7c792d35bbbf538c723172bce23212c +nox==2022.11.21 \ + --hash=sha256:0e41a990e290e274cb205a976c4c97ee3c5234441a8132c8c3fd9ea3c22149eb \ + --hash=sha256:e21c31de0711d1274ca585a2c5fde36b1aa962005ba8e9322bf5eeed16dcd684 # via -r requirements.in packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ From 70fc3e34d16931d3a5050a80fd131ee80dc4cc55 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:11:16 +0100 Subject: [PATCH 291/582] chore(deps): update dependency idna to v3.10 (#442) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 1cdd41e8ced1..a0332cd8749b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -367,9 +367,9 @@ googleapis-common-protos==1.56.4 \ --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 # via google-api-core -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests importlib-metadata==5.2.0 \ --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \ From 4d39bf1d424af85c70d47e82f735d431de896d75 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:11:30 +0100 Subject: [PATCH 292/582] chore(deps): update dependency googleapis-common-protos to v1.65.0 (#441) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index a0332cd8749b..09ef996844fe 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -363,9 +363,9 @@ google-resumable-media==2.6.0 \ --hash=sha256:972852f6c65f933e15a4a210c2b96930763b47197cdf4aa5f5bea435efb626e7 \ --hash=sha256:fc03d344381970f79eebb632a3c18bb1828593a2dc5572b5f90115ef7d11e81b # via google-cloud-storage -googleapis-common-protos==1.56.4 \ - --hash=sha256:8eb2cbc91b69feaf23e32452a7ae60e791e09967d81d4fcc7fc388182d1bd394 \ - --hash=sha256:c25873c47279387cfdcbdafa36149887901d36202cb645a0e4f29686bf6e4417 +googleapis-common-protos==1.65.0 \ + --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ + --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From ddee4df7dd6c22b1ef0f748d5a307e45e1522948 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:11:46 +0100 Subject: [PATCH 293/582] chore(deps): update dependency google-cloud-core to v2.4.1 (#437) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 09ef996844fe..365a76ed3835 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -281,9 +281,9 @@ google-auth==2.35.0 \ # google-api-core # google-cloud-core # google-cloud-storage -google-cloud-core==2.3.3 \ - --hash=sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb \ - --hash=sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863 +google-cloud-core==2.4.1 \ + --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ + --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-storage google-cloud-storage==2.5.0 \ --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ From 6d478deef7c98842e0cf5f7b89093adf9236b4ef Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:12:02 +0100 Subject: [PATCH 294/582] chore(deps): update dependency gcp-releasetool to v1.17.0 (#435) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 365a76ed3835..33eac6c34bdc 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -263,9 +263,9 @@ gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea # via -r requirements.in -gcp-releasetool==1.16.0 \ - --hash=sha256:27bf19d2e87aaa884096ff941aa3c592c482be3d6a2bfe6f06afafa6af2353e3 \ - --hash=sha256:a316b197a543fd036209d0caba7a8eb4d236d8e65381c80cbc6d7efaa7606d63 +gcp-releasetool==1.17.0 \ + --hash=sha256:1a759f4b0906f4ea9dc7db3649aa11a632c72f6dc6a54f10cf57c1925d034a1c \ + --hash=sha256:f23db51d85484998af5549181be726f177bf90b481de238fe7a99ec970266b6b # via -r requirements.in google-api-core==2.10.2 \ --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ From ec297c51983f7f51e2cd15c9b772cc5d217d20ca Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:14:16 +0100 Subject: [PATCH 295/582] chore(deps): update dependency google-resumable-media to v2.7.2 (#440) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 33eac6c34bdc..bd124e98fba0 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -359,9 +359,9 @@ google-crc32c==1.5.0 \ --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 # via google-resumable-media -google-resumable-media==2.6.0 \ - --hash=sha256:972852f6c65f933e15a4a210c2b96930763b47197cdf4aa5f5bea435efb626e7 \ - --hash=sha256:fc03d344381970f79eebb632a3c18bb1828593a2dc5572b5f90115ef7d11e81b +google-resumable-media==2.7.2 \ + --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ + --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 # via google-cloud-storage googleapis-common-protos==1.65.0 \ --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ From b8d59388572e687608ec59a24a39c07d391930cf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 08:14:19 +0100 Subject: [PATCH 296/582] chore(deps): update dependency google-crc32c to v1.6.0 (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-crc32c](https://redirect.github.com/googleapis/python-crc32c) | `==1.5.0` -> `==1.6.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/google-crc32c/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/google-crc32c/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/google-crc32c/1.5.0/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/google-crc32c/1.5.0/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-crc32c (google-crc32c) ### [`v1.6.0`](https://redirect.github.com/googleapis/python-crc32c/blob/HEAD/CHANGELOG.md#160-2024-08-29) [Compare Source](https://redirect.github.com/googleapis/python-crc32c/compare/v1.5.0...v1.6.0) ##### Features - Add support for python 3.12 ([#​177](https://redirect.github.com/googleapis/python-crc32c/issues/177)) ([5ff1207](https://redirect.github.com/googleapis/python-crc32c/commit/5ff1207e7b60256e7a32932324ccb9ad4ec265d2)) - Build using Visual Studio 17 2022 instead of Visual Studio 16 2019 ([c1c8c59](https://redirect.github.com/googleapis/python-crc32c/commit/c1c8c597d07e573406d76765022a837b007f9074)) ##### Bug Fixes - Drop support for python 3.7 and 3.8 ([c1c8c59](https://redirect.github.com/googleapis/python-crc32c/commit/c1c8c597d07e573406d76765022a837b007f9074)) - Drop support for Windows 32bit which is not supported in Visual Studio 17 2022 ([c1c8c59](https://redirect.github.com/googleapis/python-crc32c/commit/c1c8c597d07e573406d76765022a837b007f9074)) - Remove manylinux1 which is no longer supported by PyPA ([#​186](https://redirect.github.com/googleapis/python-crc32c/issues/186)) ([79edb3f](https://redirect.github.com/googleapis/python-crc32c/commit/79edb3fd3cda0e4193a6fb6a8346058398df43de))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- .../.kokoro/requirements.txt | 97 ++++++------------- 1 file changed, 28 insertions(+), 69 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index bd124e98fba0..f344093e4c7e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -289,75 +289,34 @@ google-cloud-storage==2.5.0 \ --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 # via gcp-docuploader -google-crc32c==1.5.0 \ - --hash=sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a \ - --hash=sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876 \ - --hash=sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c \ - --hash=sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289 \ - --hash=sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298 \ - --hash=sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02 \ - --hash=sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f \ - --hash=sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2 \ - --hash=sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a \ - --hash=sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb \ - --hash=sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210 \ - --hash=sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5 \ - --hash=sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee \ - --hash=sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c \ - --hash=sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a \ - --hash=sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314 \ - --hash=sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd \ - --hash=sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65 \ - --hash=sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37 \ - --hash=sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4 \ - --hash=sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13 \ - --hash=sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894 \ - --hash=sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31 \ - --hash=sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e \ - --hash=sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709 \ - --hash=sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740 \ - --hash=sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc \ - --hash=sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d \ - --hash=sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c \ - --hash=sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c \ - --hash=sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d \ - --hash=sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906 \ - --hash=sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61 \ - --hash=sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57 \ - --hash=sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c \ - --hash=sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a \ - --hash=sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438 \ - --hash=sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946 \ - --hash=sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7 \ - --hash=sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96 \ - --hash=sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091 \ - --hash=sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae \ - --hash=sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d \ - --hash=sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88 \ - --hash=sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2 \ - --hash=sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd \ - --hash=sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541 \ - --hash=sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728 \ - --hash=sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178 \ - --hash=sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968 \ - --hash=sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346 \ - --hash=sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8 \ - --hash=sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93 \ - --hash=sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7 \ - --hash=sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273 \ - --hash=sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462 \ - --hash=sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94 \ - --hash=sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd \ - --hash=sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e \ - --hash=sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57 \ - --hash=sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b \ - --hash=sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9 \ - --hash=sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a \ - --hash=sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100 \ - --hash=sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325 \ - --hash=sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183 \ - --hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \ - --hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4 +google-crc32c==1.6.0 \ + --hash=sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24 \ + --hash=sha256:18e311c64008f1f1379158158bb3f0c8d72635b9eb4f9545f8cf990c5668e59d \ + --hash=sha256:236c87a46cdf06384f614e9092b82c05f81bd34b80248021f729396a78e55d7e \ + --hash=sha256:35834855408429cecf495cac67ccbab802de269e948e27478b1e47dfb6465e57 \ + --hash=sha256:386122eeaaa76951a8196310432c5b0ef3b53590ef4c317ec7588ec554fec5d2 \ + --hash=sha256:40b05ab32a5067525670880eb5d169529089a26fe35dce8891127aeddc1950e8 \ + --hash=sha256:48abd62ca76a2cbe034542ed1b6aee851b6f28aaca4e6551b5599b6f3ef175cc \ + --hash=sha256:50cf2a96da226dcbff8671233ecf37bf6e95de98b2a2ebadbfdf455e6d05df42 \ + --hash=sha256:51c4f54dd8c6dfeb58d1df5e4f7f97df8abf17a36626a217f169893d1d7f3e9f \ + --hash=sha256:5bcc90b34df28a4b38653c36bb5ada35671ad105c99cfe915fb5bed7ad6924aa \ + --hash=sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b \ + --hash=sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc \ + --hash=sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760 \ + --hash=sha256:91ca8145b060679ec9176e6de4f89b07363d6805bd4760631ef254905503598d \ + --hash=sha256:a184243544811e4a50d345838a883733461e67578959ac59964e43cca2c791e7 \ + --hash=sha256:a9e4b426c3702f3cd23b933436487eb34e01e00327fac20c9aebb68ccf34117d \ + --hash=sha256:bb0966e1c50d0ef5bc743312cc730b533491d60585a9a08f897274e57c3f70e0 \ + --hash=sha256:bb8b3c75bd157010459b15222c3fd30577042a7060e29d42dabce449c087f2b3 \ + --hash=sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3 \ + --hash=sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00 \ + --hash=sha256:d2952396dc604544ea7476b33fe87faedc24d666fb0c2d5ac971a2b9576ab871 \ + --hash=sha256:d8797406499f28b5ef791f339594b0b5fdedf54e203b5066675c406ba69d705c \ + --hash=sha256:d9e9913f7bd69e093b81da4535ce27af842e7bf371cde42d1ae9e9bd382dc0e9 \ + --hash=sha256:e2806553238cd076f0a55bddab37a532b53580e699ed8e5606d0de1f856b5205 \ + --hash=sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc \ + --hash=sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d \ + --hash=sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4 # via google-resumable-media google-resumable-media==2.7.2 \ --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ From dfd6106649e6e9840aa49ac4ea221c17a56566f6 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 09:18:58 +0100 Subject: [PATCH 297/582] chore(deps): update dependency rich to v13 (#477) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency rich to v13 * build: update hashes * deps: add secretstorage * deps: add back missing deps * deps: downgrade pkginfo --------- Co-authored-by: Knut Olav LΓΈite --- .../.kokoro/requirements.txt | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f344093e4c7e..96c1aba5b7ee 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -1,6 +1,6 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: # # pip-compile --generate-hashes requirements.in # @@ -244,9 +244,7 @@ cryptography==43.0.3 \ --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 - # via - # gcp-releasetool - # secretstorage + # via gcp-releasetool distlib==0.3.9 \ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 @@ -356,7 +354,11 @@ keyring==23.13.1 \ # via # gcp-releasetool # twine -MarkupSafe==3.0.2 \ +markdown-it-py==3.0.0 \ + --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ + --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb + # via rich +markupsafe==3.0.2 \ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ @@ -419,6 +421,10 @@ MarkupSafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via jinja2 +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py more-itertools==10.5.0 \ --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 @@ -433,9 +439,9 @@ packaging==24.1 \ # via # gcp-releasetool # nox -pkginfo==1.11.2 \ - --hash=sha256:9ec518eefccd159de7ed45386a6bb4c6ca5fa2cb3bd9b71154fae44f6f1b36a3 \ - --hash=sha256:c6bc916b8298d159e31f2c216e35ee5b86da7da18874f879798d0a1983537c86 +pkginfo==1.10.0 \ + --hash=sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297 \ + --hash=sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097 # via twine platformdirs==2.6.2 \ --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ @@ -487,13 +493,13 @@ pycparser==2.22 \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi -Pygments==2.18.0 \ +pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via # readme-renderer # rich -PyJWT==2.9.0 \ +pyjwt==2.9.0 \ --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c # via gcp-releasetool @@ -529,9 +535,9 @@ rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==12.6.0 \ - --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ - --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 +rich==13.9.3 \ + --hash=sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283 \ + --hash=sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e # via twine rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ @@ -545,9 +551,7 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # bleach # gcp-docuploader - # google-auth # python-dateutil twine==5.1.1 \ --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ From 0a8168433168b1359c91aabc9800aa4038958112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 1 Nov 2024 09:32:51 +0100 Subject: [PATCH 298/582] deps: add nh3 (#481) --- .../sqlalchemy-spanner/.kokoro/requirements.in | 1 + .../.kokoro/requirements.txt | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in index 689b5ee187f8..cdc2d4eff96a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.in +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.in @@ -6,3 +6,4 @@ twine wheel setuptools nox +nh3 diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 96c1aba5b7ee..54570f2cdf5f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -429,6 +429,24 @@ more-itertools==10.5.0 \ --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 # via jaraco-classes +nh3==0.2.18 \ + --hash=sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164 \ + --hash=sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86 \ + --hash=sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b \ + --hash=sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad \ + --hash=sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204 \ + --hash=sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a \ + --hash=sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200 \ + --hash=sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189 \ + --hash=sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f \ + --hash=sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811 \ + --hash=sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844 \ + --hash=sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4 \ + --hash=sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be \ + --hash=sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50 \ + --hash=sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307 \ + --hash=sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe + # via -r requirements.in nox==2022.11.21 \ --hash=sha256:0e41a990e290e274cb205a976c4c97ee3c5234441a8132c8c3fd9ea3c22149eb \ --hash=sha256:e21c31de0711d1274ca585a2c5fde36b1aa962005ba8e9322bf5eeed16dcd684 From 970942244cfcfe2d75825dfd3070de469cb12332 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 09:38:44 +0100 Subject: [PATCH 299/582] chore(deps): update dependency readme-renderer to v44 (#475) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 54570f2cdf5f..6e284e162da8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -532,9 +532,9 @@ python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 # via gcp-releasetool -readme-renderer==37.3 \ - --hash=sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273 \ - --hash=sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343 +readme-renderer==44.0 \ + --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 \ + --hash=sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1 # via twine requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ From 81f0d779ff5bcbf46bcd28f7801d77febf50c345 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 09:44:00 +0100 Subject: [PATCH 300/582] chore(deps): update dependency pyasn1 to v0.6.1 (#448) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 6e284e162da8..b7c7c9b0dc72 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -497,9 +497,9 @@ py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 # via nox -pyasn1==0.4.8 \ - --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ - --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba +pyasn1==0.6.1 \ + --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ + --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 # via # pyasn1-modules # rsa From 10b02691c909892e32cb2f5e94f40147d9175879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 1 Nov 2024 10:08:12 +0100 Subject: [PATCH 301/582] deps: add proto plus (#482) --- packages/sqlalchemy-spanner/.kokoro/requirements.in | 1 + packages/sqlalchemy-spanner/.kokoro/requirements.txt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in index cdc2d4eff96a..a4020358398a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.in +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.in @@ -7,3 +7,4 @@ wheel setuptools nox nh3 +proto-plus diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b7c7c9b0dc72..59a7754630ee 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -446,7 +446,9 @@ nh3==0.2.18 \ --hash=sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50 \ --hash=sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307 \ --hash=sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe - # via -r requirements.in + # via + # -r requirements.in + # readme-renderer nox==2022.11.21 \ --hash=sha256:0e41a990e290e274cb205a976c4c97ee3c5234441a8132c8c3fd9ea3c22149eb \ --hash=sha256:e21c31de0711d1274ca585a2c5fde36b1aa962005ba8e9322bf5eeed16dcd684 @@ -465,6 +467,10 @@ platformdirs==2.6.2 \ --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ --hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2 # via virtualenv +proto-plus==1.25.0 \ + --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ + --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 + # via -r requirements.in protobuf==3.20.3 \ --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ From 019616d44994c6c35991134807935d73b717306d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 10:17:46 +0100 Subject: [PATCH 302/582] chore(deps): update dependency google-api-core to v2.22.0 (#296) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 59a7754630ee..d0ed79204f61 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -265,9 +265,9 @@ gcp-releasetool==1.17.0 \ --hash=sha256:1a759f4b0906f4ea9dc7db3649aa11a632c72f6dc6a54f10cf57c1925d034a1c \ --hash=sha256:f23db51d85484998af5549181be726f177bf90b481de238fe7a99ec970266b6b # via -r requirements.in -google-api-core==2.10.2 \ - --hash=sha256:10c06f7739fe57781f87523375e8e1a3a4674bf6392cd6131a3222182b971320 \ - --hash=sha256:34f24bd1d5f72a8c4519773d99ca6bf080a6c4e041b4e9f024fe230191dda62e +google-api-core==2.22.0 \ + --hash=sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35 \ + --hash=sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021 # via # google-cloud-core # google-cloud-storage diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ddcfad4e2cc3..2097bfc7abb2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -141,9 +141,9 @@ deprecated==1.2.14 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.21.0 \ - --hash=sha256:4a152fd11a9f774ea606388d423b68aa7e6d6a0ffe4c8266f74979613ec09f81 \ - --hash=sha256:6869eacb2a37720380ba5898312af79a4d30b8bca1548fb4093e0697dc4bdf5d +google-api-core[grpc]==2.22.0 \ + --hash=sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35 \ + --hash=sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021 # via # google-cloud-core # google-cloud-spanner From 0351ac90318ea913adc52682fbcdcf3846943ec2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 10:25:29 +0100 Subject: [PATCH 303/582] chore(deps): update dependency google-cloud-storage to v2.18.2 (#438) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d0ed79204f61..f0c501ebcad5 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -283,9 +283,9 @@ google-cloud-core==2.4.1 \ --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-storage -google-cloud-storage==2.5.0 \ - --hash=sha256:19a26c66c317ce542cea0830b7e787e8dac2588b6bfa4d3fd3b871ba16305ab0 \ - --hash=sha256:382f34b91de2212e3c2e7b40ec079d27ee2e3dbbae99b75b1bcd8c63063ce235 +google-cloud-storage==2.18.2 \ + --hash=sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166 \ + --hash=sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99 # via gcp-docuploader google-crc32c==1.6.0 \ --hash=sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24 \ From bdfd2cc741c5d33579a4722b5dda4039b246abe3 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 11:09:29 +0100 Subject: [PATCH 304/582] chore(deps): update dependency virtualenv to v20.27.1 (#458) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency virtualenv to v20.27.1 * deps: update platformdirs --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy-spanner/.kokoro/requirements.txt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f0c501ebcad5..636f6c0653e5 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -463,10 +463,9 @@ pkginfo==1.10.0 \ --hash=sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297 \ --hash=sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097 # via twine -platformdirs==2.6.2 \ - --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ - --hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2 - # via virtualenv +platformdirs==4.3.6 \ + --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ + --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb proto-plus==1.25.0 \ --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 @@ -591,9 +590,9 @@ urllib3==2.2.3 \ # via # requests # twine -virtualenv==20.16.5 \ - --hash=sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da \ - --hash=sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27 +virtualenv==20.27.1 \ + --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \ + --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4 # via nox webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ From 7dff22a6a88d9490708ecb8ddbf35666c377427b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 11:16:28 +0100 Subject: [PATCH 305/582] chore(deps): update dependency nox to v2024 (#471) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency nox to v2024 * deps: add tomli --------- Co-authored-by: Knut Olav LΓΈite --- .../.kokoro/requirements.in | 1 + .../.kokoro/requirements.txt | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in index a4020358398a..9aedbff3ce66 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.in +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.in @@ -8,3 +8,4 @@ setuptools nox nh3 proto-plus +tomli diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 636f6c0653e5..b2814b5f03d1 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -315,7 +315,9 @@ google-crc32c==1.6.0 \ --hash=sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc \ --hash=sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d \ --hash=sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4 - # via google-resumable-media + # via + # google-cloud-storage + # google-resumable-media google-resumable-media==2.7.2 \ --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 @@ -449,9 +451,9 @@ nh3==0.2.18 \ # via # -r requirements.in # readme-renderer -nox==2022.11.21 \ - --hash=sha256:0e41a990e290e274cb205a976c4c97ee3c5234441a8132c8c3fd9ea3c22149eb \ - --hash=sha256:e21c31de0711d1274ca585a2c5fde36b1aa962005ba8e9322bf5eeed16dcd684 +nox==2024.10.9 \ + --hash=sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab \ + --hash=sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95 # via -r requirements.in packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ @@ -466,10 +468,13 @@ pkginfo==1.10.0 \ platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb + # via virtualenv proto-plus==1.25.0 \ --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 - # via -r requirements.in + # via + # -r requirements.in + # google-api-core protobuf==3.20.3 \ --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ @@ -576,6 +581,10 @@ six==1.16.0 \ # via # gcp-docuploader # python-dateutil +tomli==2.0.2 \ + --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ + --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed + # via -r requirements.in twine==5.1.1 \ --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ --hash=sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db From 7e02e1f500f1dcc2ad3852dba57a42eefd541ae7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 11:26:18 +0100 Subject: [PATCH 306/582] chore(deps): update dependency argcomplete to v3 (#463) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b2814b5f03d1..44037b9c8182 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes requirements.in # -argcomplete==2.1.2 \ - --hash=sha256:4ba9cdaa28c361d251edce884cd50b4b1215d65cdc881bd204426cdde9f52731 \ - --hash=sha256:fc82ef070c607b1559b5c720529d63b54d9dcf2dcfc2632b10e6372314a34457 +argcomplete==3.5.1 \ + --hash=sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363 \ + --hash=sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4 # via nox attrs==24.2.0 \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ From e2fb7239baf2eba018ce3cb4c280fb0303163a9e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 11:35:58 +0100 Subject: [PATCH 307/582] chore(deps): update dependency gcp-releasetool to v2 (#466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency gcp-releasetool to v2 * deps: update protobuf --------- Co-authored-by: Knut Olav LΓΈite --- .../.kokoro/requirements.txt | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 44037b9c8182..b2fa27e7cf03 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -261,9 +261,9 @@ gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea # via -r requirements.in -gcp-releasetool==1.17.0 \ - --hash=sha256:1a759f4b0906f4ea9dc7db3649aa11a632c72f6dc6a54f10cf57c1925d034a1c \ - --hash=sha256:f23db51d85484998af5549181be726f177bf90b481de238fe7a99ec970266b6b +gcp-releasetool==2.2.0 \ + --hash=sha256:9ca3a41d397485bb7f6ad7933d64d9071961188f41fc0182e47562b41cebaff2 \ + --hash=sha256:ae0fc2525fdf1eb4638059dee3ec265620e1a85cb89f564615793698b3b422d6 # via -r requirements.in google-api-core==2.22.0 \ --hash=sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35 \ @@ -475,29 +475,18 @@ proto-plus==1.25.0 \ # via # -r requirements.in # google-api-core -protobuf==3.20.3 \ - --hash=sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7 \ - --hash=sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c \ - --hash=sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2 \ - --hash=sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b \ - --hash=sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050 \ - --hash=sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9 \ - --hash=sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7 \ - --hash=sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454 \ - --hash=sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480 \ - --hash=sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469 \ - --hash=sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c \ - --hash=sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e \ - --hash=sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db \ - --hash=sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905 \ - --hash=sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b \ - --hash=sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86 \ - --hash=sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4 \ - --hash=sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402 \ - --hash=sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7 \ - --hash=sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4 \ - --hash=sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99 \ - --hash=sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee +protobuf==5.28.3 \ + --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ + --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ + --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ + --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ + --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ + --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ + --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ + --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ + --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ + --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ + --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed # via # gcp-docuploader # gcp-releasetool From b5bb83458c20ad9cb3fe35215bce18e189ba2504 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 11:45:09 +0100 Subject: [PATCH 308/582] chore(deps): update dependency importlib-metadata to v8.5.0 (#467) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b2fa27e7cf03..ab10ebe0df30 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -330,9 +330,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==5.2.0 \ - --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \ - --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd +importlib-metadata==8.5.0 \ + --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ + --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via # -r requirements.in # twine diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2097bfc7abb2..91a9fd4ffe0f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -246,9 +246,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.4.0 \ - --hash=sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1 \ - --hash=sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5 +importlib-metadata==8.5.0 \ + --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ + --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via opentelemetry-api mako==1.3.6 \ --hash=sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d \ From fb8886a6511d140accb2a1e07ae3f879d559cd7a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 12:03:54 +0100 Subject: [PATCH 309/582] chore(deps): update dependency keyring to v25 (#468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency keyring to v25 * deps: add jaroco.context * deps: add backports.tarfile --------- Co-authored-by: Knut Olav LΓΈite --- .../.kokoro/requirements.in | 2 ++ .../.kokoro/requirements.txt | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in index 9aedbff3ce66..b52510c98e0d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.in +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.in @@ -9,3 +9,5 @@ nox nh3 proto-plus tomli +jaraco.context +backports.tarfile diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ab10ebe0df30..ece81019754b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -12,6 +12,10 @@ attrs==24.2.0 \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 # via gcp-releasetool +backports-tarfile==1.2.0 \ + --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ + --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 + # via -r requirements.in bleach==6.2.0 \ --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e \ --hash=sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f @@ -340,19 +344,26 @@ jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a # via keyring +jaraco-context==6.0.1 \ + --hash=sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3 \ + --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4 + # via + # -r requirements.in + # keyring +jaraco-functools==4.1.0 \ + --hash=sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d \ + --hash=sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649 + # via keyring jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 - # via - # keyring - # secretstorage jinja2==3.1.4 \ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d # via gcp-releasetool -keyring==23.13.1 \ - --hash=sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd \ - --hash=sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678 +keyring==25.5.0 \ + --hash=sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6 \ + --hash=sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741 # via # gcp-releasetool # twine @@ -430,7 +441,9 @@ mdurl==0.1.2 \ more-itertools==10.5.0 \ --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 - # via jaraco-classes + # via + # jaraco-classes + # jaraco-functools nh3==0.2.18 \ --hash=sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164 \ --hash=sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86 \ @@ -492,6 +505,7 @@ protobuf==5.28.3 \ # gcp-releasetool # google-api-core # googleapis-common-protos + # proto-plus py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 From 78b8fed1a7c8f9ebf9e980c80d4a156f9e78fe4a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 12:07:35 +0100 Subject: [PATCH 310/582] chore(deps): update ubuntu docker tag to v24 (#480) --- packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile b/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile index cf3922d790f1..e2bfb5b860c6 100644 --- a/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile +++ b/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile @@ -4,7 +4,7 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -from ubuntu:20.04 +from ubuntu:24.04 ENV DEBIAN_FRONTEND noninteractive From 3a07b69e0ebc10ab5253fbc55a461d2efcd28fbf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 1 Nov 2024 12:19:48 +0100 Subject: [PATCH 311/582] chore(deps): update dependency jaraco-classes to v3.4.0 (#443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency jaraco-classes to v3.4.0 * deps: update hashes * deps: remove duplicate entry --------- Co-authored-by: Knut Olav LΓΈite --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ece81019754b..71e0b1650558 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -340,9 +340,9 @@ importlib-metadata==8.5.0 \ # via # -r requirements.in # twine -jaraco-classes==3.2.3 \ - --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ - --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a +jaraco-classes==3.4.0 \ + --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ + --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 # via keyring jaraco-context==6.0.1 \ --hash=sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3 \ @@ -618,8 +618,3 @@ zipp==3.20.2 \ --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 # via importlib-metadata - -# WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes and the requirement is not -# satisfied by a package already installed. Consider using the --allow-unsafe flag. -# setuptools From 0ba3e4a6a8e2f1ecca4bf2a32fad49b207cf5a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 1 Nov 2024 19:48:32 +0100 Subject: [PATCH 312/582] build: fix kokoro build (#486) --- packages/sqlalchemy-spanner/.kokoro/build.sh | 4 +--- packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg | 6 ------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index 2c87f74912fe..545146826447 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -43,8 +43,6 @@ fi # otherwise run all the sessions. if [[ -n "${NOX_SESSION:-}" ]]; then python3 -m nox -s ${NOX_SESSION:-} -elif [[ "${RUN_COMPLIANCE_TESTS}" -eq "false" ]]; then - python3 -m nox -s unit else - python3 -m nox + python3 -m nox -s unit fi diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg index 3aa9014481f6..18a4c35325b8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg +++ b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg @@ -1,7 +1 @@ # Format: //devtools/kokoro/config/proto/build.proto - -# Disable system tests. -env_vars: { - key: "RUN_COMPLIANCE_TESTS" - value: "false" -} From ca942aa482427866de7d240a7ff638776d6ff7e7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 4 Nov 2024 13:44:09 +0100 Subject: [PATCH 313/582] chore(deps): update dependency rich to v13.9.4 (#484) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 71e0b1650558..78422e597783 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -566,9 +566,9 @@ rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==13.9.3 \ - --hash=sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283 \ - --hash=sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e +rich==13.9.4 \ + --hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \ + --hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90 # via twine rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ From 5e7f2e504b9040758335886eae891f36ceb12b8b Mon Sep 17 00:00:00 2001 From: minev-dev <90937832+minev-dev@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:04:15 -0800 Subject: [PATCH 314/582] fix: Add `existing_nullable` usage to `visit_column_type` (#329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Add `existing_nullable` usage to `visit_column_type` Without this, altering operations (e.g. change column length) can cause nullability change of the column. It then causes error if this column is a part of index: "400 Changing NOT NULL constraints on column column_name is not allowed because it affects index index_name" * fix: add missing placeholder --------- Co-authored-by: Knut Olav LΓΈite --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 6754931a3080..1514f9e3d957 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1564,8 +1564,9 @@ def visit_column_nullable( def visit_column_type( element: "ColumnType", compiler: "SpannerDDLCompiler", **kw ) -> str: - return "%s %s %s" % ( + return "%s %s %s %s" % ( alter_table(compiler, element.table_name, element.schema), alter_column(compiler, element.column_name), "%s" % format_type(compiler, element.type_), + "" if element.existing_nullable else "NOT NULL", ) From 553eef071bef30aab895a93b7524dcf4c87da54a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 13:57:50 +0100 Subject: [PATCH 315/582] chore(deps): update dependency alembic to v1.14.0 (#488) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 91a9fd4ffe0f..918162cde9bb 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.13.3 \ - --hash=sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2 \ - --hash=sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e +alembic==1.14.0 \ + --hash=sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25 \ + --hash=sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From da5bcab0db96d18f0826c1f2e5c4a6afbde44680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 8 Nov 2024 14:01:13 +0100 Subject: [PATCH 316/582] test: add system tests (#420) * test: add system tests * test: run system tests on prod * build: allow any Python version for sys tests * build: keep instance and create new databases instead * chore: format code * fix: do not use static fallback config * fix: cleanup job * fix: search until end of string * build: only run system tests on the emulator for presubmits * build: skip system tests when skipping conformance tests * test: run tests with Python 3.8 * test: try this * test: no tests * build: run system tests on real Spanner * chore: cleanup test database after system test run --- .../.github/workflows/test_suite.yml | 24 ++++++ packages/sqlalchemy-spanner/.kokoro/build.sh | 1 + .../sqlalchemy-spanner/create_test_config.py | 19 ++--- .../create_test_database.py | 76 ++++++++++++------- .../sqlalchemy-spanner/drop_test_database.py | 63 +++++++++++++++ .../migration_test_cleanup.py | 3 +- packages/sqlalchemy-spanner/noxfile.py | 53 ++++++++++--- .../test/system/test_basics.py | 39 ++++++++++ 8 files changed, 229 insertions(+), 49 deletions(-) create mode 100644 packages/sqlalchemy-spanner/drop_test_database.py create mode 100644 packages/sqlalchemy-spanner/test/system/test_basics.py diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 748378abc1c3..0f2197875d5b 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -126,6 +126,30 @@ jobs: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + system: + runs-on: ubuntu-latest + + services: + emulator-0: + image: gcr.io/cloud-spanner-emulator/emulator:latest + ports: + - 9010:9010 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.12 + - name: Install nox + run: python -m pip install nox + - name: Run System Tests + run: nox -s system + env: + SPANNER_EMULATOR_HOST: localhost:9010 + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + migration_tests: runs-on: ubuntu-latest diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index 545146826447..0985afd04bf2 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -45,4 +45,5 @@ if [[ -n "${NOX_SESSION:-}" ]]; then python3 -m nox -s ${NOX_SESSION:-} else python3 -m nox -s unit + python3 -m nox -s system fi diff --git a/packages/sqlalchemy-spanner/create_test_config.py b/packages/sqlalchemy-spanner/create_test_config.py index 7ef6f2558535..388cba861638 100644 --- a/packages/sqlalchemy-spanner/create_test_config.py +++ b/packages/sqlalchemy-spanner/create_test_config.py @@ -18,18 +18,18 @@ import sys -def set_test_config(project, instance, user=None, password=None, host=None, port=None): +def set_test_config(project, instance, database, user=None, password=None, host=None, port=None): config = configparser.ConfigParser() if user is not None and password is not None and host is not None and port is not None: url = ( f"spanner+spanner://{user}:{password}@{host}:{port}" f"/projects/{project}/instances/{instance}/" - "databases/compliance-test" + f"databases/{database}" ) else: url = ( f"spanner+spanner:///projects/{project}/instances/{instance}/" - "databases/compliance-test" + f"databases/{database}" ) config.add_section("db") config["db"]["default"] = url @@ -41,17 +41,18 @@ def set_test_config(project, instance, user=None, password=None, host=None, port def main(argv): project = argv[0] instance = argv[1] - if len(argv) == 6: - user = argv[2] - password = argv[3] - host = argv[4] - port = argv[5] + database = argv[2] + if len(argv) == 7: + user = argv[3] + password = argv[4] + host = argv[5] + port = argv[6] else: user = None password = None host = None port = None - set_test_config(project, instance, user, password, host, port) + set_test_config(project, instance, database, user, password, host, port) if __name__ == "__main__": diff --git a/packages/sqlalchemy-spanner/create_test_database.py b/packages/sqlalchemy-spanner/create_test_database.py index 1e29d44f7fcf..5938eb82839c 100644 --- a/packages/sqlalchemy-spanner/create_test_database.py +++ b/packages/sqlalchemy-spanner/create_test_database.py @@ -14,14 +14,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -import configparser import os import time from create_test_config import set_test_config +from google.api_core import datetime_helpers from google.api_core.exceptions import AlreadyExists, ResourceExhausted from google.cloud.spanner_v1 import Client from google.cloud.spanner_v1.instance import Instance +from google.cloud.spanner_v1.database import Database USE_EMULATOR = os.getenv("SPANNER_EMULATOR_HOST") is not None @@ -66,43 +67,62 @@ def delete_stale_test_instances(): ) -def create_test_instance(): - configs = list(CLIENT.list_instance_configs()) - if not USE_EMULATOR: - # Filter out non "us" locations - configs = [config for config in configs if "asia-southeast1" in config.name] +def delete_stale_test_databases(): + """Delete test databases that are older than four hours.""" + cutoff = (int(time.time()) - 4 * 60 * 60) * 1000 + instance = CLIENT.instance("sqlalchemy-dialect-test") + if not instance.exists(): + return + database_pbs = instance.list_databases() + for database_pb in database_pbs: + database = Database.from_pb(database_pb, instance) + # The emulator does not return a create_time for databases. + if database.create_time is None: + continue + create_time = datetime_helpers.to_milliseconds(database_pb.create_time) + if create_time > cutoff: + continue + try: + database.drop() + except ResourceExhausted: + print( + "Unable to drop stale database '{}'. May need manual delete.".format( + database.database_id + ) + ) - instance_config = configs[0].name - create_time = str(int(time.time())) - unique_resource_id = "%s%d" % ("-", 1000 * time.time()) - instance_id = ( - "sqlalchemy-dialect-test" - if USE_EMULATOR - else "sqlalchemy-test" + unique_resource_id - ) - labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} - instance = CLIENT.instance(instance_id, instance_config, labels=labels) +def create_test_instance(): + instance_id = "sqlalchemy-dialect-test" + instance = CLIENT.instance(instance_id) + if not instance.exists(): + instance_config = f"projects/{PROJECT}/instanceConfigs/regional-us-east1" + if USE_EMULATOR: + configs = list(CLIENT.list_instance_configs()) + instance_config = configs[0].name + create_time = str(int(time.time())) + labels = {"python-spanner-sqlalchemy-systest": "true", "created": create_time} + + instance = CLIENT.instance(instance_id, instance_config, labels=labels) - try: - created_op = instance.create() - created_op.result(1800) # block until completion - except AlreadyExists: - pass # instance was already created + try: + created_op = instance.create() + created_op.result(1800) # block until completion + except AlreadyExists: + pass # instance was already created - if USE_EMULATOR: - database = instance.database("compliance-test") - database.drop() + unique_resource_id = "%s%d" % ("-", 1000 * time.time()) + database_id = "sqlalchemy-test" + unique_resource_id try: - database = instance.database("compliance-test") + database = instance.database(database_id) created_op = database.create() created_op.result(1800) except AlreadyExists: - pass # instance was already created + pass # database was already created - set_test_config(PROJECT, instance_id) + set_test_config(PROJECT, instance_id, database_id) -delete_stale_test_instances() +delete_stale_test_databases() create_test_instance() diff --git a/packages/sqlalchemy-spanner/drop_test_database.py b/packages/sqlalchemy-spanner/drop_test_database.py new file mode 100644 index 000000000000..3f2b25c2a777 --- /dev/null +++ b/packages/sqlalchemy-spanner/drop_test_database.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import configparser +import os +import re +import time + +from create_test_config import set_test_config +from google.api_core import datetime_helpers +from google.api_core.exceptions import AlreadyExists, ResourceExhausted +from google.cloud.spanner_v1 import Client +from google.cloud.spanner_v1.instance import Instance +from google.cloud.spanner_v1.database import Database + + +USE_EMULATOR = os.getenv("SPANNER_EMULATOR_HOST") is not None + +PROJECT = os.getenv( + "GOOGLE_CLOUD_PROJECT", + os.getenv("PROJECT_ID", "emulator-test-project"), +) +CLIENT = None + +if USE_EMULATOR: + from google.auth.credentials import AnonymousCredentials + + CLIENT = Client(project=PROJECT, credentials=AnonymousCredentials()) +else: + CLIENT = Client(project=PROJECT) + + +def delete_test_database(): + """Delete the currently configured test database.""" + config = configparser.ConfigParser() + if os.path.exists("test.cfg"): + config.read("test.cfg") + else: + config.read("setup.cfg") + db_url = config.get("db", "default") + + instance_id = re.findall(r"instances(.*?)databases", db_url) + database_id = re.findall(r"databases(.*?)$", db_url) + + instance = CLIENT.instance( + instance_id="".join(instance_id).replace("/", "")) + database = instance.database("".join(database_id).replace("/", "")) + database.drop() + +delete_test_database() diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py index 6226635939f6..c56b10d0cecd 100644 --- a/packages/sqlalchemy-spanner/migration_test_cleanup.py +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -25,10 +25,11 @@ def main(argv): project = re.findall(r"projects(.*?)instances", db_url) instance_id = re.findall(r"instances(.*?)databases", db_url) + database_id = re.findall(r"databases(.*?)$", db_url) client = spanner.Client(project="".join(project).replace("/", "")) instance = client.instance(instance_id="".join(instance_id).replace("/", "")) - database = instance.database("compliance-test") + database = instance.database("".join(database_id).replace("/", "")) database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index eff6bfc927f6..2c4b21bc8525 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -252,6 +252,43 @@ def compliance_test_20(session): ) +@nox.session() +def system(session): + """Run SQLAlchemy dialect system test suite.""" + + # Sanity check: Only run tests if the environment variable is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( + "SPANNER_EMULATOR_HOST", "" + ): + session.skip( + "Credentials or emulator host must be set via environment variable" + ) + + if os.environ.get("RUN_COMPLIANCE_TESTS", "true") == "false" and not os.environ.get( + "SPANNER_EMULATOR_HOST", "" + ): + session.skip("RUN_COMPLIANCE_TESTS is set to false, skipping") + + session.install( + "pytest", + "pytest-cov", + "pytest-asyncio", + ) + + session.install("mock") + session.install(".[tracing]") + session.install("opentelemetry-api==1.27.0") + session.install("opentelemetry-sdk==1.27.0") + session.install("opentelemetry-instrumentation==0.48b0") + session.run("python", "create_test_database.py") + + session.install("sqlalchemy>=2.0") + + session.run("py.test", "--quiet", os.path.join("test", "system"), *session.posargs) + + session.run("python", "drop_test_database.py") + + @nox.session(python=DEFAULT_PYTHON_VERSION) def unit(session): """Run unit tests.""" @@ -263,7 +300,9 @@ def unit(session): session.install("opentelemetry-api==1.27.0") session.install("opentelemetry-sdk==1.27.0") session.install("opentelemetry-instrumentation==0.48b0") - session.run("python", "create_test_config.py", "my-project", "my-instance") + session.run( + "python", "create_test_config.py", "my-project", "my-instance", "my-database" + ) session.run("py.test", "--quiet", os.path.join("test/unit"), *session.posargs) @@ -281,6 +320,7 @@ def mockserver(session): "create_test_config.py", "my-project", "my-instance", + "my-database", "none", "AnonymousCredentials", "localhost", @@ -323,21 +363,12 @@ def _migration_test(session): session.run("python", "create_test_database.py") - project = os.getenv( - "GOOGLE_CLOUD_PROJECT", - os.getenv("PROJECT_ID", "emulator-test-project"), - ) - db_url = ( - f"spanner+spanner:///projects/{project}/instances/" - "sqlalchemy-dialect-test/databases/compliance-test" - ) - config = configparser.ConfigParser() if os.path.exists("test.cfg"): config.read("test.cfg") else: config.read("setup.cfg") - db_url = config.get("db", "default", fallback=db_url) + db_url = config.get("db", "default") session.run("alembic", "init", "test_migration") diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py new file mode 100644 index 000000000000..6a53b2349b5a --- /dev/null +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -0,0 +1,39 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from sqlalchemy import text, Table, Column, Integer, PrimaryKeyConstraint, String +from sqlalchemy.testing import eq_ +from sqlalchemy.testing.plugin.plugin_base import fixtures + + +class TestBasics(fixtures.TablesTest): + @classmethod + def define_tables(cls, metadata): + Table( + "numbers", + metadata, + Column("number", Integer), + Column("name", String(20)), + PrimaryKeyConstraint("number"), + ) + + def test_hello_world(self, connection): + greeting = connection.execute(text("select 'Hello World'")) + eq_("Hello World", greeting.fetchone()[0]) + + def test_insert_number(self, connection): + connection.execute( + text("insert or update into numbers(number, name) values (1, 'One')") + ) + name = connection.execute(text("select name from numbers where number=1")) + eq_("One", name.fetchone()[0]) From ff81fa8fa3eee13c8a86a95ab610f2ec395cd739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 8 Nov 2024 14:02:00 +0100 Subject: [PATCH 317/582] docs: fix readme typo (#487) --- packages/sqlalchemy-spanner/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 85fecf20d97c..25cde4598d2c 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -508,7 +508,7 @@ run the tests the ``nox`` package commands can be used: Running tests on Spanner emulator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The dialect test suite can be runned on `Spanner +The dialect test suite can be run on `Spanner emulator `__. Several tests, relating to ``NULL`` values of data types, are skipped when executed on emulator. From 6449b9a354646b987fc7f78830b880c100f1402e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:02:44 +0100 Subject: [PATCH 318/582] chore(deps): update dependency opentelemetry-api to v1.28.0 (#489) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 918162cde9bb..fb196b96fa84 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -317,9 +317,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.27.0 \ - --hash=sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7 \ - --hash=sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342 +opentelemetry-api==1.28.0 \ + --hash=sha256:578610bcb8aa5cdcb11169d136cc752958548fb6ccffb0969c1036b0ee9e5353 \ + --hash=sha256:8457cd2c59ea1bd0988560f021656cecd254ad7ef6be4ba09dbefeca2409ce52 # via # -r requirements.in # opentelemetry-instrumentation From cc5c8fed276ef62e6264ca1d0ae0661dc46323ce Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:02:56 +0100 Subject: [PATCH 319/582] chore(deps): update dependency opentelemetry-sdk to v1.28.0 (#490) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index fb196b96fa84..8d0f2a7a3f54 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -329,9 +329,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.27.0 \ - --hash=sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d \ - --hash=sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f +opentelemetry-sdk==1.28.0 \ + --hash=sha256:41d5420b2e3fb7716ff4981b510d551eff1fc60eb5a95cf7335b31166812a893 \ + --hash=sha256:4b37da81d7fad67f6683c4420288c97f4ed0d988845d5886435f428ec4b8429a # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From c948e2538e6799599c536bafdbd39bea3a47f2d7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:03:08 +0100 Subject: [PATCH 320/582] chore(deps): update dependency google-auth to v2.36.0 (#491) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 78422e597783..22118575b77b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -275,9 +275,9 @@ google-api-core==2.22.0 \ # via # google-cloud-core # google-cloud-storage -google-auth==2.35.0 \ - --hash=sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f \ - --hash=sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a +google-auth==2.36.0 \ + --hash=sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb \ + --hash=sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1 # via # gcp-releasetool # google-api-core diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8d0f2a7a3f54..0416b9cbdcb6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -147,9 +147,9 @@ google-api-core[grpc]==2.22.0 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.35.0 \ - --hash=sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f \ - --hash=sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a +google-auth==2.36.0 \ + --hash=sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb \ + --hash=sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1 # via # google-api-core # google-cloud-core From cb61a263f52e401428e7e4521b6fd4a96f52aee4 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:07:08 +0100 Subject: [PATCH 321/582] chore(deps): update dependency packaging to v24.2 (#499) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 22118575b77b..3339b12b913b 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -468,9 +468,9 @@ nox==2024.10.9 \ --hash=sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab \ --hash=sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95 # via -r requirements.in -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +packaging==24.2 \ + --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ + --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f # via # gcp-releasetool # nox diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0416b9cbdcb6..9a0a96f8299c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -337,9 +337,9 @@ opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ --hash=sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f # via opentelemetry-sdk -packaging==24.1 \ - --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ - --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +packaging==24.2 \ + --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ + --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f # via # -r requirements.in # build From 13c27b578bbd1cf242806842501c8f0275823e8f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:07:19 +0100 Subject: [PATCH 322/582] chore(deps): update actions/checkout action to v4 (#500) --- packages/sqlalchemy-spanner/.github/workflows/test_suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 0f2197875d5b..9f146a9bee82 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -137,7 +137,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: From 3668a16921e5837062fe2d0256e3ed99b2b28835 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 8 Nov 2024 14:07:36 +0100 Subject: [PATCH 323/582] chore(deps): update actions/setup-python action to v5 (#501) --- packages/sqlalchemy-spanner/.github/workflows/test_suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 9f146a9bee82..b234dc03dd69 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -139,7 +139,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install nox From 14b4b06ce38d8b7647039c26c75367c328f5e125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 8 Nov 2024 14:23:31 +0100 Subject: [PATCH 324/582] fix: support storing columns for indices (#485) * test: add system tests * test: run system tests on prod * build: allow any Python version for sys tests * build: keep instance and create new databases instead * chore: format code * fix: do not use static fallback config * fix: cleanup job * fix: search until end of string * build: only run system tests on the emulator for presubmits * build: skip system tests when skipping conformance tests * test: run tests with Python 3.8 * test: try this * test: no tests * fix: support storing columns for indices * fix: split key and non-key columns * build: run system tests on real Spanner * fix: add include_columns as none * fix: remove unused test * fix: use lower case for asc/desc * test: expect lower case desc --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 65 ++++++++++++++++--- .../test/system/test_basics.py | 43 +++++++++++- .../sqlalchemy-spanner/test/test_suite_20.py | 6 +- 3 files changed, 99 insertions(+), 15 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 1514f9e3d957..e57d46a818c2 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -492,6 +492,26 @@ def post_create_table(self, table): return post_cmds + def visit_create_index( + self, create, include_schema=False, include_table_schema=True, **kw + ): + text = super().visit_create_index( + create, include_schema, include_table_schema, **kw + ) + index = create.element + if "spanner" in index.dialect_options: + options = index.dialect_options["spanner"] + if "storing" in options: + storing = options["storing"] + storing_columns = [ + index.table.c[col] if isinstance(col, str) else col + for col in storing + ] + text += " STORING (%s)" % ", ".join( + [self.preparer.quote(c.name) for c in storing_columns] + ) + return text + def get_identity_options(self, identity_options): text = ["sequence_kind = 'bit_reversed_positive'"] if identity_options.start is not None: @@ -997,15 +1017,35 @@ def get_multi_indexes( i.table_schema, i.table_name, i.index_name, - ARRAY_AGG(ic.column_name), + ( + SELECT ARRAY_AGG(ic.column_name) + FROM information_schema.index_columns ic + WHERE ic.index_name = i.index_name + AND ic.table_catalog = i.table_catalog + AND ic.table_schema = i.table_schema + AND ic.table_name = i.table_name + AND ic.column_ordering is not null + ) as columns, i.is_unique, - ARRAY_AGG(ic.column_ordering) + ( + SELECT ARRAY_AGG(ic.column_ordering) + FROM information_schema.index_columns ic + WHERE ic.index_name = i.index_name + AND ic.table_catalog = i.table_catalog + AND ic.table_schema = i.table_schema + AND ic.table_name = i.table_name + AND ic.column_ordering is not null + ) as column_orderings, + ( + SELECT ARRAY_AGG(storing.column_name) + FROM information_schema.index_columns storing + WHERE storing.index_name = i.index_name + AND storing.table_catalog = i.table_catalog + AND storing.table_schema = i.table_schema + AND storing.table_name = i.table_name + AND storing.column_ordering is null + ) as storing_columns, FROM information_schema.indexes as i - JOIN information_schema.index_columns AS ic - ON ic.index_name = i.index_name - AND ic.table_catalog = i.table_catalog - AND ic.table_schema = i.table_schema - AND ic.table_name = i.table_name JOIN information_schema.tables AS t ON i.table_catalog = t.table_catalog AND i.table_schema = t.table_schema @@ -1016,7 +1056,8 @@ def get_multi_indexes( {schema_filter_query} i.index_type != 'PRIMARY_KEY' AND i.spanner_is_managed = FALSE - GROUP BY i.table_schema, i.table_name, i.index_name, i.is_unique + GROUP BY i.table_catalog, i.table_schema, i.table_name, + i.index_name, i.is_unique ORDER BY i.index_name """.format( table_filter_query=table_filter_query, @@ -1029,13 +1070,19 @@ def get_multi_indexes( result_dict = {} for row in rows: + dialect_options = {} + include_columns = row[6] + if include_columns: + dialect_options["spanner_storing"] = include_columns index_info = { "name": row[2], "column_names": row[3], "unique": row[4], "column_sorting": { - col: order for col, order in zip(row[3], row[5]) + col: order.lower() for col, order in zip(row[3], row[5]) }, + "include_columns": include_columns if include_columns else [], + "dialect_options": dialect_options, } row[0] = row[0] or None table_info = result_dict.get((row[0], row[1]), []) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 6a53b2349b5a..3357104cf83e 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -11,7 +11,18 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import text, Table, Column, Integer, PrimaryKeyConstraint, String + +from sqlalchemy import ( + text, + Table, + Column, + Integer, + PrimaryKeyConstraint, + String, + Index, + MetaData, + Boolean, +) from sqlalchemy.testing import eq_ from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -19,13 +30,21 @@ class TestBasics(fixtures.TablesTest): @classmethod def define_tables(cls, metadata): - Table( + numbers = Table( "numbers", metadata, Column("number", Integer), Column("name", String(20)), + Column("alternative_name", String(20)), + Column("prime", Boolean), PrimaryKeyConstraint("number"), ) + Index( + "idx_numbers_name", + numbers.c.name, + numbers.c.prime.desc(), + spanner_storing=[numbers.c.alternative_name], + ) def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) @@ -33,7 +52,25 @@ def test_hello_world(self, connection): def test_insert_number(self, connection): connection.execute( - text("insert or update into numbers(number, name) values (1, 'One')") + text( + """insert or update into numbers (number, name, prime) + values (1, 'One', false)""" + ) ) name = connection.execute(text("select name from numbers where number=1")) eq_("One", name.fetchone()[0]) + + def test_reflect(self, connection): + engine = connection.engine + meta: MetaData = MetaData() + meta.reflect(bind=engine) + eq_(1, len(meta.tables)) + table = meta.tables["numbers"] + eq_(1, len(table.indexes)) + index = next(iter(table.indexes)) + eq_(2, len(index.columns)) + eq_("name", index.columns[0].name) + eq_("prime", index.columns[1].name) + dialect_options = index.dialect_options["spanner"] + eq_(1, len(dialect_options["storing"])) + eq_("alternative_name", dialect_options["storing"][0]) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 4902b3ab6def..22b23e0a7305 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -1414,7 +1414,7 @@ def idx( "include_columns": [], } if column_sorting: - res["column_sorting"] = {"q": "DESC"} + res["column_sorting"] = {"q": "desc"} if duplicates: res["duplicates_constraint"] = name return [res] @@ -1458,11 +1458,11 @@ def idx( *idx( "q", name="noncol_idx_nopk", - column_sorting={"q": "DESC"}, + column_sorting={"q": "desc"}, ) ], (schema, "noncol_idx_test_pk"): [ - *idx("q", name="noncol_idx_pk", column_sorting={"q": "DESC"}) + *idx("q", name="noncol_idx_pk", column_sorting={"q": "desc"}) ], (schema, self.temp_table_name()): [ *idx("foo", name="user_tmp_ix"), From d77962adf3c83544920687e177fd86d1a8c1b53e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 8 Nov 2024 17:24:52 +0100 Subject: [PATCH 325/582] docs: add samples for Spanner-specific features (#492) * docs: add samples for Spanner-specific features * docs: more samples * docs: add more samples * test: add tests for samples * chore: fix linting error * docs: document samples * docs: link to README --- .../.github/workflows/test_suite.yml | 16 ++ packages/sqlalchemy-spanner/README.rst | 7 + packages/sqlalchemy-spanner/samples/README.md | 30 ++++ .../samples/bit_reversed_sequence_sample.py | 70 ++++++++ .../samples/date_and_timestamp_sample.py | 64 +++++++ .../samples/default_column_value_sample.py | 61 +++++++ .../samples/generated_column_sample.py | 50 ++++++ .../samples/hello_world_sample.py | 31 ++++ .../samples/insert_data_sample.py | 73 ++++++++ .../samples/interleaved_table_sample.py | 98 ++++++++++ packages/sqlalchemy-spanner/samples/model.py | 167 ++++++++++++++++++ .../sqlalchemy-spanner/samples/noxfile.py | 80 +++++++++ .../samples/sample_helper.py | 86 +++++++++ .../samples/transaction_sample.py | 82 +++++++++ 14 files changed, 915 insertions(+) create mode 100644 packages/sqlalchemy-spanner/samples/README.md create mode 100644 packages/sqlalchemy-spanner/samples/bit_reversed_sequence_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/date_and_timestamp_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/default_column_value_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/generated_column_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/hello_world_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/insert_data_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/interleaved_table_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/model.py create mode 100644 packages/sqlalchemy-spanner/samples/noxfile.py create mode 100644 packages/sqlalchemy-spanner/samples/sample_helper.py create mode 100644 packages/sqlalchemy-spanner/samples/transaction_sample.py diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index b234dc03dd69..23f28e197e37 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -53,6 +53,22 @@ jobs: - name: Run mockserver tests run: nox -s mockserver + samples: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Install nox + run: python -m pip install nox + - name: Run samples + run: nox -s _all_samples + working-directory: samples + compliance_tests_13: runs-on: ubuntu-latest diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 25cde4598d2c..5c39e1397d58 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -58,6 +58,13 @@ Next install the package from the package ``setup.py`` file: During setup the dialect will be registered with entry points. +Samples +------------- + +The `samples directory `__ +contains multiple examples for how to configure and use common Spanner features. + + A Minimal App ------------- diff --git a/packages/sqlalchemy-spanner/samples/README.md b/packages/sqlalchemy-spanner/samples/README.md new file mode 100644 index 000000000000..7ebf7e9e0969 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/README.md @@ -0,0 +1,30 @@ +# Spanner SQLAlchemy Samples + +This folder contains samples for how to use common Spanner features with SQLAlchemy. The samples use +a shared [data model](model.py) and can be executed as a standalone application. The samples +automatically start the [Spanner Emulator](https://cloud.google.com/spanner/docs/emulator) in a +Docker container when they are executed. You must therefore have Docker installed on your system to +run a sample. + +You can run a sample with `nox`: + +```shell +nox -s hello_world +``` + +Change `hello_world` to run any of the other sample names. The runnable samples all end with +`_sample.py`. Omit the `_sample.py` part of the file name to run the sample. + + + +| Sample name | Description | +|-----------------------|-----------------------------------------------------------------------------| +| bit_reversed_sequence | Use a bit-reversed sequence for primary key generation. | +| date_and_timestamp | Map Spanner DATE and TIMESTAMP columns to SQLAlchemy. | +| default_column_value | Create and use a Spanner DEFAULT column constraint in SQLAlchemy. | +| generated_column | Create and use a Spanner generated column in SQLAlchemy. | +| hello_world | Shows how to connect to Spanner with SQLAlchemy and execute a simple query. | +| insert_data | Insert multiple rows to Spanner with SQLAlchemy. | +| interleaved_table | Create and use an interleaved table (INTERLEAVE IN PARENT) with SQLAlchemy. | +| transaction | Execute a read/write transaction on Spanner with SQLAlchemy. | + diff --git a/packages/sqlalchemy-spanner/samples/bit_reversed_sequence_sample.py b/packages/sqlalchemy-spanner/samples/bit_reversed_sequence_sample.py new file mode 100644 index 000000000000..bd7d80ceb52e --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/bit_reversed_sequence_sample.py @@ -0,0 +1,70 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Concert, Venue, TicketSale + + +# Shows how to use a bit-reversed sequence for primary key generation. +# +# The TicketSale model uses a bit-reversed sequence for automatic primary key +# generation: +# +# id: Mapped[int] = mapped_column( +# BigInteger, +# Sequence("ticket_sale_id"), +# server_default=TextClause("GET_NEXT_SEQUENCE_VALUE(SEQUENCE ticket_sale_id)"), +# primary_key=True, +# ) +# +# This leads to the following table definition: +# +# CREATE TABLE ticket_sales ( +# id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(SEQUENCE ticket_sale_id)), +# ... +# ) PRIMARY KEY (id) +def bit_reversed_sequence_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + singer = Singer(id=str(uuid.uuid4()), first_name="John", last_name="Doe") + venue = Venue(code="CH", name="Concert Hall", active=True) + concert = Concert( + venue=venue, + start_time=datetime.datetime(2024, 11, 7, 19, 30, 0), + singer=singer, + title="John Doe - Live in Concert Hall", + ) + # TicketSale automatically generates a primary key value using a + # bit-reversed sequence. We therefore do not need to specify a primary + # key value when we create an instance of TicketSale. + ticket_sale = TicketSale( + concert=concert, customer_name="Alice Doe", seats=["A010", "A011", "A012"] + ) + session.add_all([singer, venue, concert, ticket_sale]) + session.commit() + + +if __name__ == "__main__": + run_sample(bit_reversed_sequence_sample) diff --git a/packages/sqlalchemy-spanner/samples/date_and_timestamp_sample.py b/packages/sqlalchemy-spanner/samples/date_and_timestamp_sample.py new file mode 100644 index 000000000000..442ec6117492 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/date_and_timestamp_sample.py @@ -0,0 +1,64 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Concert, Venue + + +# Shows how to map and use the DATE and TIMESTAMP data types in Spanner. +def date_and_timestamp_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + # Singer has a property birthdate, which is mapped to a DATE column. + # Use the datetime.date type for this. + singer = Singer( + id=str(uuid.uuid4()), + first_name="John", + last_name="Doe", + birthdate=datetime.date(1979, 10, 14), + ) + venue = Venue(code="CH", name="Concert Hall", active=True) + # Concert has a property `start_time`, which is mapped to a TIMESTAMP + # column. Use the datetime.datetime type for this. + concert = Concert( + venue=venue, + start_time=datetime.datetime(2024, 11, 7, 19, 30, 0), + singer=singer, + title="John Doe - Live in Concert Hall", + ) + session.add_all([singer, venue, concert]) + session.commit() + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + print( + f"{singer.full_name}, born on {singer.birthdate}, has planned " + f"a concert that starts on {concert.start_time} in {venue.name}." + ) + + +if __name__ == "__main__": + run_sample(date_and_timestamp_sample) diff --git a/packages/sqlalchemy-spanner/samples/default_column_value_sample.py b/packages/sqlalchemy-spanner/samples/default_column_value_sample.py new file mode 100644 index 000000000000..82ecf566f6f4 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/default_column_value_sample.py @@ -0,0 +1,61 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Album, Track + + +# Shows how to use a default column with SQLAlchemy and Spanner. +def default_column_value_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + # The Track model has a `recorded_at` property that is set to + # CURRENT_TIMESTAMP if no other value is supplied. + singer = Singer(id=str(uuid.uuid4()), first_name="John", last_name="Doe") + album = Album(id=str(uuid.uuid4()), title="My album", singer=singer) + + # This track will use the default CURRENT_TIMESTAMP for the recorded_at + # property. + track1 = Track( + id=str(uuid.uuid4()), + track_number=1, + title="My track 1", + album=album, + ) + track2 = Track( + id=str(uuid.uuid4()), + track_number=2, + title="My track 2", + recorded_at=datetime.datetime(2024, 11, 7, 10, 0, 0), + album=album, + ) + session.add_all([singer, album, track1, track2]) + session.commit() + print(f"Track 1 was recorded at: " f"{track1.recorded_at}") + print(f"Track 2 was recorded at: " f"{track2.recorded_at}") + + +if __name__ == "__main__": + run_sample(default_column_value_sample) diff --git a/packages/sqlalchemy-spanner/samples/generated_column_sample.py b/packages/sqlalchemy-spanner/samples/generated_column_sample.py new file mode 100644 index 000000000000..fe6b157ba287 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/generated_column_sample.py @@ -0,0 +1,50 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer + + +# Shows how to use a generated column with SQLAlchemy and Spanner. +def generated_column_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + # The Singer model has a `full_name` property that is generated by the + # database. + singer = Singer(id=str(uuid.uuid4()), first_name="John", last_name="Doe") + session.add(singer) + session.commit() + print( + f"The database generated a full name for the singer: " f"{singer.full_name}" + ) + + # Updating the first name or last name of the singer will also update + # the generated full name property. + singer.last_name = "Jones" + session.commit() + print(f"Updated full name for singer: " f"{singer.full_name}") + + +if __name__ == "__main__": + run_sample(generated_column_sample) diff --git a/packages/sqlalchemy-spanner/samples/hello_world_sample.py b/packages/sqlalchemy-spanner/samples/hello_world_sample.py new file mode 100644 index 000000000000..57f676c14cb1 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/hello_world_sample.py @@ -0,0 +1,31 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine, select, text +from sample_helper import run_sample + + +def quickstart(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database" + ) + with engine.connect().execution_options(isolation_level="AUTOCOMMIT") as connection: + results = connection.execute(select(text("'Hello World!'"))).fetchall() + print("\nMessage from Spanner: ", results[0][0], "\n") + + +if __name__ == "__main__": + run_sample(quickstart) diff --git a/packages/sqlalchemy-spanner/samples/insert_data_sample.py b/packages/sqlalchemy-spanner/samples/insert_data_sample.py new file mode 100644 index 000000000000..a415e621ff39 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/insert_data_sample.py @@ -0,0 +1,73 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Album, Track + +# Shows how to insert data using SQLAlchemy, including relationships that are +# defined both as foreign keys and as interleaved tables. +def insert_data(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + singer = Singer( + id=str(uuid.uuid4()), + first_name="John", + last_name="Smith", + albums=[ + Album( + id=str(uuid.uuid4()), + title="Rainforest", + tracks=[ + # Track is INTERLEAVED IN PARENT Album, but can be treated + # as a normal relationship in SQLAlchemy. + Track(track_number=1, title="Green"), + Track(track_number=2, title="Blue"), + Track(track_number=3, title="Yellow"), + ], + ), + Album( + id=str(uuid.uuid4()), + title="Butterflies", + tracks=[ + Track(track_number=1, title="Purple"), + Track(track_number=2, title="Cyan"), + Track(track_number=3, title="Mauve"), + ], + ), + ], + ) + session.add(singer) + session.commit() + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + print( + f"Inserted singer {singer.full_name} with {len(singer.albums)} " + f"albums successfully" + ) + + +if __name__ == "__main__": + run_sample(insert_data) diff --git a/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py b/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py new file mode 100644 index 000000000000..0d6521593e1d --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py @@ -0,0 +1,98 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Album, Track + +# Shows how INTERLEAVE IN PARENT can be used in SQLAlchemy. +# INTERLEAVE IN PARENT can be modelled as if it were a normal relationship +# in SQLAlchemy. SQLAlchemy can also generate the correct DDL for this. +# +# This sample uses the following table structure: +# CREATE TABLE albums ( +# id STRING(36) NOT NULL, +# title STRING(200) NOT NULL, +# release_date DATE, +# singer_id STRING(36) NOT NULL, +# FOREIGN KEY(singer_id) REFERENCES singers (id) +# ) PRIMARY KEY (id); +# +# CREATE TABLE tracks ( +# id STRING(36) NOT NULL, +# track_number INT64 NOT NULL, +# title STRING(200) NOT NULL, +# duration NUMERIC +# ) PRIMARY KEY (id, track_number), +# INTERLEAVE IN PARENT albums ON DELETE CASCADE +# +# See model.py for the full model definitions. +def interleaved_table(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + # Insert a Singer row, two Albums, and six Tracks. + # Track is INTERLEAVED IN PARENT Album. + singer = Singer( + id=str(uuid.uuid4()), + first_name="John", + last_name="Smith", + albums=[ + Album( + id=str(uuid.uuid4()), + title="Rainforest", + tracks=[ + # Track is INTERLEAVED IN PARENT Album, but can be treated + # as a normal relationship in SQLAlchemy. + Track(track_number=1, title="Green"), + Track(track_number=2, title="Blue"), + Track(track_number=3, title="Yellow"), + ], + ), + Album( + id=str(uuid.uuid4()), + title="Butterflies", + tracks=[ + Track(track_number=1, title="Purple"), + Track(track_number=2, title="Cyan"), + Track(track_number=3, title="Mauve"), + ], + ), + ], + ) + session.add(singer) + session.commit() + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + # We can iterate over the tracks of an album as if it were a normal + # relationship. + print(f"Singer {singer.full_name} has these albums:") + for album in singer.albums: + print(f"\tAlbum {album.title} has these tracks:") + for track in album.tracks: + print(f"\t\t{track.track_number} - {track.title}") + + +if __name__ == "__main__": + run_sample(interleaved_table) diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py new file mode 100644 index 000000000000..13a4c83d757a --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -0,0 +1,167 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +from typing import Optional, List + +from sqlalchemy import ( + String, + Computed, + Date, + LargeBinary, + Integer, + Numeric, + ForeignKey, + JSON, + Boolean, + DateTime, + BigInteger, + ARRAY, + ForeignKeyConstraint, + Sequence, + TextClause, + func, + FetchedValue, +) +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship + + +class Base(DeclarativeBase): + pass + + +# Most models in this sample use a client-side generated UUID as primary key. +# This allows inserts to use Batch DML, as the primary key value does not need +# to be returned from Spanner using a THEN RETURN clause. +# +# The TicketSale model uses a bit-reversed sequence for primary key generation. +# This is achieved by creating a bit-reversed sequence and assigning the id +# column of the model a server_default value that gets the next value from that +# sequence. + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[str] = mapped_column(String(36), primary_key=True) + first_name: Mapped[Optional[str]] = mapped_column(String(200), nullable=True) + last_name: Mapped[str] = mapped_column(String(200), nullable=False) + full_name: Mapped[str] = mapped_column( + String, Computed("COALESCE(first_name || ' ', '') || last_name") + ) + birthdate: Mapped[Optional[datetime.date]] = mapped_column(Date, nullable=True) + picture: Mapped[Optional[bytes]] = mapped_column(LargeBinary, nullable=True) + albums: Mapped[List["Album"]] = relationship( + back_populates="singer", cascade="all, delete-orphan" + ) + concerts: Mapped[List["Concert"]] = relationship( + back_populates="singer", cascade="all, delete-orphan" + ) + + +class Album(Base): + __tablename__ = "albums" + id: Mapped[str] = mapped_column(String(36), primary_key=True) + title: Mapped[str] = mapped_column(String(200), nullable=False) + release_date: Mapped[Optional[datetime.date]] = mapped_column(Date, nullable=True) + singer_id: Mapped[str] = mapped_column(ForeignKey("singers.id")) + singer: Mapped["Singer"] = relationship(back_populates="albums") + tracks: Mapped[List["Track"]] = relationship( + back_populates="album", + primaryjoin="Album.id == foreign(Track.id)", + order_by="Track.track_number", + ) + + +class Track(Base): + __tablename__ = "tracks" + # This interleaves the table `tracks` in its parent `albums`. + __table_args__ = { + "spanner_interleave_in": "albums", + "spanner_interleave_on_delete_cascade": True, + } + id: Mapped[str] = mapped_column(String(36), primary_key=True) + track_number: Mapped[int] = mapped_column(Integer, primary_key=True) + title: Mapped[str] = mapped_column(String(200), nullable=False) + duration: Mapped[Optional[float]] = mapped_column(Numeric, nullable=True) + recorded_at: Mapped[Optional[datetime.datetime]] = mapped_column( + DateTime, + nullable=True, + # TODO: Enable this once 'func.now()' is mapped to CURRENT_TIMESTAMP + # server_default=func.now(), + server_default=TextClause("CURRENT_TIMESTAMP"), + ) + album: Mapped["Album"] = relationship( + back_populates="tracks", + foreign_keys=[id], + primaryjoin="Track.id == Album.id", + remote_side="Album.id", + ) + + +# SQLAlchemy does not know what 'spanner_interleave_in' means, so we need to +# explicitly tell SQLAlchemy that `tracks` depends on `albums`, and that +# `albums` therefore must be created before `tracks`. +Track.__table__.add_is_dependent_on(Album.__table__) + + +class Venue(Base): + __tablename__ = "venues" + code: Mapped[str] = mapped_column(String(10), primary_key=True) + name: Mapped[str] = mapped_column(String(200), nullable=False) + description: Mapped[str] = mapped_column(JSON, nullable=True) + active: Mapped[bool] = mapped_column(Boolean, nullable=False) + concerts: Mapped[List["Concert"]] = relationship( + back_populates="venue", cascade="all, delete-orphan" + ) + + +class Concert(Base): + __tablename__ = "concerts" + venue_code: Mapped[str] = mapped_column( + String(10), ForeignKey("venues.code"), primary_key=True + ) + start_time: Mapped[Optional[datetime.datetime]] = mapped_column( + DateTime, primary_key=True, nullable=False + ) + singer_id: Mapped[str] = mapped_column( + String(36), ForeignKey("singers.id"), primary_key=True + ) + title: Mapped[str] = mapped_column(String(200), nullable=False) + singer: Mapped["Singer"] = relationship(back_populates="concerts") + venue: Mapped["Venue"] = relationship(back_populates="concerts") + ticket_sales: Mapped[List["TicketSale"]] = relationship(back_populates="concert") + + +class TicketSale(Base): + __tablename__ = "ticket_sales" + __table_args__ = ( + ForeignKeyConstraint( + ["venue_code", "start_time", "singer_id"], + ["concerts.venue_code", "concerts.start_time", "concerts.singer_id"], + ), + ) + id: Mapped[int] = mapped_column( + BigInteger, + Sequence("ticket_sale_id"), + server_default=TextClause("GET_NEXT_SEQUENCE_VALUE(SEQUENCE ticket_sale_id)"), + primary_key=True, + ) + customer_name: Mapped[str] = mapped_column(String(200), nullable=False) + seats: Mapped[list[str]] = mapped_column(ARRAY(String(20)), nullable=False) + concert: Mapped["Concert"] = relationship(back_populates="ticket_sales") + venue_code: Mapped[str] = mapped_column(String(10), ForeignKey("venues.code")) + start_time: Mapped[Optional[datetime.datetime]] = mapped_column( + DateTime, nullable=False + ) + singer_id: Mapped[str] = mapped_column(String(36), ForeignKey("singers.id")) diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py new file mode 100644 index 000000000000..b103fd77df76 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -0,0 +1,80 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from os import listdir +from os.path import isfile, join + +import nox + + +@nox.session() +def hello_world(session): + _sample(session) + + +@nox.session() +def bit_reversed_sequence(session): + _sample(session) + + +@nox.session() +def date_and_timestamp(session): + _sample(session) + + +@nox.session() +def default_column_value(session): + _sample(session) + + +@nox.session() +def generated_column(session): + _sample(session) + + +@nox.session() +def insert_data(session): + _sample(session) + + +@nox.session() +def interleaved_table(session): + _sample(session) + + +@nox.session() +def transaction(session): + _sample(session) + + +@nox.session() +def _all_samples(session): + _sample(session) + + +def _sample(session): + session.install("testcontainers") + session.install("sqlalchemy") + session.install("setuptools") + session.install( + "git+https://github.com/googleapis/python-spanner.git#egg=google-cloud-spanner" + ) + session.install("../.") + if session.name == "_all_samples": + files = [ + f for f in listdir(".") if isfile(join(".", f)) and f.endswith("_sample.py") + ] + for file in files: + session.run("python", file) + else: + session.run("python", session.name + "_sample.py") diff --git a/packages/sqlalchemy-spanner/samples/sample_helper.py b/packages/sqlalchemy-spanner/samples/sample_helper.py new file mode 100644 index 000000000000..862d535d3bae --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/sample_helper.py @@ -0,0 +1,86 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from typing import Callable + +from google.api_core.client_options import ClientOptions +from google.auth.credentials import AnonymousCredentials +from google.cloud.spanner_v1 import Client +from sqlalchemy import create_engine +from sqlalchemy.dialects import registry +from testcontainers.core.container import DockerContainer +from testcontainers.core.waiting_utils import wait_for_logs + +from model import Base + + +def run_sample(sample_method: Callable): + registry.register( + "spanner", + "google.cloud.sqlalchemy_spanner.sqlalchemy_spanner", + "SpannerDialect", + ) + os.environ["SPANNER_EMULATOR_HOST"] = "" + emulator, port = start_emulator() + os.environ["SPANNER_EMULATOR_HOST"] = "localhost:" + str(port) + try: + _create_tables() + sample_method() + finally: + if emulator is not None: + emulator.stop() + + +def start_emulator() -> (DockerContainer, str): + emulator = DockerContainer( + "gcr.io/cloud-spanner-emulator/emulator" + ).with_exposed_ports(9010) + emulator.start() + wait_for_logs(emulator, "gRPC server listening at 0.0.0.0:9010") + port = emulator.get_exposed_port(9010) + _create_instance_and_database(port) + return emulator, port + + +def _create_instance_and_database(port: str): + client = Client( + project="sample-project", + credentials=AnonymousCredentials(), + client_options=ClientOptions( + api_endpoint="localhost:" + port, + ), + ) + configs = list(client.list_instance_configs()) + instance_config = configs[0].name + instance_id = "sample-instance" + database_id = "sample-database" + + instance = client.instance(instance_id, instance_config) + created_op = instance.create() + created_op.result(1800) # block until completion + + database = instance.database(database_id) + created_op = database.create() + created_op.result(1800) + + +def _create_tables(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + Base.metadata.create_all(engine) diff --git a/packages/sqlalchemy-spanner/samples/transaction_sample.py b/packages/sqlalchemy-spanner/samples/transaction_sample.py new file mode 100644 index 000000000000..b1f42ede86db --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/transaction_sample.py @@ -0,0 +1,82 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Concert, Venue + + +# Shows how to execute a read/write transaction on Spanner using SQLAlchemy. +def transaction_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + # SQLAlchemy by default automatically starts a transaction the first + # time the database is accessed. + singer_id = str(uuid.uuid4()) + singer = Singer(id=singer_id, first_name="John", last_name="Doe") + session.add(singer) + # Flush the session. This pushes all changes in this session to the + # database without committing the current transaction. + session.flush([singer]) + + # Verify that we can read this singer from the database during the + # same transaction. The Singer model has a `full_name` property that is + # generated by the database. This will be read from the database when + # we call refresh. + session.refresh(singer) + print( + f"The database generated a full name for the singer: " f"{singer.full_name}" + ) + + # We cannot read the singer in a different session, as the current + # transaction has not yet committed. + # We use AUTOCOMMIT for the additional session, as we do not need a + # read/write transaction for just trying to read one row. + with Session( + engine.execution_options(isolation_level="AUTOCOMMIT") + ) as session2: + # singer2 will be None, as the row will not be found. + singer2 = session2.get(Singer, singer_id) + print( + f"Fetching singer in a different transaction before the " + f"transaction was committed: {singer2}" + ) + + session.commit() + + # Now that the original transaction has committed, we can read the + # singer in a different session. + with Session( + engine.execution_options(isolation_level="AUTOCOMMIT") + ) as session2: + # singer2 will now return the actual row. + singer2 = session2.get(Singer, singer_id) + print( + f"Fetching singer in a different transaction after the " + f"transaction was committed: {singer2.full_name}" + ) + + +if __name__ == "__main__": + run_sample(transaction_sample) From ecba797f61b292cceb94719c8c698d58626985b8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 14:55:47 +0100 Subject: [PATCH 326/582] chore(deps): update dependency opentelemetry-api to v1.28.2 (#504) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 9a0a96f8299c..d32ce3085147 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -317,9 +317,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.28.0 \ - --hash=sha256:578610bcb8aa5cdcb11169d136cc752958548fb6ccffb0969c1036b0ee9e5353 \ - --hash=sha256:8457cd2c59ea1bd0988560f021656cecd254ad7ef6be4ba09dbefeca2409ce52 +opentelemetry-api==1.28.2 \ + --hash=sha256:6fcec89e265beb258fe6b1acaaa3c8c705a934bd977b9f534a2b7c0d2d4275a6 \ + --hash=sha256:ecdc70c7139f17f9b0cf3742d57d7020e3e8315d6cffcdf1a12a905d45b19cc0 # via # -r requirements.in # opentelemetry-instrumentation From 0ec696d35de189e9da3a5a4d43cdf991dd526e07 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 14:57:54 +0100 Subject: [PATCH 327/582] chore(deps): update dependency opentelemetry-sdk to v1.28.2 (#505) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d32ce3085147..b8f26e7a01d2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -329,9 +329,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.28.0 \ - --hash=sha256:41d5420b2e3fb7716ff4981b510d551eff1fc60eb5a95cf7335b31166812a893 \ - --hash=sha256:4b37da81d7fad67f6683c4420288c97f4ed0d988845d5886435f428ec4b8429a +opentelemetry-sdk==1.28.2 \ + --hash=sha256:5fed24c5497e10df30282456fe2910f83377797511de07d14cec0d3e0a1a3110 \ + --hash=sha256:93336c129556f1e3ccd21442b94d3521759541521861b2214c499571b85cb71b # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 5099d2206f956e418b7e784bb4ef0259ced3f047 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 14:58:55 +0100 Subject: [PATCH 328/582] chore(deps): update dependency zipp to v3.21.0 (#507) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 3339b12b913b..b39eaf5c38cd 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -614,7 +614,7 @@ wheel==0.44.0 \ --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 # via -r requirements.in -zipp==3.20.2 \ - --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ - --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 +zipp==3.21.0 \ + --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ + --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 # via importlib-metadata diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index b8f26e7a01d2..02019bc3c9e8 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -562,9 +562,9 @@ wrapt==1.16.0 \ # via # deprecated # opentelemetry-instrumentation -zipp==3.20.2 \ - --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \ - --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29 +zipp==3.21.0 \ + --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ + --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be From 7f15bb1a40d8d9e23f551add80080ec2669c4535 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:01:16 +0100 Subject: [PATCH 329/582] chore(deps): update dependency wheel to v0.45.1 (#506) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b39eaf5c38cd..adec3916cfbe 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -610,9 +610,9 @@ webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 # via bleach -wheel==0.44.0 \ - --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ - --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 +wheel==0.45.1 \ + --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ + --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via -r requirements.in zipp==3.21.0 \ --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 02019bc3c9e8..272f9305e19f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -484,9 +484,9 @@ urllib3==2.2.3 \ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 # via requests -wheel==0.44.0 \ - --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ - --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 +wheel==0.45.1 \ + --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ + --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via pip-tools wrapt==1.16.0 \ --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ From a5ad42e29e570aa2c12cc560be60155753c4a079 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:01:30 +0100 Subject: [PATCH 330/582] chore(deps): update dependency google-cloud-spanner to v3.50.1 (#508) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 272f9305e19f..90ad9bab7c4d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -157,9 +157,9 @@ google-cloud-core==2.4.1 \ --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-spanner -google-cloud-spanner==3.49.1 \ - --hash=sha256:261eafb63b0dd55256afcb5f7149b7527e55b5c8aca8059f77771dfe935ab03b \ - --hash=sha256:c064d1175319f8c9b634a3888de226f4ec70493f7ec08a45321a4b17a47fc3ca +google-cloud-spanner==3.50.1 \ + --hash=sha256:82937ea03b55de86bddf622f555aeae65ae86bb4f28ab35bd920ac505917c9bf \ + --hash=sha256:9d399aa53fae58816023a4eb31fa267333c3a879a9221229e7f06fdda543884a # via -r requirements.in googleapis-common-protos[grpc]==1.65.0 \ --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ From 2b7f6e2a45df0092b35ab73d60fb38f354abcad0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:01:43 +0100 Subject: [PATCH 331/582] chore(deps): update dependency google-api-core to v2.23.0 (#509) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index adec3916cfbe..d85d9cdfd03c 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -269,9 +269,9 @@ gcp-releasetool==2.2.0 \ --hash=sha256:9ca3a41d397485bb7f6ad7933d64d9071961188f41fc0182e47562b41cebaff2 \ --hash=sha256:ae0fc2525fdf1eb4638059dee3ec265620e1a85cb89f564615793698b3b422d6 # via -r requirements.in -google-api-core==2.22.0 \ - --hash=sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35 \ - --hash=sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021 +google-api-core==2.23.0 \ + --hash=sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace \ + --hash=sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f # via # google-cloud-core # google-cloud-storage diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 90ad9bab7c4d..c5afe2824c14 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -141,9 +141,9 @@ deprecated==1.2.14 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.22.0 \ - --hash=sha256:26f8d76b96477db42b55fd02a33aae4a42ec8b86b98b94969b7333a2c828bf35 \ - --hash=sha256:a6652b6bd51303902494998626653671703c420f6f4c88cfd3f50ed723e9d021 +google-api-core[grpc]==2.23.0 \ + --hash=sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace \ + --hash=sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f # via # google-cloud-core # google-cloud-spanner From bd1c5abfc58ed869faf6ea9f8ada63d02f022a7c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:01:56 +0100 Subject: [PATCH 332/582] chore(deps): update dependency tomli to v2.1.0 (#510) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d85d9cdfd03c..1754187b85c2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -584,9 +584,9 @@ six==1.16.0 \ # via # gcp-docuploader # python-dateutil -tomli==2.0.2 \ - --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ - --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +tomli==2.1.0 \ + --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ + --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 # via -r requirements.in twine==5.1.1 \ --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c5afe2824c14..a603f6b40a8f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -469,9 +469,9 @@ sqlparse==0.5.1 \ --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e # via google-cloud-spanner -tomli==2.0.2 \ - --hash=sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38 \ - --hash=sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed +tomli==2.1.0 \ + --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ + --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 # via -r requirements.in typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ From 2cd278eec7c2569213c95591d4ad945e2a1e77e3 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:02:08 +0100 Subject: [PATCH 333/582] chore(deps): update dependency gcp-releasetool to v2.3.0 (#511) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 1754187b85c2..b37bdaf2e6d2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -265,9 +265,9 @@ gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea # via -r requirements.in -gcp-releasetool==2.2.0 \ - --hash=sha256:9ca3a41d397485bb7f6ad7933d64d9071961188f41fc0182e47562b41cebaff2 \ - --hash=sha256:ae0fc2525fdf1eb4638059dee3ec265620e1a85cb89f564615793698b3b422d6 +gcp-releasetool==2.3.0 \ + --hash=sha256:510516c6a2135e55503fd58f5c8e9d93506d8fba4ebed381a1eccb3d8f9b6740 \ + --hash=sha256:804547a3d2e022924bceadcc453fc49e3059a42a607b99e55b1e2a2d10cb5323 # via -r requirements.in google-api-core==2.23.0 \ --hash=sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace \ From 70d6e166258549d883a8a0f674cc9b8149511d2c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:02:21 +0100 Subject: [PATCH 334/582] chore(deps): update dependency googleapis-common-protos to v1.66.0 (#512) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b37bdaf2e6d2..0a1623febc05 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -326,9 +326,9 @@ google-resumable-media==2.7.2 \ --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 # via google-cloud-storage -googleapis-common-protos==1.65.0 \ - --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ - --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 +googleapis-common-protos==1.66.0 \ + --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ + --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a603f6b40a8f..207d1a371fe1 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -161,9 +161,9 @@ google-cloud-spanner==3.50.1 \ --hash=sha256:82937ea03b55de86bddf622f555aeae65ae86bb4f28ab35bd920ac505917c9bf \ --hash=sha256:9d399aa53fae58816023a4eb31fa267333c3a879a9221229e7f06fdda543884a # via -r requirements.in -googleapis-common-protos[grpc]==1.65.0 \ - --hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \ - --hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0 +googleapis-common-protos[grpc]==1.66.0 \ + --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ + --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed # via # google-api-core # grpc-google-iam-v1 From 7e76ba6a19f63c18b85513a3b2164893c4873388 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:03:00 +0100 Subject: [PATCH 335/582] chore(deps): update dependency sqlparse to v0.5.2 (#513) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 207d1a371fe1..1e721b70ee3a 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -465,9 +465,9 @@ sqlalchemy==2.0.36 \ # via # -r requirements.in # alembic -sqlparse==0.5.1 \ - --hash=sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4 \ - --hash=sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e +sqlparse==0.5.2 \ + --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ + --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e # via google-cloud-spanner tomli==2.1.0 \ --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ From 0bc6261845734aa72c745e132ef7715b60c63fa8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:14:05 +0100 Subject: [PATCH 336/582] chore(deps): update dependency deprecated to v1.2.15 (#515) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1e721b70ee3a..8e34354ccd40 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -135,9 +135,9 @@ click==8.1.7 \ # via # -r requirements.in # pip-tools -deprecated==1.2.14 \ - --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \ - --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3 +Deprecated==1.2.15 \ + --hash=sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320 \ + --hash=sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d # via # opentelemetry-api # opentelemetry-semantic-conventions From 1a756ec2c55020b4374224f1c8928499924d5d0d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:14:27 +0100 Subject: [PATCH 337/582] chore(deps): update dependency grpcio to v1.68.0 (#516) --- packages/sqlalchemy-spanner/requirements.txt | 112 +++++++++---------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8e34354ccd40..5410b3946c48 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -176,62 +176,62 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.67.1 \ - --hash=sha256:01f616a964e540638af5130469451cf580ba8c7329f45ca998ab66e0c7dcdb04 \ - --hash=sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292 \ - --hash=sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955 \ - --hash=sha256:0f3e49c738396e93b7ba9016e153eb09e0778e776df6090c1b8c91877cc1c426 \ - --hash=sha256:178f5db771c4f9a9facb2ab37a434c46cb9be1a75e820f187ee3d1e7805c4f65 \ - --hash=sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970 \ - --hash=sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e \ - --hash=sha256:24e8a26dbfc5274d7474c27759b54486b8de23c709d76695237515bc8b5baeab \ - --hash=sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953 \ - --hash=sha256:299b3d8c4f790c6bcca485f9963b4846dd92cf6f1b65d3697145d005c80f9fe8 \ - --hash=sha256:3b6c16489326d79ead41689c4b84bc40d522c9a7617219f4ad94bc7f448c5085 \ - --hash=sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732 \ - --hash=sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f \ - --hash=sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af \ - --hash=sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78 \ - --hash=sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc \ - --hash=sha256:5db70d32d6703b89912af16d6d45d78406374a8b8ef0d28140351dd0ec610e98 \ - --hash=sha256:5ed601c4c6008429e3d247ddb367fe8c7259c355757448d7c1ef7bd4a6739e8e \ - --hash=sha256:60336bff760fbb47d7e86165408126f1dded184448e9a4c892189eb7c9d3f90f \ - --hash=sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e \ - --hash=sha256:60e6a4dcf5af7bbc36fd9f81c9f372e8ae580870a9e4b6eafe948cd334b81cf3 \ - --hash=sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed \ - --hash=sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38 \ - --hash=sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb \ - --hash=sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5 \ - --hash=sha256:804c6457c3cd3ec04fe6006c739579b8d35c86ae3298ffca8de57b493524b771 \ - --hash=sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc \ - --hash=sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb \ - --hash=sha256:85f862069b86a305497e74d0dc43c02de3d1d184fc2c180993aa8aa86fbd19b8 \ - --hash=sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75 \ - --hash=sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f \ - --hash=sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f \ - --hash=sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb \ - --hash=sha256:95b5f2b857856ed78d72da93cd7d09b6db8ef30102e5e7fe0961fe4d9f7d48e8 \ - --hash=sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8 \ - --hash=sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311 \ - --hash=sha256:a25bdea92b13ff4d7790962190bf6bf5c4639876e01c0f3dda70fc2769616335 \ - --hash=sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62 \ - --hash=sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af \ - --hash=sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b \ - --hash=sha256:b49359977c6ec9f5d0573ea4e0071ad278ef905aa74e420acc73fd28ce39e9ce \ - --hash=sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1 \ - --hash=sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f \ - --hash=sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0 \ - --hash=sha256:cdc491ae35a13535fd9196acb5afe1af37c8237df2e54427be3eecda3653127e \ - --hash=sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121 \ - --hash=sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744 \ - --hash=sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa \ - --hash=sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e \ - --hash=sha256:ec74ef02010186185de82cc594058a3ccd8d86821842bbac9873fd4a2cf8be8d \ - --hash=sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0 \ - --hash=sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d \ - --hash=sha256:f5b76ff64aaac53fede0cc93abf57894ab2a7362986ba22243d06218b93efe46 \ - --hash=sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96 \ - --hash=sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba +grpcio==1.68.0 \ + --hash=sha256:0d230852ba97654453d290e98d6aa61cb48fa5fafb474fb4c4298d8721809354 \ + --hash=sha256:0efbbd849867e0e569af09e165363ade75cf84f5229b2698d53cf22c7a4f9e21 \ + --hash=sha256:14331e5c27ed3545360464a139ed279aa09db088f6e9502e95ad4bfa852bb116 \ + --hash=sha256:15327ab81131ef9b94cb9f45b5bd98803a179c7c61205c8c0ac9aff9d6c4e82a \ + --hash=sha256:15377bce516b1c861c35e18eaa1c280692bf563264836cece693c0f169b48829 \ + --hash=sha256:15fa1fe25d365a13bc6d52fcac0e3ee1f9baebdde2c9b3b2425f8a4979fccea1 \ + --hash=sha256:18668e36e7f4045820f069997834e94e8275910b1f03e078a6020bd464cb2363 \ + --hash=sha256:2af76ab7c427aaa26aa9187c3e3c42f38d3771f91a20f99657d992afada2294a \ + --hash=sha256:2bddd04a790b69f7a7385f6a112f46ea0b34c4746f361ebafe9ca0be567c78e9 \ + --hash=sha256:32a9cb4686eb2e89d97022ecb9e1606d132f85c444354c17a7dbde4a455e4a3b \ + --hash=sha256:3ac7f10850fd0487fcce169c3c55509101c3bde2a3b454869639df2176b60a03 \ + --hash=sha256:3b2b559beb2d433129441783e5f42e3be40a9e1a89ec906efabf26591c5cd415 \ + --hash=sha256:4028b8e9a3bff6f377698587d642e24bd221810c06579a18420a17688e421af7 \ + --hash=sha256:44bcbebb24363d587472089b89e2ea0ab2e2b4df0e4856ba4c0b087c82412121 \ + --hash=sha256:46a2d74d4dd8993151c6cd585594c082abe74112c8e4175ddda4106f2ceb022f \ + --hash=sha256:4df81d78fd1646bf94ced4fb4cd0a7fe2e91608089c522ef17bc7db26e64effd \ + --hash=sha256:4e300e6978df0b65cc2d100c54e097c10dfc7018b9bd890bbbf08022d47f766d \ + --hash=sha256:4f1931c7aa85be0fa6cea6af388e576f3bf6baee9e5d481c586980c774debcb4 \ + --hash=sha256:50992f214264e207e07222703c17d9cfdcc2c46ed5a1ea86843d440148ebbe10 \ + --hash=sha256:55d3b52fd41ec5772a953612db4e70ae741a6d6ed640c4c89a64f017a1ac02b5 \ + --hash=sha256:5a180328e92b9a0050958ced34dddcb86fec5a8b332f5a229e353dafc16cd332 \ + --hash=sha256:619b5d0f29f4f5351440e9343224c3e19912c21aeda44e0c49d0d147a8d01544 \ + --hash=sha256:6b2f98165ea2790ea159393a2246b56f580d24d7da0d0342c18a085299c40a75 \ + --hash=sha256:6f9c7ad1a23e1047f827385f4713b5b8c6c7d325705be1dd3e31fb00dcb2f665 \ + --hash=sha256:79f81b7fbfb136247b70465bd836fa1733043fdee539cd6031cb499e9608a110 \ + --hash=sha256:7e0a3e72c0e9a1acab77bef14a73a416630b7fd2cbd893c0a873edc47c42c8cd \ + --hash=sha256:7e7483d39b4a4fddb9906671e9ea21aaad4f031cdfc349fec76bdfa1e404543a \ + --hash=sha256:88fb2925789cfe6daa20900260ef0a1d0a61283dfb2d2fffe6194396a354c618 \ + --hash=sha256:8af6137cc4ae8e421690d276e7627cfc726d4293f6607acf9ea7260bd8fc3d7d \ + --hash=sha256:8b0ff09c81e3aded7a183bc6473639b46b6caa9c1901d6f5e2cba24b95e59e30 \ + --hash=sha256:8c73f9fbbaee1a132487e31585aa83987ddf626426d703ebcb9a528cf231c9b1 \ + --hash=sha256:99f06232b5c9138593ae6f2e355054318717d32a9c09cdc5a2885540835067a1 \ + --hash=sha256:9fe1b141cda52f2ca73e17d2d3c6a9f3f3a0c255c216b50ce616e9dca7e3441d \ + --hash=sha256:a17278d977746472698460c63abf333e1d806bd41f2224f90dbe9460101c9796 \ + --hash=sha256:a59f5822f9459bed098ffbceb2713abbf7c6fd13f2b9243461da5c338d0cd6c3 \ + --hash=sha256:a6213d2f7a22c3c30a479fb5e249b6b7e648e17f364598ff64d08a5136fe488b \ + --hash=sha256:a831dcc343440969aaa812004685ed322cdb526cd197112d0db303b0da1e8659 \ + --hash=sha256:afbf45a62ba85a720491bfe9b2642f8761ff348006f5ef67e4622621f116b04a \ + --hash=sha256:b0cf343c6f4f6aa44863e13ec9ddfe299e0be68f87d68e777328bff785897b05 \ + --hash=sha256:c03d89df516128febc5a7e760d675b478ba25802447624edf7aa13b1e7b11e2a \ + --hash=sha256:c1245651f3c9ea92a2db4f95d37b7597db6b246d5892bca6ee8c0e90d76fb73c \ + --hash=sha256:cc5f0a4f5904b8c25729a0498886b797feb817d1fd3812554ffa39551112c161 \ + --hash=sha256:dba037ff8d284c8e7ea9a510c8ae0f5b016004f13c3648f72411c464b67ff2fb \ + --hash=sha256:def1a60a111d24376e4b753db39705adbe9483ef4ca4761f825639d884d5da78 \ + --hash=sha256:e0d2f68eaa0a755edd9a47d40e50dba6df2bceda66960dee1218da81a2834d27 \ + --hash=sha256:e0d30f3fee9372796f54d3100b31ee70972eaadcc87314be369360248a3dcffe \ + --hash=sha256:e18589e747c1e70b60fab6767ff99b2d0c359ea1db8a2cb524477f93cdbedf5b \ + --hash=sha256:e1e7ed311afb351ff0d0e583a66fcb39675be112d61e7cfd6c8269884a98afbc \ + --hash=sha256:e46541de8425a4d6829ac6c5d9b16c03c292105fe9ebf78cb1c31e8d242f9155 \ + --hash=sha256:e694b5928b7b33ca2d3b4d5f9bf8b5888906f181daff6b406f4938f3a997a490 \ + --hash=sha256:f60fa2adf281fd73ae3a50677572521edca34ba373a45b457b5ebe87c2d01e1d \ + --hash=sha256:f84890b205692ea813653ece4ac9afa2139eae136e419231b0eec7c39fdbe4c2 \ + --hash=sha256:f8f695d9576ce836eab27ba7401c60acaf9ef6cf2f70dfe5462055ba3df02cc3 \ + --hash=sha256:fc05759ffbd7875e0ff2bd877be1438dfe97c9312bbc558c8284a9afa1d0f40e \ + --hash=sha256:fd2c2d47969daa0e27eadaf15c13b5e92605c5e5953d23c06d0b5239a2f176d3 # via # google-api-core # googleapis-common-protos From 5121c95d74fb3c21acca914de36e5dfe18ed3ca0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:14:41 +0100 Subject: [PATCH 338/582] chore(deps): update dependency grpcio-status to v1.68.0 (#517) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 5410b3946c48..2fa958b99c2d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -238,9 +238,9 @@ grpcio==1.68.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.67.1 \ - --hash=sha256:16e6c085950bdacac97c779e6a502ea671232385e6e37f258884d6883392c2bd \ - --hash=sha256:2bf38395e028ceeecfd8866b081f61628114b384da7d51ae064ddc8d766a5d11 +grpcio-status==1.68.0 \ + --hash=sha256:0a71b15d989f02df803b4ba85c5bf1f43aeaa58ac021e5f9974b8cadc41f784d \ + --hash=sha256:8369823de22ab6a2cddb3804669c149ae7a71819e127c2dca7c2322028d52bea # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 9da0fde1bbfe33f5ad2650204d5fd9e83e9b0d32 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:15:01 +0100 Subject: [PATCH 339/582] chore(deps): update dependency pyjwt to v2.10.0 (#518) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 0a1623febc05..e7334f5cb816 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -530,9 +530,9 @@ pygments==2.18.0 \ # via # readme-renderer # rich -pyjwt==2.9.0 \ - --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \ - --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c +PyJWT==2.10.0 \ + --hash=sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15 \ + --hash=sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c # via gcp-releasetool pyparsing==3.2.0 \ --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ From dd3595aedae5938f8decffea4223fdb876ff832f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:16:39 +0100 Subject: [PATCH 340/582] chore(deps): update dependency virtualenv to v20.28.0 (#514) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e7334f5cb816..5136ca7405de 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -602,9 +602,9 @@ urllib3==2.2.3 \ # via # requests # twine -virtualenv==20.27.1 \ - --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \ - --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4 +virtualenv==20.28.0 \ + --hash=sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0 \ + --hash=sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa # via nox webencodings==0.5.1 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ From 1fa9c079bfbbe5f057c8c33f73424bdb2980635b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 26 Nov 2024 15:17:00 +0100 Subject: [PATCH 341/582] chore(deps): update dependency wrapt to v1.17.0 (#519) --- packages/sqlalchemy-spanner/requirements.txt | 137 +++++++++---------- 1 file changed, 66 insertions(+), 71 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2fa958b99c2d..0ea726d81496 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -488,77 +488,72 @@ wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via pip-tools -wrapt==1.16.0 \ - --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ - --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ - --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ - --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ - --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ - --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ - --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ - --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ - --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ - --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ - --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ - --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ - --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ - --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ - --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ - --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ - --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ - --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ - --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ - --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ - --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ - --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ - --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ - --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ - --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ - --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ - --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ - --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ - --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ - --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ - --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ - --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ - --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ - --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ - --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ - --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ - --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ - --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ - --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ - --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ - --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ - --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ - --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ - --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ - --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ - --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ - --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ - --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ - --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ - --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ - --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ - --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ - --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ - --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ - --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ - --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ - --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ - --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ - --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ - --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ - --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ - --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ - --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ - --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ - --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ - --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ - --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ - --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ - --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ - --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 +wrapt==1.17.0 \ + --hash=sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d \ + --hash=sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301 \ + --hash=sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635 \ + --hash=sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a \ + --hash=sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed \ + --hash=sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721 \ + --hash=sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801 \ + --hash=sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b \ + --hash=sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1 \ + --hash=sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88 \ + --hash=sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8 \ + --hash=sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0 \ + --hash=sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f \ + --hash=sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578 \ + --hash=sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7 \ + --hash=sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045 \ + --hash=sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada \ + --hash=sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d \ + --hash=sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b \ + --hash=sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a \ + --hash=sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977 \ + --hash=sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea \ + --hash=sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346 \ + --hash=sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13 \ + --hash=sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22 \ + --hash=sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339 \ + --hash=sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9 \ + --hash=sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181 \ + --hash=sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c \ + --hash=sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90 \ + --hash=sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a \ + --hash=sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489 \ + --hash=sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f \ + --hash=sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504 \ + --hash=sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea \ + --hash=sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569 \ + --hash=sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4 \ + --hash=sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce \ + --hash=sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab \ + --hash=sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a \ + --hash=sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f \ + --hash=sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c \ + --hash=sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9 \ + --hash=sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf \ + --hash=sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d \ + --hash=sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627 \ + --hash=sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d \ + --hash=sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4 \ + --hash=sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c \ + --hash=sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d \ + --hash=sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad \ + --hash=sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b \ + --hash=sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33 \ + --hash=sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371 \ + --hash=sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1 \ + --hash=sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393 \ + --hash=sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106 \ + --hash=sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df \ + --hash=sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379 \ + --hash=sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451 \ + --hash=sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b \ + --hash=sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575 \ + --hash=sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed \ + --hash=sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb \ + --hash=sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838 # via # deprecated # opentelemetry-instrumentation From 1329f1b90b42798de48e7e25d9b9872dc0f6dca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 28 Nov 2024 14:22:34 +0100 Subject: [PATCH 342/582] fix: support THEN RETURN for insert, update, delete (#503) * fix: support THEN RETURN for insert, update, delete Support THEN RETURN clauses for INSERT, UPDATE, and DELETE statements. Fixes #498 * test: override insert auto-generated pk test --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 4 + packages/sqlalchemy-spanner/noxfile.py | 2 +- .../bit_reversed_sequence_model.py | 33 +++++ .../test_bit_reversed_sequence.py | 137 ++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite_20.py | 26 ++++ 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/bit_reversed_sequence_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e57d46a818c2..e2fb651d585b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -611,6 +611,10 @@ class SpannerDialect(DefaultDialect): supports_native_decimal = True supports_statement_cache = True + insert_returning = True + update_returning = True + delete_returning = True + ddl_compiler = SpannerDDLCompiler preparer = SpannerIdentifierPreparer statement_compiler = SpannerSQLCompiler diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 2c4b21bc8525..974daf99bb6c 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -327,7 +327,7 @@ def mockserver(session): "9999", ) session.run( - "py.test", "--quiet", os.path.join("test/mockserver_tests"), *session.posargs + "py.test", "--quiet", os.path.join("test", "mockserver_tests"), *session.posargs ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/bit_reversed_sequence_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/bit_reversed_sequence_model.py new file mode 100644 index 000000000000..b76cdd3f955f --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/bit_reversed_sequence_model.py @@ -0,0 +1,33 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger, Sequence, TextClause +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column( + BigInteger, + Sequence("singer_id"), + server_default=TextClause("GET_NEXT_SEQUENCE_VALUE(SEQUENCE singer_id)"), + primary_key=True, + ) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py new file mode 100644 index 000000000000..82822d4433e7 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py @@ -0,0 +1,137 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + CommitRequest, + GetSessionRequest, + BeginTransactionRequest, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestBitReversedSequence(MockServerTestBase): + def test_create_table(self): + from test.mockserver_tests.bit_reversed_sequence_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true + FROM INFORMATION_SCHEMA.SEQUENCES + WHERE NAME="singer_id" + AND SCHEMA="" + LIMIT 1""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(2, len(requests[0].statements)) + eq_( + "CREATE SEQUENCE singer_id OPTIONS " + "(sequence_kind = 'bit_reversed_positive')", + requests[0].statements[0], + ) + eq_( + "CREATE TABLE singers (\n" + "\tid INT64 NOT NULL DEFAULT " + "(GET_NEXT_SEQUENCE_VALUE(SEQUENCE singer_id)), \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[1], + ) + + def test_insert_row(self): + from test.mockserver_tests.bit_reversed_sequence_model import Singer + + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ) + ] + ) + ) + ) + ), + stats=result_set.ResultSetStats( + dict( + row_count_exact=1, + ) + ), + ) + ) + result.rows.extend(["1"]) + + add_result( + "INSERT INTO singers (id, name) " + "VALUES ( GET_NEXT_SEQUENCE_VALUE(SEQUENCE singer_id), @a0) " + "THEN RETURN singers.id", + result, + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + singer = Singer(name="Test") + session.add(singer) + # Flush the session to send the insert statement to the database. + session.flush() + eq_(1, singer.id) + session.commit() + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(5, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + # We should get rid of this extra round-trip for GetSession.... + is_instance_of(requests[1], GetSessionRequest) + is_instance_of(requests[2], BeginTransactionRequest) + is_instance_of(requests[3], ExecuteSqlRequest) + is_instance_of(requests[4], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 22b23e0a7305..dbbc8f8813ed 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -2171,6 +2171,32 @@ def test_autoclose_on_insert(self): assert r.is_insert assert not r.returns_rows + def test_autoclose_on_insert_implicit_returning(self, connection): + """ + SPANNER OVERRIDE: + + Cloud Spanner doesn't support tables with an auto increment primary key, + following insertions will fail with `400 id must not be NULL in table + autoinc_pk`. + + Overriding the tests and adding a manual primary key value to avoid the same + failures. + """ + r = connection.execute( + # return_defaults() ensures RETURNING will be used, + # new in 2.0 as sqlite/mariadb offer both RETURNING and + # cursor.lastrowid + self.tables.autoinc_pk.insert().return_defaults(), + dict(id=2, data="some data"), + ) + assert r._soft_closed + assert not r.closed + assert r.is_insert + + # Spanner does not return any rows in this case, because the primary key + # is not auto-generated. + assert not r.returns_rows + class BytesTest(_LiteralRoundTripFixture, fixtures.TestBase): __backend__ = True From c007a625cbd017c18f098f5dc0f51d7f35f18f32 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 28 Nov 2024 15:52:13 +0100 Subject: [PATCH 343/582] chore(deps): update dependency cryptography to v44 (#521) --- .../.kokoro/requirements.txt | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 5136ca7405de..9fd86335010a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -220,34 +220,36 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 # via gcp-releasetool distlib==0.3.9 \ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ From ff9463d416353e98606d00fe67715b7681f44a4f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 28 Nov 2024 15:52:35 +0100 Subject: [PATCH 344/582] chore(deps): update dependency protobuf to v5.29.0 (#522) --- .../.kokoro/requirements.txt | 24 +++++++++---------- packages/sqlalchemy-spanner/requirements.txt | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 9fd86335010a..67ecdc7b1544 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -490,18 +490,18 @@ proto-plus==1.25.0 \ # via # -r requirements.in # google-api-core -protobuf==5.28.3 \ - --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ - --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ - --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ - --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ - --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ - --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ - --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ - --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ - --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ - --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ - --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed +protobuf==5.29.0 \ + --hash=sha256:0cd67a1e5c2d88930aa767f702773b2d054e29957432d7c6a18f8be02a07719a \ + --hash=sha256:0d10091d6d03537c3f902279fcf11e95372bdd36a79556311da0487455791b20 \ + --hash=sha256:17d128eebbd5d8aee80300aed7a43a48a25170af3337f6f1333d1fac2c6839ac \ + --hash=sha256:34a90cf30c908f47f40ebea7811f743d360e202b6f10d40c02529ebd84afc069 \ + --hash=sha256:445a0c02483869ed8513a585d80020d012c6dc60075f96fa0563a724987b1001 \ + --hash=sha256:6c3009e22717c6cc9e6594bb11ef9f15f669b19957ad4087214d69e08a213368 \ + --hash=sha256:85286a47caf63b34fa92fdc1fd98b649a8895db595cfa746c5286eeae890a0b1 \ + --hash=sha256:88c4af76a73183e21061881360240c0cdd3c39d263b4e8fb570aaf83348d608f \ + --hash=sha256:c931c61d0cc143a2e756b1e7f8197a508de5365efd40f83c907a9febf36e6b43 \ + --hash=sha256:e467f81fdd12ded9655cea3e9b83dc319d93b394ce810b556fb0f421d8613e86 \ + --hash=sha256:ea7fb379b257911c8c020688d455e8f74efd2f734b72dc1ea4b4d7e9fd1326f2 # via # gcp-docuploader # gcp-releasetool diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0ea726d81496..0838c63a40f4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -357,18 +357,18 @@ proto-plus==1.25.0 \ # via # google-api-core # google-cloud-spanner -protobuf==5.28.3 \ - --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ - --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ - --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ - --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ - --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ - --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ - --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ - --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ - --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ - --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ - --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed +protobuf==5.29.0 \ + --hash=sha256:0cd67a1e5c2d88930aa767f702773b2d054e29957432d7c6a18f8be02a07719a \ + --hash=sha256:0d10091d6d03537c3f902279fcf11e95372bdd36a79556311da0487455791b20 \ + --hash=sha256:17d128eebbd5d8aee80300aed7a43a48a25170af3337f6f1333d1fac2c6839ac \ + --hash=sha256:34a90cf30c908f47f40ebea7811f743d360e202b6f10d40c02529ebd84afc069 \ + --hash=sha256:445a0c02483869ed8513a585d80020d012c6dc60075f96fa0563a724987b1001 \ + --hash=sha256:6c3009e22717c6cc9e6594bb11ef9f15f669b19957ad4087214d69e08a213368 \ + --hash=sha256:85286a47caf63b34fa92fdc1fd98b649a8895db595cfa746c5286eeae890a0b1 \ + --hash=sha256:88c4af76a73183e21061881360240c0cdd3c39d263b4e8fb570aaf83348d608f \ + --hash=sha256:c931c61d0cc143a2e756b1e7f8197a508de5365efd40f83c907a9febf36e6b43 \ + --hash=sha256:e467f81fdd12ded9655cea3e9b83dc319d93b394ce810b556fb0f421d8613e86 \ + --hash=sha256:ea7fb379b257911c8c020688d455e8f74efd2f734b72dc1ea4b4d7e9fd1326f2 # via # google-api-core # google-cloud-spanner From 68ea8c43f787c48c899b53e6b3b840d50b72210c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 28 Nov 2024 15:52:52 +0100 Subject: [PATCH 345/582] chore(deps): update dependency tomli to v2.2.1 (#523) --- .../.kokoro/requirements.txt | 36 +++++++++++++++++-- packages/sqlalchemy-spanner/requirements.txt | 36 +++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 67ecdc7b1544..58ccf31dbfa6 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -586,9 +586,39 @@ six==1.16.0 \ # via # gcp-docuploader # python-dateutil -tomli==2.1.0 \ - --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ - --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 +tomli==2.2.1 \ + --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ + --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ + --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ + --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ + --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ + --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ + --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ + --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ + --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ + --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ + --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ + --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ + --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ + --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ + --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ + --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ + --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ + --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ + --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ + --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ + --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ + --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ + --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ + --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ + --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ + --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ + --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ + --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ + --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ + --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ + --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ + --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in twine==5.1.1 \ --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0838c63a40f4..9131e5a26c1c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -469,9 +469,39 @@ sqlparse==0.5.2 \ --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e # via google-cloud-spanner -tomli==2.1.0 \ - --hash=sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8 \ - --hash=sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391 +tomli==2.2.1 \ + --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ + --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ + --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ + --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ + --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ + --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ + --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ + --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ + --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ + --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ + --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ + --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ + --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ + --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ + --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ + --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ + --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ + --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ + --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ + --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ + --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ + --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ + --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ + --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ + --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ + --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ + --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ + --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ + --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ + --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ + --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ + --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ From 3d92328a223b94be006c900af5e1a68e3074eeb1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 28 Nov 2024 15:53:11 +0100 Subject: [PATCH 346/582] chore(deps): update dependency pyjwt to v2.10.1 (#524) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 58ccf31dbfa6..0da919e70ec2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -532,9 +532,9 @@ pygments==2.18.0 \ # via # readme-renderer # rich -PyJWT==2.10.0 \ - --hash=sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15 \ - --hash=sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c +PyJWT==2.10.1 \ + --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ + --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb # via gcp-releasetool pyparsing==3.2.0 \ --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ From 8a99ba4f5ef117d3a248b844cb87f2ce8b7efc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 28 Nov 2024 15:54:15 +0100 Subject: [PATCH 347/582] feat: add helper function for insert-or-update (#526) Adds helper functions for insert-or-update and insert-or-ignore and samples for how to use these functions. Fixes #391 --- .../google/cloud/sqlalchemy_spanner/dml.py | 26 +++++++++ .../samples/insert_or_ignore_sample.py | 54 +++++++++++++++++++ .../samples/insert_or_update_sample.py | 54 +++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/dml.py create mode 100644 packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py create mode 100644 packages/sqlalchemy-spanner/samples/insert_or_update_sample.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/dml.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/dml.py new file mode 100644 index 000000000000..311aee0db487 --- /dev/null +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/dml.py @@ -0,0 +1,26 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import Insert, insert +from sqlalchemy.sql._typing import _DMLTableArgument + + +def insert_or_update(table: _DMLTableArgument) -> Insert: + """Construct a Spanner-specific insert-or-update statement.""" + return insert(table).prefix_with("OR UPDATE") + + +def insert_or_ignore(table: _DMLTableArgument) -> Insert: + """Construct a Spanner-specific insert-or-ignore statement.""" + return insert(table).prefix_with("OR IGNORE") diff --git a/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py b/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py new file mode 100644 index 000000000000..36fbd492781a --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py @@ -0,0 +1,54 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session + +from google.cloud.sqlalchemy_spanner.dml import insert_or_ignore +from sample_helper import run_sample +from model import Singer + +# Shows how to use insert-or-ignore using SQLAlchemy and Spanner. +def insert_or_ignore_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + stmt = ( + insert_or_ignore(Singer) + .values( + id=str(uuid.uuid4()), + first_name="John", + last_name="Smith", + ) + .returning(Singer.id) + ) + singer_id = session.execute(stmt).scalar() + print(singer_id) + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + stmt = select(Singer).where(Singer.id == singer_id) + singer = session.execute(stmt).scalar() + print(f"Inserted or ignored singer {singer.full_name} successfully") + + +if __name__ == "__main__": + run_sample(insert_or_ignore_sample) diff --git a/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py b/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py new file mode 100644 index 000000000000..9b23b24adc90 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py @@ -0,0 +1,54 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session + +from google.cloud.sqlalchemy_spanner.dml import insert_or_update +from sample_helper import run_sample +from model import Singer + +# Shows how to use insert-or-update using SQLAlchemy and Spanner. +def insert_or_update_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + stmt = ( + insert_or_update(Singer) + .values( + id=str(uuid.uuid4()), + first_name="John", + last_name="Smith", + ) + .returning(Singer.id) + ) + singer_id = session.execute(stmt).scalar() + print(singer_id) + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + stmt = select(Singer).where(Singer.id == singer_id) + singer = session.execute(stmt).scalar() + print(f"Inserted or updated singer {singer.full_name} successfully") + + +if __name__ == "__main__": + run_sample(insert_or_update_sample) From 2f7b4bf37eb4a1f2fae25bd5f643752a6c4a2b34 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Dec 2024 18:14:29 +0100 Subject: [PATCH 348/582] chore(deps): update dependency nh3 to v0.2.19 (#527) --- .../.kokoro/requirements.txt | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 0da919e70ec2..2e425b364d25 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -446,23 +446,30 @@ more-itertools==10.5.0 \ # via # jaraco-classes # jaraco-functools -nh3==0.2.18 \ - --hash=sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164 \ - --hash=sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86 \ - --hash=sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b \ - --hash=sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad \ - --hash=sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204 \ - --hash=sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a \ - --hash=sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200 \ - --hash=sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189 \ - --hash=sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f \ - --hash=sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811 \ - --hash=sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844 \ - --hash=sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4 \ - --hash=sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be \ - --hash=sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50 \ - --hash=sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307 \ - --hash=sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe +nh3==0.2.19 \ + --hash=sha256:00810cd5275f5c3f44b9eb0e521d1a841ee2f8023622de39ffc7d88bd533d8e0 \ + --hash=sha256:0b6820fc64f2ff7ef3e7253a093c946a87865c877b3889149a6d21d322ed8dbd \ + --hash=sha256:11270b16c1b012677e3e2dd166c1aa273388776bf99a3e3677179db5097ee16a \ + --hash=sha256:2b926f179eb4bce72b651bfdf76f8aa05d167b2b72bc2f3657fd319f40232adc \ + --hash=sha256:2eb021804e9df1761abeb844bb86648d77aa118a663c82f50ea04110d87ed707 \ + --hash=sha256:3805161c4e12088bd74752ba69630e915bc30fe666034f47217a2f16b16efc37 \ + --hash=sha256:5d4f5e2189861b352b73acb803b5f4bb409c2f36275d22717e27d4e0c217ae55 \ + --hash=sha256:75c7cafb840f24430b009f7368945cb5ca88b2b54bb384ebfba495f16bc9c121 \ + --hash=sha256:7e98621856b0a911c21faa5eef8f8ea3e691526c2433f9afc2be713cb6fbdb48 \ + --hash=sha256:833b3b5f1783ce95834a13030300cea00cbdfd64ea29260d01af9c4821da0aa9 \ + --hash=sha256:a7b928862daddb29805a1010a0282f77f4b8b238a37b5f76bc6c0d16d930fd22 \ + --hash=sha256:ac536a4b5c073fdadd8f5f4889adabe1cbdae55305366fb870723c96ca7f49c3 \ + --hash=sha256:b8eb7affc590e542fa7981ef508cd1644f62176bcd10d4429890fc629b47f0bc \ + --hash=sha256:c2e3f0d18cc101132fe10ab7ef5c4f41411297e639e23b64b5e888ccaad63f41 \ + --hash=sha256:d0adf00e2b2026fa10a42537b60d161e516f206781c7515e4e97e09f72a8c5d0 \ + --hash=sha256:d53a4577b6123ca1d7e8483fad3e13cb7eda28913d516bd0a648c1a473aa21a9 \ + --hash=sha256:d8325d51e47cb5b11f649d55e626d56c76041ba508cd59e0cb1cf687cc7612f1 \ + --hash=sha256:df8eac98fec80bd6f5fd0ae27a65de14f1e1a65a76d8e2237eb695f9cd1121d9 \ + --hash=sha256:e3dedd7858a21312f7675841529941035a2ac91057db13402c8fe907aa19205a \ + --hash=sha256:ec9c8bf86e397cb88c560361f60fdce478b5edb8b93f04ead419b72fbe937ea6 \ + --hash=sha256:ed06ed78f6b69d57463b46a04f68f270605301e69d80756a8adf7519002de57d \ + --hash=sha256:fc483dd8d20f8f8c010783a25a84db3bebeadced92d24d34b40d687f8043ac69 \ + --hash=sha256:fdb20740d24ab9f2a1341458a00a11205294e97e905de060eeab1ceca020c09c # via # -r requirements.in # readme-renderer From 64e58d9e6199eadc628bb375765fa06383ce676e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Dec 2024 18:15:37 +0100 Subject: [PATCH 349/582] chore(deps): update dependency twine to v6 (#528) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 2e425b364d25..6b481ff49d14 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -627,9 +627,9 @@ tomli==2.2.1 \ --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in -twine==5.1.1 \ - --hash=sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997 \ - --hash=sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db +twine==6.0.1 \ + --hash=sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27 \ + --hash=sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218 # via -r requirements.in typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ From 1b1d5cca68d0543342e22f335854333e36be3257 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Dec 2024 18:15:55 +0100 Subject: [PATCH 350/582] chore(deps): update dependency grpcio to v1.68.1 (#529) --- packages/sqlalchemy-spanner/requirements.txt | 112 +++++++++---------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 9131e5a26c1c..e2cab69cd4fd 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -176,62 +176,62 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.68.0 \ - --hash=sha256:0d230852ba97654453d290e98d6aa61cb48fa5fafb474fb4c4298d8721809354 \ - --hash=sha256:0efbbd849867e0e569af09e165363ade75cf84f5229b2698d53cf22c7a4f9e21 \ - --hash=sha256:14331e5c27ed3545360464a139ed279aa09db088f6e9502e95ad4bfa852bb116 \ - --hash=sha256:15327ab81131ef9b94cb9f45b5bd98803a179c7c61205c8c0ac9aff9d6c4e82a \ - --hash=sha256:15377bce516b1c861c35e18eaa1c280692bf563264836cece693c0f169b48829 \ - --hash=sha256:15fa1fe25d365a13bc6d52fcac0e3ee1f9baebdde2c9b3b2425f8a4979fccea1 \ - --hash=sha256:18668e36e7f4045820f069997834e94e8275910b1f03e078a6020bd464cb2363 \ - --hash=sha256:2af76ab7c427aaa26aa9187c3e3c42f38d3771f91a20f99657d992afada2294a \ - --hash=sha256:2bddd04a790b69f7a7385f6a112f46ea0b34c4746f361ebafe9ca0be567c78e9 \ - --hash=sha256:32a9cb4686eb2e89d97022ecb9e1606d132f85c444354c17a7dbde4a455e4a3b \ - --hash=sha256:3ac7f10850fd0487fcce169c3c55509101c3bde2a3b454869639df2176b60a03 \ - --hash=sha256:3b2b559beb2d433129441783e5f42e3be40a9e1a89ec906efabf26591c5cd415 \ - --hash=sha256:4028b8e9a3bff6f377698587d642e24bd221810c06579a18420a17688e421af7 \ - --hash=sha256:44bcbebb24363d587472089b89e2ea0ab2e2b4df0e4856ba4c0b087c82412121 \ - --hash=sha256:46a2d74d4dd8993151c6cd585594c082abe74112c8e4175ddda4106f2ceb022f \ - --hash=sha256:4df81d78fd1646bf94ced4fb4cd0a7fe2e91608089c522ef17bc7db26e64effd \ - --hash=sha256:4e300e6978df0b65cc2d100c54e097c10dfc7018b9bd890bbbf08022d47f766d \ - --hash=sha256:4f1931c7aa85be0fa6cea6af388e576f3bf6baee9e5d481c586980c774debcb4 \ - --hash=sha256:50992f214264e207e07222703c17d9cfdcc2c46ed5a1ea86843d440148ebbe10 \ - --hash=sha256:55d3b52fd41ec5772a953612db4e70ae741a6d6ed640c4c89a64f017a1ac02b5 \ - --hash=sha256:5a180328e92b9a0050958ced34dddcb86fec5a8b332f5a229e353dafc16cd332 \ - --hash=sha256:619b5d0f29f4f5351440e9343224c3e19912c21aeda44e0c49d0d147a8d01544 \ - --hash=sha256:6b2f98165ea2790ea159393a2246b56f580d24d7da0d0342c18a085299c40a75 \ - --hash=sha256:6f9c7ad1a23e1047f827385f4713b5b8c6c7d325705be1dd3e31fb00dcb2f665 \ - --hash=sha256:79f81b7fbfb136247b70465bd836fa1733043fdee539cd6031cb499e9608a110 \ - --hash=sha256:7e0a3e72c0e9a1acab77bef14a73a416630b7fd2cbd893c0a873edc47c42c8cd \ - --hash=sha256:7e7483d39b4a4fddb9906671e9ea21aaad4f031cdfc349fec76bdfa1e404543a \ - --hash=sha256:88fb2925789cfe6daa20900260ef0a1d0a61283dfb2d2fffe6194396a354c618 \ - --hash=sha256:8af6137cc4ae8e421690d276e7627cfc726d4293f6607acf9ea7260bd8fc3d7d \ - --hash=sha256:8b0ff09c81e3aded7a183bc6473639b46b6caa9c1901d6f5e2cba24b95e59e30 \ - --hash=sha256:8c73f9fbbaee1a132487e31585aa83987ddf626426d703ebcb9a528cf231c9b1 \ - --hash=sha256:99f06232b5c9138593ae6f2e355054318717d32a9c09cdc5a2885540835067a1 \ - --hash=sha256:9fe1b141cda52f2ca73e17d2d3c6a9f3f3a0c255c216b50ce616e9dca7e3441d \ - --hash=sha256:a17278d977746472698460c63abf333e1d806bd41f2224f90dbe9460101c9796 \ - --hash=sha256:a59f5822f9459bed098ffbceb2713abbf7c6fd13f2b9243461da5c338d0cd6c3 \ - --hash=sha256:a6213d2f7a22c3c30a479fb5e249b6b7e648e17f364598ff64d08a5136fe488b \ - --hash=sha256:a831dcc343440969aaa812004685ed322cdb526cd197112d0db303b0da1e8659 \ - --hash=sha256:afbf45a62ba85a720491bfe9b2642f8761ff348006f5ef67e4622621f116b04a \ - --hash=sha256:b0cf343c6f4f6aa44863e13ec9ddfe299e0be68f87d68e777328bff785897b05 \ - --hash=sha256:c03d89df516128febc5a7e760d675b478ba25802447624edf7aa13b1e7b11e2a \ - --hash=sha256:c1245651f3c9ea92a2db4f95d37b7597db6b246d5892bca6ee8c0e90d76fb73c \ - --hash=sha256:cc5f0a4f5904b8c25729a0498886b797feb817d1fd3812554ffa39551112c161 \ - --hash=sha256:dba037ff8d284c8e7ea9a510c8ae0f5b016004f13c3648f72411c464b67ff2fb \ - --hash=sha256:def1a60a111d24376e4b753db39705adbe9483ef4ca4761f825639d884d5da78 \ - --hash=sha256:e0d2f68eaa0a755edd9a47d40e50dba6df2bceda66960dee1218da81a2834d27 \ - --hash=sha256:e0d30f3fee9372796f54d3100b31ee70972eaadcc87314be369360248a3dcffe \ - --hash=sha256:e18589e747c1e70b60fab6767ff99b2d0c359ea1db8a2cb524477f93cdbedf5b \ - --hash=sha256:e1e7ed311afb351ff0d0e583a66fcb39675be112d61e7cfd6c8269884a98afbc \ - --hash=sha256:e46541de8425a4d6829ac6c5d9b16c03c292105fe9ebf78cb1c31e8d242f9155 \ - --hash=sha256:e694b5928b7b33ca2d3b4d5f9bf8b5888906f181daff6b406f4938f3a997a490 \ - --hash=sha256:f60fa2adf281fd73ae3a50677572521edca34ba373a45b457b5ebe87c2d01e1d \ - --hash=sha256:f84890b205692ea813653ece4ac9afa2139eae136e419231b0eec7c39fdbe4c2 \ - --hash=sha256:f8f695d9576ce836eab27ba7401c60acaf9ef6cf2f70dfe5462055ba3df02cc3 \ - --hash=sha256:fc05759ffbd7875e0ff2bd877be1438dfe97c9312bbc558c8284a9afa1d0f40e \ - --hash=sha256:fd2c2d47969daa0e27eadaf15c13b5e92605c5e5953d23c06d0b5239a2f176d3 +grpcio==1.68.1 \ + --hash=sha256:025f790c056815b3bf53da850dd70ebb849fd755a4b1ac822cb65cd631e37d43 \ + --hash=sha256:04cfd68bf4f38f5bb959ee2361a7546916bd9a50f78617a346b3aeb2b42e2161 \ + --hash=sha256:0feb02205a27caca128627bd1df4ee7212db051019a9afa76f4bb6a1a80ca95e \ + --hash=sha256:1098f03dedc3b9810810568060dea4ac0822b4062f537b0f53aa015269be0a76 \ + --hash=sha256:12941d533f3cd45d46f202e3667be8ebf6bcb3573629c7ec12c3e211d99cfccf \ + --hash=sha256:255b1635b0ed81e9f91da4fcc8d43b7ea5520090b9a9ad9340d147066d1d3613 \ + --hash=sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600 \ + --hash=sha256:2c4cec6177bf325eb6faa6bd834d2ff6aa8bb3b29012cceb4937b86f8b74323c \ + --hash=sha256:2cc1fd04af8399971bcd4f43bd98c22d01029ea2e56e69c34daf2bf8470e47f5 \ + --hash=sha256:334ab917792904245a028f10e803fcd5b6f36a7b2173a820c0b5b076555825e1 \ + --hash=sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515 \ + --hash=sha256:37ea3be171f3cf3e7b7e412a98b77685eba9d4fd67421f4a34686a63a65d99f9 \ + --hash=sha256:390eee4225a661c5cd133c09f5da1ee3c84498dc265fd292a6912b65c421c78c \ + --hash=sha256:3aed6544e4d523cd6b3119b0916cef3d15ef2da51e088211e4d1eb91a6c7f4f1 \ + --hash=sha256:3ceb56c4285754e33bb3c2fa777d055e96e6932351a3082ce3559be47f8024f0 \ + --hash=sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054 \ + --hash=sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73 \ + --hash=sha256:4efac5481c696d5cb124ff1c119a78bddbfdd13fc499e3bc0ca81e95fc573684 \ + --hash=sha256:52fbf85aa71263380d330f4fce9f013c0798242e31ede05fcee7fbe40ccfc20d \ + --hash=sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c \ + --hash=sha256:66a24f3d45c33550703f0abb8b656515b0ab777970fa275693a2f6dc8e35f1c1 \ + --hash=sha256:6ab2d912ca39c51f46baf2a0d92aa265aa96b2443266fc50d234fa88bf877d8e \ + --hash=sha256:77d65165fc35cff6e954e7fd4229e05ec76102d4406d4576528d3a3635fc6172 \ + --hash=sha256:7dfc914cc31c906297b30463dde0b9be48e36939575eaf2a0a22a8096e69afe5 \ + --hash=sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2 \ + --hash=sha256:80af6f1e69c5e68a2be529990684abdd31ed6622e988bf18850075c81bb1ad6e \ + --hash=sha256:83bbf5807dc3ee94ce1de2dfe8a356e1d74101e4b9d7aa8c720cc4818a34aded \ + --hash=sha256:8720c25cd9ac25dd04ee02b69256d0ce35bf8a0f29e20577427355272230965a \ + --hash=sha256:8829924fffb25386995a31998ccbbeaa7367223e647e0122043dfc485a87c666 \ + --hash=sha256:8a3869a6661ec8f81d93f4597da50336718bde9eb13267a699ac7e0a1d6d0bea \ + --hash=sha256:8cb620037a2fd9eeee97b4531880e439ebfcd6d7d78f2e7dcc3726428ab5ef63 \ + --hash=sha256:919d7f18f63bcad3a0f81146188e90274fde800a94e35d42ffe9eadf6a9a6330 \ + --hash=sha256:95c87ce2a97434dffe7327a4071839ab8e8bffd0054cc74cbe971fba98aedd60 \ + --hash=sha256:963cc8d7d79b12c56008aabd8b457f400952dbea8997dd185f155e2f228db079 \ + --hash=sha256:96f473cdacfdd506008a5d7579c9f6a7ff245a9ade92c3c0265eb76cc591914f \ + --hash=sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd \ + --hash=sha256:a0c8ddabef9c8f41617f213e527254c41e8b96ea9d387c632af878d05db9229c \ + --hash=sha256:a1b988b40f2fd9de5c820f3a701a43339d8dcf2cb2f1ca137e2c02671cc83ac1 \ + --hash=sha256:a47faedc9ea2e7a3b6569795c040aae5895a19dde0c728a48d3c5d7995fda385 \ + --hash=sha256:a8040f85dcb9830d8bbb033ae66d272614cec6faceee88d37a88a9bd1a7a704e \ + --hash=sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9 \ + --hash=sha256:c08079b4934b0bf0a8847f42c197b1d12cba6495a3d43febd7e99ecd1cdc8d54 \ + --hash=sha256:c28848761a6520c5c6071d2904a18d339a796ebe6b800adc8b3f474c5ce3c3ad \ + --hash=sha256:cb400138e73969eb5e0535d1d06cae6a6f7a15f2cc74add320e2130b8179211a \ + --hash=sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe \ + --hash=sha256:ccf2ebd2de2d6661e2520dae293298a3803a98ebfc099275f113ce1f6c2a80f1 \ + --hash=sha256:d35740e3f45f60f3c37b1e6f2f4702c23867b9ce21c6410254c9c682237da68d \ + --hash=sha256:d99abcd61760ebb34bdff37e5a3ba333c5cc09feda8c1ad42547bea0416ada78 \ + --hash=sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0 \ + --hash=sha256:dffd29a2961f3263a16d73945b57cd44a8fd0b235740cb14056f0612329b345e \ + --hash=sha256:e4842e4872ae4ae0f5497bf60a0498fa778c192cc7a9e87877abd2814aca9475 \ + --hash=sha256:e8dbe3e00771bfe3d04feed8210fc6617006d06d9a2679b74605b9fed3e8362c \ + --hash=sha256:ee2e743e51cb964b4975de572aa8fb95b633f496f9fcb5e257893df3be854746 \ + --hash=sha256:eeb38ff04ab6e5756a2aef6ad8d94e89bb4a51ef96e20f45c44ba190fa0bcaad \ + --hash=sha256:f8261fa2a5f679abeb2a0a93ad056d765cdca1c47745eda3f2d87f874ff4b8c9 # via # google-api-core # googleapis-common-protos From 173d69e78a4546000044522eb7599557449bf4d5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 3 Dec 2024 18:16:08 +0100 Subject: [PATCH 351/582] chore(deps): update dependency grpcio-status to v1.68.1 (#530) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e2cab69cd4fd..b638d4789dbe 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -238,9 +238,9 @@ grpcio==1.68.1 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.68.0 \ - --hash=sha256:0a71b15d989f02df803b4ba85c5bf1f43aeaa58ac021e5f9974b8cadc41f784d \ - --hash=sha256:8369823de22ab6a2cddb3804669c149ae7a71819e127c2dca7c2322028d52bea +grpcio-status==1.68.1 \ + --hash=sha256:66f3d8847f665acfd56221333d66f7ad8927903d87242a482996bdb45e8d28fd \ + --hash=sha256:e1378d036c81a1610d7b4c7a146cd663dd13fcc915cf4d7d053929dba5bbb6e1 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From ca5252290e6f45e277ff069c7c00fbb50e22a74c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Dec 2024 12:20:45 +0100 Subject: [PATCH 352/582] chore(deps): update dependency pkginfo to v1.12.0 (#532) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 6b481ff49d14..36440e8b2b1d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -483,9 +483,9 @@ packaging==24.2 \ # via # gcp-releasetool # nox -pkginfo==1.10.0 \ - --hash=sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297 \ - --hash=sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097 +pkginfo==1.12.0 \ + --hash=sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf \ + --hash=sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088 # via twine platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ From 863e44228fc134a75740301e395e90fe9a63f103 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Dec 2024 14:10:15 +0100 Subject: [PATCH 353/582] chore(deps): update dependency mako to v1.3.7 (#535) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index b638d4789dbe..6cf0222ece45 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -250,9 +250,9 @@ importlib-metadata==8.5.0 \ --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via opentelemetry-api -mako==1.3.6 \ - --hash=sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d \ - --hash=sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a +Mako==1.3.7 \ + --hash=sha256:20405b1232e0759f0e7d87b01f6bb94fce0761747f1cb876ecf90bd512d0b639 \ + --hash=sha256:d18f990ad57f800ce8e76cbfb0b74afe471c293517e9f5003ace6dad5aa72c36 # via alembic markupsafe==3.0.2 \ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ From 8902a209dc5a7eb3b0d85a6340c6fe3d8b43d3ae Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Dec 2024 16:17:25 +0100 Subject: [PATCH 354/582] chore(deps): update dependency google-cloud-storage to v2.19.0 (#538) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 36440e8b2b1d..f4183ce048f3 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -289,9 +289,9 @@ google-cloud-core==2.4.1 \ --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-storage -google-cloud-storage==2.18.2 \ - --hash=sha256:97a4d45c368b7d401ed48c4fdfe86e1e1cb96401c9e199e419d289e2c0370166 \ - --hash=sha256:aaf7acd70cdad9f274d29332673fcab98708d0e1f4dceb5a5356aaef06af4d99 +google-cloud-storage==2.19.0 \ + --hash=sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba \ + --hash=sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2 # via gcp-docuploader google-crc32c==1.6.0 \ --hash=sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24 \ From e57713467db6cc8d289b18d12f76940022e1a896 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Dec 2024 16:18:09 +0100 Subject: [PATCH 355/582] chore(deps): update dependency protobuf to v5.29.1 (#537) --- .../.kokoro/requirements.txt | 24 +++++++++---------- packages/sqlalchemy-spanner/requirements.txt | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f4183ce048f3..89187a7d0fe2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -497,18 +497,18 @@ proto-plus==1.25.0 \ # via # -r requirements.in # google-api-core -protobuf==5.29.0 \ - --hash=sha256:0cd67a1e5c2d88930aa767f702773b2d054e29957432d7c6a18f8be02a07719a \ - --hash=sha256:0d10091d6d03537c3f902279fcf11e95372bdd36a79556311da0487455791b20 \ - --hash=sha256:17d128eebbd5d8aee80300aed7a43a48a25170af3337f6f1333d1fac2c6839ac \ - --hash=sha256:34a90cf30c908f47f40ebea7811f743d360e202b6f10d40c02529ebd84afc069 \ - --hash=sha256:445a0c02483869ed8513a585d80020d012c6dc60075f96fa0563a724987b1001 \ - --hash=sha256:6c3009e22717c6cc9e6594bb11ef9f15f669b19957ad4087214d69e08a213368 \ - --hash=sha256:85286a47caf63b34fa92fdc1fd98b649a8895db595cfa746c5286eeae890a0b1 \ - --hash=sha256:88c4af76a73183e21061881360240c0cdd3c39d263b4e8fb570aaf83348d608f \ - --hash=sha256:c931c61d0cc143a2e756b1e7f8197a508de5365efd40f83c907a9febf36e6b43 \ - --hash=sha256:e467f81fdd12ded9655cea3e9b83dc319d93b394ce810b556fb0f421d8613e86 \ - --hash=sha256:ea7fb379b257911c8c020688d455e8f74efd2f734b72dc1ea4b4d7e9fd1326f2 +protobuf==5.29.1 \ + --hash=sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c \ + --hash=sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331 \ + --hash=sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34 \ + --hash=sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110 \ + --hash=sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0 \ + --hash=sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853 \ + --hash=sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57 \ + --hash=sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb \ + --hash=sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d \ + --hash=sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155 \ + --hash=sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18 # via # gcp-docuploader # gcp-releasetool diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6cf0222ece45..6e90193d2055 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -357,18 +357,18 @@ proto-plus==1.25.0 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.0 \ - --hash=sha256:0cd67a1e5c2d88930aa767f702773b2d054e29957432d7c6a18f8be02a07719a \ - --hash=sha256:0d10091d6d03537c3f902279fcf11e95372bdd36a79556311da0487455791b20 \ - --hash=sha256:17d128eebbd5d8aee80300aed7a43a48a25170af3337f6f1333d1fac2c6839ac \ - --hash=sha256:34a90cf30c908f47f40ebea7811f743d360e202b6f10d40c02529ebd84afc069 \ - --hash=sha256:445a0c02483869ed8513a585d80020d012c6dc60075f96fa0563a724987b1001 \ - --hash=sha256:6c3009e22717c6cc9e6594bb11ef9f15f669b19957ad4087214d69e08a213368 \ - --hash=sha256:85286a47caf63b34fa92fdc1fd98b649a8895db595cfa746c5286eeae890a0b1 \ - --hash=sha256:88c4af76a73183e21061881360240c0cdd3c39d263b4e8fb570aaf83348d608f \ - --hash=sha256:c931c61d0cc143a2e756b1e7f8197a508de5365efd40f83c907a9febf36e6b43 \ - --hash=sha256:e467f81fdd12ded9655cea3e9b83dc319d93b394ce810b556fb0f421d8613e86 \ - --hash=sha256:ea7fb379b257911c8c020688d455e8f74efd2f734b72dc1ea4b4d7e9fd1326f2 +protobuf==5.29.1 \ + --hash=sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c \ + --hash=sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331 \ + --hash=sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34 \ + --hash=sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110 \ + --hash=sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0 \ + --hash=sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853 \ + --hash=sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57 \ + --hash=sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb \ + --hash=sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d \ + --hash=sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155 \ + --hash=sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18 # via # google-api-core # google-cloud-spanner From 0c427afd0ade0137b17ab96369ec795f767e7f1e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Dec 2024 16:18:22 +0100 Subject: [PATCH 356/582] chore(deps): update dependency six to v1.17.0 (#536) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 89187a7d0fe2..2da7b1436521 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -587,9 +587,9 @@ secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 # via keyring -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +six==1.17.0 \ + --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ + --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 # via # gcp-docuploader # python-dateutil From 6b2db9d8f73f25e318c52bc9f1aa3fe9fd15d551 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 6 Dec 2024 12:34:20 +0100 Subject: [PATCH 357/582] chore(deps): update dependency google-cloud-spanner to v3.51.0 (#542) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [google-cloud-spanner](https://redirect.github.com/googleapis/python-spanner) | `==3.50.1` -> `==3.51.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/google-cloud-spanner/3.51.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/pypi/google-cloud-spanner/3.51.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/pypi/google-cloud-spanner/3.50.1/3.51.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/google-cloud-spanner/3.50.1/3.51.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
googleapis/python-spanner (google-cloud-spanner) ### [`v3.51.0`](https://redirect.github.com/googleapis/python-spanner/blob/HEAD/CHANGELOG.md#3510-2024-12-05) [Compare Source](https://redirect.github.com/googleapis/python-spanner/compare/v3.50.1...v3.51.0) ##### Features - Add connection variable for ignoring transaction warnings ([#​1249](https://redirect.github.com/googleapis/python-spanner/issues/1249)) ([eeb7836](https://redirect.github.com/googleapis/python-spanner/commit/eeb7836b6350aa9626dfb733208e6827d38bb9c9)) - **spanner:** Implement custom tracer_provider injection for opentelemetry traces ([#​1229](https://redirect.github.com/googleapis/python-spanner/issues/1229)) ([6869ed6](https://redirect.github.com/googleapis/python-spanner/commit/6869ed651e41d7a8af046884bc6c792a4177f766)) - Support float32 parameters in dbapi ([#​1245](https://redirect.github.com/googleapis/python-spanner/issues/1245)) ([829b799](https://redirect.github.com/googleapis/python-spanner/commit/829b799e0c9c6da274bf95c272cda564cfdba928)) ##### Bug Fixes - Allow setting connection.read_only to same value ([#​1247](https://redirect.github.com/googleapis/python-spanner/issues/1247)) ([5e8ca94](https://redirect.github.com/googleapis/python-spanner/commit/5e8ca949b583fbcf0b92b42696545973aad8c78f)) - Allow setting staleness to same value in tx ([#​1253](https://redirect.github.com/googleapis/python-spanner/issues/1253)) ([a214885](https://redirect.github.com/googleapis/python-spanner/commit/a214885ed474f3d69875ef580d5f8cbbabe9199a)) - Dbapi raised AttributeError with \[] as arguments ([#​1257](https://redirect.github.com/googleapis/python-spanner/issues/1257)) ([758bf48](https://redirect.github.com/googleapis/python-spanner/commit/758bf4889a7f3346bc8282a3eed47aee43be650c)) ##### Performance Improvements - Optimize ResultSet decoding ([#​1244](https://redirect.github.com/googleapis/python-spanner/issues/1244)) ([ccae6e0](https://redirect.github.com/googleapis/python-spanner/commit/ccae6e0287ba6cf3c14f15a907b2106b11ef1fdc)) - Remove repeated GetSession calls for FixedSizePool ([#​1252](https://redirect.github.com/googleapis/python-spanner/issues/1252)) ([c064815](https://redirect.github.com/googleapis/python-spanner/commit/c064815abaaa4b564edd6f0e365a37e7e839080c)) ##### Documentation - **samples:** Add samples for Cloud Spanner Default Backup Schedules ([#​1238](https://redirect.github.com/googleapis/python-spanner/issues/1238)) ([054a186](https://redirect.github.com/googleapis/python-spanner/commit/054a18658eedc5d4dbecb7508baa3f3d67f5b815))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- .../mockserver_tests/test_bit_reversed_sequence.py | 11 ++++------- packages/sqlalchemy-spanner/test/test_suite_13.py | 3 +++ packages/sqlalchemy-spanner/test/test_suite_14.py | 10 +++++++++- packages/sqlalchemy-spanner/test/test_suite_20.py | 10 +++++++++- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6e90193d2055..71ed5445bc29 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -157,9 +157,9 @@ google-cloud-core==2.4.1 \ --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-spanner -google-cloud-spanner==3.50.1 \ - --hash=sha256:82937ea03b55de86bddf622f555aeae65ae86bb4f28ab35bd920ac505917c9bf \ - --hash=sha256:9d399aa53fae58816023a4eb31fa267333c3a879a9221229e7f06fdda543884a +google-cloud-spanner==3.51.0 \ + --hash=sha256:2d01f33582526ebe7fab62034e92e722e512c21f6bc4abe27e03d86ef7ea576a \ + --hash=sha256:346c2c20f64847883464fb0de5a6f9b48ecc6f79b032a2fb3a0aa088d9a9863f # via -r requirements.in googleapis-common-protos[grpc]==1.66.0 \ --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py index 82822d4433e7..a18bc08e808a 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py @@ -21,7 +21,6 @@ BatchCreateSessionsRequest, ExecuteSqlRequest, CommitRequest, - GetSessionRequest, BeginTransactionRequest, ) from test.mockserver_tests.mock_server_test_base import ( @@ -128,10 +127,8 @@ def test_insert_row(self): session.commit() # Verify the requests that we got. requests = self.spanner_service.requests - eq_(5, len(requests)) + eq_(4, len(requests)) is_instance_of(requests[0], BatchCreateSessionsRequest) - # We should get rid of this extra round-trip for GetSession.... - is_instance_of(requests[1], GetSessionRequest) - is_instance_of(requests[2], BeginTransactionRequest) - is_instance_of(requests[3], ExecuteSqlRequest) - is_instance_of(requests[4], CommitRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index b0cddf5945e6..97f5754e066f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -1300,6 +1300,9 @@ def test_float_as_float(self): filter_=lambda n: n is not None and round(n, 5) or None, ) + def test_float_coerce_round_trip(self, connection): + pass + @requires.precision_numerics_general def test_precision_decimal(self): """ diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index e4183821f2ca..5730515792e7 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -27,7 +27,7 @@ from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy -from sqlalchemy import create_engine +from sqlalchemy import create_engine, literal, FLOAT from sqlalchemy import inspect from sqlalchemy import testing from sqlalchemy import ForeignKey @@ -53,6 +53,7 @@ from sqlalchemy import Float from sqlalchemy import LargeBinary from sqlalchemy import String +from sqlalchemy.sql.expression import cast from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relation from sqlalchemy.orm import Session @@ -1650,6 +1651,13 @@ def test_float_as_float(self, do_numeric_test): filter_=lambda n: n is not None and round(n, 5) or None, ) + @testing.requires.literal_float_coercion + def test_float_coerce_round_trip(self, connection): + expr = 15.7563 + + val = connection.scalar(select(cast(literal(expr), FLOAT))) + eq_(val, expr) + @requires.precision_numerics_general def test_precision_decimal(self, do_numeric_test): """ diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index dbbc8f8813ed..4b6849e45a69 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -26,7 +26,7 @@ from google.cloud.spanner_v1 import RequestOptions, Client import sqlalchemy -from sqlalchemy import create_engine +from sqlalchemy import create_engine, literal, FLOAT from sqlalchemy.engine import Inspector from sqlalchemy import inspect from sqlalchemy import testing @@ -55,6 +55,7 @@ from sqlalchemy import Float from sqlalchemy import LargeBinary from sqlalchemy import String +from sqlalchemy.sql.expression import cast from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from sqlalchemy.orm import Session @@ -2455,6 +2456,13 @@ def test_float_as_float(self, do_numeric_test): filter_=lambda n: n is not None and round(n, 5) or None, ) + @testing.requires.literal_float_coercion + def test_float_coerce_round_trip(self, connection): + expr = 15.7563 + + val = connection.scalar(select(cast(literal(expr), FLOAT))) + eq_(val, expr) + @requires.precision_numerics_general def test_precision_decimal(self, do_numeric_test): """ From 6fd2b39ed395f251543bc6213f53133fd5ca5fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 08:44:08 +0100 Subject: [PATCH 358/582] feat: support float32 (#531) * feat: support float32 Adds support for FLOAT32 columns. Applications should use the SQLAlchemy type REAL to create a FLOAT32 column, as FLOAT is already reserved for FLOAT64. Fixes #409 * chore: run code formatter * fix: remove DOUBLE reference which is SQLAlchemy 2.0-only --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 11 +++ .../test/mockserver_tests/float32_model.py | 30 ++++++++ .../test/mockserver_tests/test_float32.py | 73 +++++++++++++++++++ .../test/mockserver_tests/test_quickstart.py | 1 - .../test/system/test_basics.py | 39 +++++++++- 5 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/float32_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e2fb651d585b..09c7f9ae0207 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -84,6 +84,7 @@ def reset_connection(dbapi_conn, connection_record, reset_state=None): "BYTES": types.LargeBinary, "DATE": types.DATE, "DATETIME": types.DATETIME, + "FLOAT32": types.REAL, "FLOAT64": types.Float, "INT64": types.BIGINT, "NUMERIC": types.NUMERIC(precision=38, scale=9), @@ -101,6 +102,7 @@ def reset_connection(dbapi_conn, connection_record, reset_state=None): types.LargeBinary: "BYTES(MAX)", types.DATE: "DATE", types.DATETIME: "DATETIME", + types.REAL: "FLOAT32", types.Float: "FLOAT64", types.BIGINT: "INT64", types.DECIMAL: "NUMERIC", @@ -540,9 +542,18 @@ class SpannerTypeCompiler(GenericTypeCompiler): def visit_INTEGER(self, type_, **kw): return "INT64" + def visit_DOUBLE(self, type_, **kw): + return "FLOAT64" + def visit_FLOAT(self, type_, **kw): + # Note: This was added before Spanner supported FLOAT32. + # Changing this now to generate a FLOAT32 would be a breaking change. + # Users therefore have to use REAL to generate a FLOAT32 column. return "FLOAT64" + def visit_REAL(self, type_, **kw): + return "FLOAT32" + def visit_TEXT(self, type_, **kw): return "STRING({})".format(type_.length or "MAX") diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/float32_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/float32_model.py new file mode 100644 index 000000000000..b6987e97a64e --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/float32_model.py @@ -0,0 +1,30 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column +from sqlalchemy.types import REAL + + +class Base(DeclarativeBase): + pass + + +class Number(Base): + __tablename__ = "numbers" + number: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(30)) + ln: Mapped[float] = mapped_column(REAL) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py new file mode 100644 index 000000000000..801a57c238dd --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py @@ -0,0 +1,73 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy.orm import Session +from sqlalchemy.testing import ( + eq_, + is_instance_of, + is_false, +) +from google.cloud.spanner_v1 import ( + BatchCreateSessionsRequest, + ExecuteSqlRequest, + ResultSet, + ResultSetStats, + BeginTransactionRequest, + CommitRequest, + TypeCode, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) + + +class TestFloat32(MockServerTestBase): + def test_insert_data(self): + from test.mockserver_tests.float32_model import Number + + update_count = ResultSet( + dict( + stats=ResultSetStats( + dict( + row_count_exact=1, + ) + ) + ) + ) + add_result( + "INSERT INTO numbers (number, name, ln) VALUES (@a0, @a1, @a2)", + update_count, + ) + + engine = self.create_engine() + with Session(engine) as session: + n1 = Number(number=1, name="One", ln=0.0) + session.add_all([n1]) + session.commit() + + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) + request: ExecuteSqlRequest = requests[2] + eq_(3, len(request.params)) + eq_("1", request.params["a0"]) + eq_("One", request.params["a1"]) + eq_(0.0, request.params["a2"]) + eq_(TypeCode.INT64, request.param_types["a0"].code) + eq_(TypeCode.STRING, request.param_types["a1"].code) + is_false("a2" in request.param_types) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py index ce9711f7df07..0b31f9e2addf 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py @@ -30,7 +30,6 @@ class TestQuickStart(MockServerTestBase): def test_create_tables(self): from test.mockserver_tests.quickstart_model import Base - # TODO: Fix the double quotes inside these SQL fragments. add_result( """SELECT true FROM INFORMATION_SCHEMA.TABLES diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 3357104cf83e..171485b8c7ff 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -22,7 +22,10 @@ Index, MetaData, Boolean, + BIGINT, ) +from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column +from sqlalchemy.types import REAL from sqlalchemy.testing import eq_ from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -37,6 +40,7 @@ def define_tables(cls, metadata): Column("name", String(20)), Column("alternative_name", String(20)), Column("prime", Boolean), + Column("ln", REAL), PrimaryKeyConstraint("number"), ) Index( @@ -53,8 +57,8 @@ def test_hello_world(self, connection): def test_insert_number(self, connection): connection.execute( text( - """insert or update into numbers (number, name, prime) - values (1, 'One', false)""" + """insert or update into numbers (number, name, prime, ln) + values (1, 'One', false, cast(ln(1) as float32))""" ) ) name = connection.execute(text("select name from numbers where number=1")) @@ -66,6 +70,17 @@ def test_reflect(self, connection): meta.reflect(bind=engine) eq_(1, len(meta.tables)) table = meta.tables["numbers"] + eq_(5, len(table.columns)) + eq_("number", table.columns[0].name) + eq_(BIGINT, type(table.columns[0].type)) + eq_("name", table.columns[1].name) + eq_(String, type(table.columns[1].type)) + eq_("alternative_name", table.columns[2].name) + eq_(String, type(table.columns[2].type)) + eq_("prime", table.columns[3].name) + eq_(Boolean, type(table.columns[3].type)) + eq_("ln", table.columns[4].name) + eq_(REAL, type(table.columns[4].type)) eq_(1, len(table.indexes)) index = next(iter(table.indexes)) eq_(2, len(index.columns)) @@ -74,3 +89,23 @@ def test_reflect(self, connection): dialect_options = index.dialect_options["spanner"] eq_(1, len(dialect_options["storing"])) eq_("alternative_name", dialect_options["storing"][0]) + + def test_orm(self, connection): + class Base(DeclarativeBase): + pass + + class Number(Base): + __tablename__ = "numbers" + number: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(20)) + alternative_name: Mapped[str] = mapped_column(String(20)) + prime: Mapped[bool] = mapped_column(Boolean) + ln: Mapped[float] = mapped_column(REAL) + + engine = connection.engine + with Session(engine) as session: + number = Number( + number=1, name="One", alternative_name="Uno", prime=False, ln=0.0 + ) + session.add(number) + session.commit() From dde21aa1b85fdb870d20dcbd449c887af29f2369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 08:44:44 +0100 Subject: [PATCH 359/582] docs: add sample for read-only transactions (#533) * docs: add sample for read-only transactions Adds a sample and documentation for read-only transactions. Fixes #493 * chore: run two read-only transactions in test * chore: remove GetSession requests * chore: remove unused import --- packages/sqlalchemy-spanner/README.rst | 13 +- .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../samples/read_only_transaction_sample.py | 64 ++++++++++ .../test/mockserver_tests/read_only_model.py | 33 +++++ .../test_read_only_transaction.py | 119 ++++++++++++++++++ 5 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/read_only_transaction_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/read_only_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 5c39e1397d58..852bdc5cbc1e 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -344,8 +344,9 @@ ReadOnly transactions ~~~~~~~~~~~~~~~~~~~~~ By default, transactions produced by a Spanner connection are in -ReadWrite mode. However, some applications require an ability to grant -ReadOnly access to users/methods; for these cases Spanner dialect +ReadWrite mode. However, workloads that only read data perform better +if they use read-only transactions, as Spanner does not need to take +locks for the data that is read; for these cases, the Spanner dialect supports the ``read_only`` execution option, which switches a connection into ReadOnly mode: @@ -354,11 +355,13 @@ into ReadOnly mode: with engine.connect().execution_options(read_only=True) as connection: connection.execute(select(["*"], from_obj=table)).fetchall() -Note that execution options are applied lazily - on the ``execute()`` -method call, right before it. +See the `Read-only transaction sample +`__ +for a concrete example. ReadOnly/ReadWrite mode of a connection can't be changed while a -transaction is in progress - first you must commit or rollback it. +transaction is in progress - you must commit or rollback the current +transaction before changing the mode. Stale reads ~~~~~~~~~~~ diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index b103fd77df76..5011e9710e3d 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -57,6 +57,11 @@ def transaction(session): _sample(session) +@nox.session() +def read_only_transaction(session): + _sample(session) + + @nox.session() def _all_samples(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/samples/read_only_transaction_sample.py b/packages/sqlalchemy-spanner/samples/read_only_transaction_sample.py new file mode 100644 index 000000000000..35ef84e7fd12 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/read_only_transaction_sample.py @@ -0,0 +1,64 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine, Engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Concert, Venue + + +# Shows how to execute a read-only transaction on Spanner using SQLAlchemy. +def read_only_transaction_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # First insert a few test rows that can be queried in a read-only transaction. + insert_test_data(engine) + + # Create a session that uses a read-only transaction. + # Read-only transactions do not take locks, and are therefore preferred + # above read/write transactions for workloads that only read data on Spanner. + with Session(engine.execution_options(read_only=True)) as session: + print("Singers ordered by last name") + singers = session.query(Singer).order_by(Singer.last_name).all() + for singer in singers: + print("Singer: ", singer.full_name) + + print() + print("Singers ordered by first name") + singers = session.query(Singer).order_by(Singer.first_name).all() + for singer in singers: + print("Singer: ", singer.full_name) + + +def insert_test_data(engine: Engine): + with Session(engine) as session: + session.add_all( + [ + Singer(id=str(uuid.uuid4()), first_name="John", last_name="Doe"), + Singer(id=str(uuid.uuid4()), first_name="Jane", last_name="Doe"), + ] + ) + session.commit() + + +if __name__ == "__main__": + run_sample(read_only_transaction_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/read_only_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/read_only_model.py new file mode 100644 index 000000000000..b76cdd3f955f --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/read_only_model.py @@ -0,0 +1,33 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger, Sequence, TextClause +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column( + BigInteger, + Sequence("singer_id"), + server_default=TextClause("GET_NEXT_SEQUENCE_VALUE(SEQUENCE singer_id)"), + primary_key=True, + ) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py new file mode 100644 index 000000000000..18abf69f3c62 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py @@ -0,0 +1,119 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + BeginTransactionRequest, + TransactionOptions, +) +from test.mockserver_tests.mock_server_test_base import MockServerTestBase +from test.mockserver_tests.mock_server_test_base import add_result +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestReadOnlyTransaction(MockServerTestBase): + def test_read_only_transaction(self): + from test.mockserver_tests.read_only_model import Singer + + add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + echo=True, + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + for i in range(2): + with Session(engine.execution_options(read_only=True)) as session: + # Execute two queries in a read-only transaction. + session.scalars(select(Singer)).all() + session.scalars(select(Singer)).all() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(7, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], ExecuteSqlRequest) + is_instance_of(requests[4], BeginTransactionRequest) + is_instance_of(requests[5], ExecuteSqlRequest) + is_instance_of(requests[6], ExecuteSqlRequest) + # Verify that the transaction is a read-only transaction. + for index in [1, 4]: + begin_request: BeginTransactionRequest = requests[index] + eq_( + TransactionOptions( + dict( + read_only=TransactionOptions.ReadOnly( + dict( + strong=True, + return_read_timestamp=True, + ) + ) + ) + ), + begin_request.options, + ) + + +def add_singer_query_result(sql: str): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="singers_id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="singers_name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Jane Doe", + ), + ( + "2", + "John Doe", + ), + ] + ) + add_result(sql, result) From d9bb4afbde2fa82d7e158e0e9f48d633936fe910 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 9 Dec 2024 08:51:57 +0100 Subject: [PATCH 360/582] chore(deps): update dependency argcomplete to v3.5.2 (#543) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 2da7b1436521..4f5d4af45053 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes requirements.in # -argcomplete==3.5.1 \ - --hash=sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363 \ - --hash=sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4 +argcomplete==3.5.2 \ + --hash=sha256:036d020d79048a5d525bc63880d7a4b8d1668566b8a76daf1144c0bbe0f63472 \ + --hash=sha256:23146ed7ac4403b70bd6026402468942ceba34a6732255b9edf5b7354f68a6bb # via nox attrs==24.2.0 \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ From b57bf4c20ffa0769bdf10169ce0dbda4f20667d8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 9 Dec 2024 08:52:09 +0100 Subject: [PATCH 361/582] chore(deps): update dependency mako to v1.3.8 (#544) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 71ed5445bc29..d3b98e3f4822 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -250,9 +250,9 @@ importlib-metadata==8.5.0 \ --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via opentelemetry-api -Mako==1.3.7 \ - --hash=sha256:20405b1232e0759f0e7d87b01f6bb94fce0761747f1cb876ecf90bd512d0b639 \ - --hash=sha256:d18f990ad57f800ce8e76cbfb0b74afe471c293517e9f5003ace6dad5aa72c36 +Mako==1.3.8 \ + --hash=sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627 \ + --hash=sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8 # via alembic markupsafe==3.0.2 \ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ From 6e461e6068d91075b2955421f96b10bed2a319fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 08:53:34 +0100 Subject: [PATCH 362/582] feat: support Partitioned DML (#541) Adds tests and samples for executing Partitioned DML using SQLAlchemy. Fixes #496 --- .../samples/partitioned_dml_sample.py | 45 +++++++++++++++++++ .../mockserver_tests/mock_server_test_base.py | 12 +++++ .../test/mockserver_tests/mock_spanner.py | 25 ++++++++--- .../test/mockserver_tests/test_basics.py | 31 ++++++++++++- 4 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py diff --git a/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py b/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py new file mode 100644 index 000000000000..62c312ff3e28 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py @@ -0,0 +1,45 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode +from sqlalchemy import create_engine, text + +from sample_helper import run_sample + +# Shows how to use Partitioned DML using SQLAlchemy and Spanner. +def partitioned_dml_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # Get a connection in auto-commit mode. + # Partitioned DML can only be executed in auto-commit mode, as each + # Partitioned DML transaction can only consist of one statement. + with engine.connect().execution_options(isolation_level="AUTOCOMMIT") as connection: + # Set the DML mode to PARTITIONED_NON_ATOMIC. + connection.connection.set_autocommit_dml_mode( + AutocommitDmlMode.PARTITIONED_NON_ATOMIC + ) + # Use a bulk update statement to back-fill a column. + lower_bound_rowcount = connection.execute( + text("update venues set active=true where active is null") + ).rowcount + # Partitioned DML returns the lower-bound update count. + print("Updated at least ", lower_bound_rowcount, " venue records") + + +if __name__ == "__main__": + run_sample(partitioned_dml_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py index 71e1bf1fa326..5aa33732c980 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import Engine, create_engine from sqlalchemy.testing.plugin.plugin_base import fixtures import google.cloud.spanner_v1.types.type as spanner_type @@ -35,6 +36,17 @@ def add_result(sql: str, result: ResultSet): MockServerTestBase.spanner_service.mock_spanner.add_result(sql, result) +def add_update_count( + sql: str, count: int, dml_mode: AutocommitDmlMode = AutocommitDmlMode.TRANSACTIONAL +): + if dml_mode == AutocommitDmlMode.PARTITIONED_NON_ATOMIC: + stats = dict(row_count_lower_bound=count) + else: + stats = dict(row_count_exact=count) + result = result_set.ResultSet(dict(stats=result_set.ResultSetStats(stats))) + add_result(sql, result) + + def add_select1_result(): result = result_set.ResultSet( dict( diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py index db1891448ade..932f6371e42b 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_spanner.py @@ -12,7 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from google.cloud.spanner_v1 import TransactionOptions, ResultSetMetadata +from google.cloud.spanner_v1 import ( + TransactionOptions, + ResultSetMetadata, + ExecuteSqlRequest, +) from google.protobuf import empty_pb2 import test.mockserver_tests.spanner_pb2_grpc as spanner_grpc import test.mockserver_tests.spanner_database_admin_pb2_grpc as database_admin_grpc @@ -40,23 +44,25 @@ def get_result(self, sql: str) -> result_set.ResultSet: return result def get_result_as_partial_result_sets( - self, sql: str + self, sql: str, started_transaction: transaction.Transaction ) -> [result_set.PartialResultSet]: result: result_set.ResultSet = self.get_result(sql) partials = [] first = True if len(result.rows) == 0: partial = result_set.PartialResultSet() - partial.metadata = result.metadata + partial.metadata = ResultSetMetadata(result.metadata) partials.append(partial) else: for row in result.rows: partial = result_set.PartialResultSet() if first: - partial.metadata = result.metadata + partial.metadata = ResultSetMetadata(result.metadata) partial.values.extend(row) partials.append(partial) partials[len(partials) - 1].stats = result.stats + if started_transaction: + partials[0].metadata.transaction = started_transaction return partials @@ -120,9 +126,16 @@ def ExecuteSql(self, request, context): self._requests.append(request) return result_set.ResultSet() - def ExecuteStreamingSql(self, request, context): + def ExecuteStreamingSql(self, request: ExecuteSqlRequest, context): self._requests.append(request) - partials = self.mock_spanner.get_result_as_partial_result_sets(request.sql) + started_transaction = None + if not request.transaction.begin == TransactionOptions(): + started_transaction = self.__create_transaction( + request.session, request.transaction.begin + ) + partials = self.mock_spanner.get_result_as_partial_result_sets( + request.sql, started_transaction + ) for result in partials: yield result diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index b6c916c42bc4..829183665745 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -13,7 +13,17 @@ # limitations under the License. from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest -from sqlalchemy import create_engine, select, MetaData, Table, Column, Integer, String +from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode +from sqlalchemy import ( + create_engine, + select, + MetaData, + Table, + Column, + Integer, + String, + text, +) from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( FixedSizePool, @@ -26,6 +36,7 @@ MockServerTestBase, add_select1_result, add_result, + add_update_count, ) @@ -127,3 +138,21 @@ def test_create_multiple_tables(self): "\n) PRIMARY KEY (id)", requests[0].statements[i], ) + + def test_partitioned_dml(self): + sql = "UPDATE singers SET checked=true WHERE active = true" + add_update_count(sql, 100, AutocommitDmlMode.PARTITIONED_NON_ATOMIC) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": PingingPool(size=10)}, + ) + # TODO: Support autocommit_dml_mode as a connection variable in execution + # options. + with engine.connect().execution_options( + isolation_level="AUTOCOMMIT" + ) as connection: + connection.connection.set_autocommit_dml_mode( + AutocommitDmlMode.PARTITIONED_NON_ATOMIC + ) + results = connection.execute(text(sql)).rowcount + eq_(100, results) From 7416818290095db3613752621cf88dde304887b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 08:57:01 +0100 Subject: [PATCH 363/582] docs: add sample for stale reads (#539) * docs: add sample for stale reads Adds a sample and tests for executing stale reads on Spanner. Using stale reads can improve performance when the application does not require the guarantees that are given by strong reads. Fixes #495 * chore: remove GetSession requests --- .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../samples/stale_read_sample.py | 96 ++++++++++ .../test/mockserver_tests/stale_read_model.py | 28 +++ .../test/mockserver_tests/test_stale_reads.py | 169 ++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 packages/sqlalchemy-spanner/samples/stale_read_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/stale_read_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 5011e9710e3d..35b744dc87be 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -57,6 +57,11 @@ def transaction(session): _sample(session) +@nox.session() +def stale_read(session): + _sample(session) + + @nox.session() def read_only_transaction(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/samples/stale_read_sample.py b/packages/sqlalchemy-spanner/samples/stale_read_sample.py new file mode 100644 index 000000000000..989a0c13ca0e --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/stale_read_sample.py @@ -0,0 +1,96 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid +from sqlalchemy import create_engine, Engine, select, text +from sqlalchemy.orm import Session +from sample_helper import run_sample +from model import Singer + + +# Shows how to execute stale reads on Spanner using SQLAlchemy. +def stale_read_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # First get the current database timestamp. We can use this timestamp to + # query the database at a point in time where we know it was empty. + with Session(engine.execution_options(isolation_level="AUTOCOMMIT")) as session: + timestamp = session.execute(select(text("current_timestamp"))).one()[0] + print(timestamp) + + # Insert a few test rows. + insert_test_data(engine) + + # Create a session that uses a read-only transaction with a strong timestamp + # bound. This means that it will read all data that has been committed at the + # time this transaction starts. + # Read-only transactions do not take locks, and are therefore preferred + # above read/write transactions for workloads that only read data on Spanner. + with Session(engine.execution_options(read_only=True)) as session: + print("Found singers with strong timestamp bound:") + singers = session.query(Singer).order_by(Singer.last_name).all() + for singer in singers: + print("Singer: ", singer.full_name) + + # Create a session that uses a read-only transaction that selects data in + # the past. We'll use the timestamp that we retrieved before inserting the + # test data for this transaction. + with Session( + engine.execution_options( + read_only=True, staleness={"read_timestamp": timestamp} + ) + ) as session: + print("Searching for singers using a read timestamp in the past:") + singers = session.query(Singer).order_by(Singer.last_name).all() + if singers: + for singer in singers: + print("Singer: ", singer.full_name) + else: + print("No singers found.") + + # Spanner also supports min_read_timestamp and max_staleness as staleness + # options. These can only be used in auto-commit mode. + # Spanner will choose a read timestamp that satisfies the given restriction + # and that can be served as efficiently as possible. + with Session( + engine.execution_options( + isolation_level="AUTOCOMMIT", staleness={"max_staleness": {"seconds": 15}} + ) + ) as session: + print("Searching for singers using a max staleness of 15 seconds:") + singers = session.query(Singer).order_by(Singer.last_name).all() + if singers: + for singer in singers: + print("Singer: ", singer.full_name) + else: + print("No singers found.") + + +def insert_test_data(engine: Engine): + with Session(engine) as session: + session.add_all( + [ + Singer(id=str(uuid.uuid4()), first_name="John", last_name="Doe"), + Singer(id=str(uuid.uuid4()), first_name="Jane", last_name="Doe"), + ] + ) + session.commit() + + +if __name__ == "__main__": + run_sample(stale_read_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/stale_read_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/stale_read_model.py new file mode 100644 index 000000000000..025a56d21997 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/stale_read_model.py @@ -0,0 +1,28 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py new file mode 100644 index 000000000000..02be066cde24 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py @@ -0,0 +1,169 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + BeginTransactionRequest, + TransactionOptions, +) +from test.mockserver_tests.mock_server_test_base import MockServerTestBase +from test.mockserver_tests.mock_server_test_base import add_result +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestStaleReads(MockServerTestBase): + def test_stale_read_multi_use(self): + from test.mockserver_tests.stale_read_model import Singer + + add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + echo=True, + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + timestamp = datetime.datetime.fromtimestamp(1733328910) + for i in range(2): + with Session( + engine.execution_options( + read_only=True, + staleness={"read_timestamp": timestamp}, + ) + ) as session: + # Execute two queries in a read-only transaction. + session.scalars(select(Singer)).all() + session.scalars(select(Singer)).all() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(7, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], ExecuteSqlRequest) + is_instance_of(requests[4], BeginTransactionRequest) + is_instance_of(requests[5], ExecuteSqlRequest) + is_instance_of(requests[6], ExecuteSqlRequest) + # Verify that the transaction is a read-only transaction. + for index in [1, 4]: + begin_request: BeginTransactionRequest = requests[index] + eq_( + TransactionOptions( + dict( + read_only=TransactionOptions.ReadOnly( + dict( + read_timestamp={"seconds": 1733328910}, + return_read_timestamp=True, + ) + ) + ) + ), + begin_request.options, + ) + + def test_stale_read_single_use(self): + from test.mockserver_tests.stale_read_model import Singer + + add_singer_query_result("SELECT singers.id, singers.name\n" + "FROM singers") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + echo=True, + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session( + engine.execution_options( + isolation_level="AUTOCOMMIT", + staleness={"max_staleness": {"seconds": 15}}, + ) + ) as session: + # Execute two queries in autocommit. + session.scalars(select(Singer)).all() + session.scalars(select(Singer)).all() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(3, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + # Verify that the requests use a stale read. + for index in [1, 2]: + execute_request: ExecuteSqlRequest = requests[index] + eq_( + TransactionOptions( + dict( + read_only=TransactionOptions.ReadOnly( + dict( + max_staleness={"seconds": 15}, + return_read_timestamp=True, + ) + ) + ) + ), + execute_request.transaction.single_use, + ) + + +def add_singer_query_result(sql: str): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="singers_id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="singers_name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Jane Doe", + ), + ( + "2", + "John Doe", + ), + ] + ) + add_result(sql, result) From c52c2c3ea5767949efb6ee3b0017f9697af1b7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 09:58:23 +0100 Subject: [PATCH 364/582] test: add tests for using json array (#534) * test: add tests for using json array Adds test to verify that using JSON with both an array and a dict work as expected. Fixes #404 * chore: remove GetSession checks in tests --------- Co-authored-by: Sanjeev Bhatt --- .../test/mockserver_tests/json_model.py | 30 +++ .../test/mockserver_tests/test_json.py | 186 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/json_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/json_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/json_model.py new file mode 100644 index 000000000000..7a8ca5303141 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/json_model.py @@ -0,0 +1,30 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger +from sqlalchemy.sql.sqltypes import JSON +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Venue(Base): + __tablename__ = "venues" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) + description = mapped_column(JSON) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py new file mode 100644 index 000000000000..d38eb7043045 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py @@ -0,0 +1,186 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + CommitRequest, + BeginTransactionRequest, + TypeCode, + JsonObject, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, + add_update_count, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestJson(MockServerTestBase): + def test_create_table(self): + from test.mockserver_tests.json_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="venues" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE venues (\n" + "\tid INT64 NOT NULL, \n" + "\tname STRING(MAX) NOT NULL, \n" + "\tdescription JSON\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + + def test_insert_dict(self): + self._test_insert_json( + {"type": "Stadium", "size": "Great"}, '{"size":"Great","type":"Stadium"}' + ) + + def test_insert_array(self): + self._test_insert_json( + [{"type": "Stadium", "size": "Great"}], + '[{"size":"Great","type":"Stadium"}]', + ) + + def _test_insert_json(self, description, expected): + from test.mockserver_tests.json_model import Venue + + add_update_count( + "INSERT INTO venues (id, name, description) VALUES (@a0, @a1, @a2)", 1 + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + venue = Venue(id=1, name="Test", description=description) + session.add(venue) + session.commit() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) + request: ExecuteSqlRequest = requests[2] + eq_(3, len(request.params)) + eq_("1", request.params["a0"]) + eq_("Test", request.params["a1"]) + eq_(expected, request.params["a2"]) + eq_(TypeCode.INT64, request.param_types["a0"].code) + eq_(TypeCode.STRING, request.param_types["a1"].code) + eq_(TypeCode.JSON, request.param_types["a2"].code) + + def test_select_dict(self): + self._test_select_json( + '{"size":"Great","type":"Stadium"}', + JsonObject({"size": "Great", "type": "Stadium"}), + ) + + def test_select_array(self): + self._test_select_json( + '[{"size":"Great","type":"Stadium"}]', + JsonObject([{"size": "Great", "type": "Stadium"}]), + ) + + def _test_select_json(self, description, expected): + from test.mockserver_tests.json_model import Venue + + sql = "SELECT venues.id, venues.name, venues.description \n" "FROM venues" + add_venue_query_result(sql, description) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine.execution_options(read_only=True)) as session: + venue = session.execute(select(Venue)).first()[0] + eq_(venue.description, expected) + + +def add_venue_query_result(sql: str, description: str): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="description", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.JSON) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Test", + description, + ), + ] + ) + add_result(sql, result) From da58f4ecb3cf68f74a0fb5d3e9406785abbd3e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 10:08:17 +0100 Subject: [PATCH 365/582] fix: map now() to current_timestamp (#540) Fixes #497 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 3 +++ .../mockserver_tests/mock_server_test_base.py | 17 +++++++++----- .../test/mockserver_tests/test_basics.py | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 09c7f9ae0207..e6042e3166cc 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -235,6 +235,9 @@ def get_from_hint_text(self, _, text): """ return text + def visit_now_func(self, func, **kwargs): + return "current_timestamp" + def visit_empty_set_expr(self, type_, **kw): """Return an empty set expression of the given type. diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py index 5aa33732c980..fa5ed4bdfaf4 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py @@ -22,6 +22,7 @@ Client, ResultSet, PingingPool, + TypeCode, ) from google.cloud.spanner_v1.database import Database from google.cloud.spanner_v1.instance import Instance @@ -48,6 +49,12 @@ def add_update_count( def add_select1_result(): + add_single_result("select 1", "c", TypeCode.INT64, [("1",)]) + + +def add_single_result( + sql: str, column_name: str, type_code: spanner_type.TypeCode, row +): result = result_set.ResultSet( dict( metadata=result_set.ResultSetMetadata( @@ -57,10 +64,8 @@ def add_select1_result(): fields=[ spanner_type.StructType.Field( dict( - name="c", - type=spanner_type.Type( - dict(code=spanner_type.TypeCode.INT64) - ), + name=column_name, + type=spanner_type.Type(dict(code=type_code)), ) ) ] @@ -70,8 +75,8 @@ def add_select1_result(): ), ) ) - result.rows.extend(["1"]) - MockServerTestBase.spanner_service.mock_spanner.add_result("select 1", result) + result.rows.extend(row) + MockServerTestBase.spanner_service.mock_spanner.add_result(sql, result) class MockServerTestBase(fixtures.TestBase): diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 829183665745..28ea1b86ad29 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import datetime from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import ( @@ -22,6 +23,7 @@ Column, Integer, String, + func, text, ) from sqlalchemy.testing import eq_, is_instance_of @@ -31,11 +33,13 @@ ExecuteSqlRequest, ResultSet, PingingPool, + TypeCode, ) from test.mockserver_tests.mock_server_test_base import ( MockServerTestBase, add_select1_result, add_result, + add_single_result, add_update_count, ) @@ -70,6 +74,25 @@ def test_sqlalchemy_select1(self): results = connection.execute(select(1)).fetchall() self.verify_select1(results) + def test_sqlalchemy_select_now(self): + now = datetime.datetime.now(datetime.UTC) + iso_now = now.isoformat().replace("+00:00", "Z") + add_single_result( + "SELECT current_timestamp AS now_1", + "now_1", + TypeCode.TIMESTAMP, + [(iso_now,)], + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": PingingPool(size=10)}, + ) + with engine.connect().execution_options( + isolation_level="AUTOCOMMIT" + ) as connection: + spanner_now = connection.execute(select(func.now())).fetchone()[0] + eq_(spanner_now.timestamp(), now.timestamp()) + def test_create_table(self): add_result( """SELECT true From d7662ab07ec0fe3acf94cbcc9bf6dd57417694a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 10:18:20 +0100 Subject: [PATCH 366/582] test: add test with 'roles' table (#520) * test: add test with 'roles' table Add a test that verifies that a table with the same name as a system view can be used. * chore: fix linting --- .../test/system/test_basics.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 171485b8c7ff..e3099912f48f 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Optional from sqlalchemy import ( text, Table, @@ -90,6 +91,30 @@ def test_reflect(self, connection): eq_(1, len(dialect_options["storing"])) eq_("alternative_name", dialect_options["storing"][0]) + def test_table_name_overlapping_with_system_table(self, connection): + class Base(DeclarativeBase): + pass + + class Role(Base): + __tablename__ = "roles" + id: Mapped[int] = mapped_column(Integer, primary_key=True) + name: Mapped[str] = mapped_column(String(100), nullable=True) + type: Mapped[str] = mapped_column(String(100), nullable=True) + description: Mapped[Optional[str]] = mapped_column(String(512)) + + engine = connection.engine + Base.metadata.create_all(engine) + + with Session(engine) as session: + role = Role( + id=1, + name="Test", + type="Test", + description="Test", + ) + session.add(role) + session.commit() + def test_orm(self, connection): class Base(DeclarativeBase): pass From 7ff6871b06248cba69f17c702eec08170219806b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 9 Dec 2024 12:00:24 +0100 Subject: [PATCH 367/582] docs: cleanup the transaction section of README a bit (#545) Cleans up the Transaction section of the README file a bit. --- packages/sqlalchemy-spanner/README.rst | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 852bdc5cbc1e..1ec9dfc90f80 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -80,7 +80,7 @@ on this step in a dialect prefix part: # for SQLAlchemy 1.3: spanner:///projects/project-id/instances/instance-id/databases/database-id - # for SQLAlchemy 1.4: + # for SQLAlchemy 1.4 and 2.0: spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id To pass your custom client object directly to be be used, create engine as following: @@ -237,7 +237,7 @@ Unique constraints ~~~~~~~~~~~~~~~~~~ Cloud Spanner doesn't support direct UNIQUE constraints creation. In -order to achieve column values uniqueness UNIQUE indexes should be used. +order to achieve column values uniqueness, UNIQUE indexes should be used. Instead of direct UNIQUE constraint creation: @@ -265,10 +265,16 @@ Autocommit mode ~~~~~~~~~~~~~~~ Spanner dialect supports both ``SERIALIZABLE`` and ``AUTOCOMMIT`` -isolation levels. ``SERIALIZABLE`` is the default one, where -transactions need to be committed manually. ``AUTOCOMMIT`` mode -corresponds to automatically committing of a query right in its -execution time. +isolation levels. ``SERIALIZABLE`` is the default isolation level. + +``AUTOCOMMIT`` mode corresponds to automatically committing each +insert/update/delete statement right after is has been executed. +Queries that are executed in ``AUTOCOMMIT`` mode use a single-use +read-only transaction. These do not take any locks and do not need +to be committed. + +Workloads that only read data, should use either ``AUTOCOMMIT`` or +a read-only transaction. Isolation level change example: @@ -279,7 +285,7 @@ Isolation level change example: eng = create_engine("spanner:///projects/project-id/instances/instance-id/databases/database-id") autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT") -Automatic transactions retry +Automatic transaction retry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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. @@ -287,8 +293,8 @@ This, however, may require to manually repeat a long list of operations, execute 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. -Autoincremented IDs -~~~~~~~~~~~~~~~~~~~ +Auto-incremented IDs +~~~~~~~~~~~~~~~~~~~~ Cloud Spanner doesn't support autoincremented IDs mechanism due to performance reasons (`see for more From 1d75a68d1c18d9850560b7e6a03d80bceefb02de Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:12:45 +0100 Subject: [PATCH 368/582] chore(main): release 1.8.0 (#415) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 34 ++++++++++++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 83533552c59c..fccd8630dd26 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,39 @@ # Changelog +## [1.8.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.7.0...v1.8.0) (2024-12-09) + + +### Features + +* Add helper function for insert-or-update ([#526](https://github.com/googleapis/python-spanner-sqlalchemy/issues/526)) ([6ff12ec](https://github.com/googleapis/python-spanner-sqlalchemy/commit/6ff12ecf6f1883525a901df4b4103b45ca95abed)), closes [#391](https://github.com/googleapis/python-spanner-sqlalchemy/issues/391) +* Support dml returning ([#335](https://github.com/googleapis/python-spanner-sqlalchemy/issues/335)) ([7db3f37](https://github.com/googleapis/python-spanner-sqlalchemy/commit/7db3f374510673d6521b16ca44d21043069d6ee7)) +* Support float32 ([#531](https://github.com/googleapis/python-spanner-sqlalchemy/issues/531)) ([6c3cb42](https://github.com/googleapis/python-spanner-sqlalchemy/commit/6c3cb42919c5c8d52719d855af4fc2bb22c13fae)) +* Support Partitioned DML ([#541](https://github.com/googleapis/python-spanner-sqlalchemy/issues/541)) ([108d965](https://github.com/googleapis/python-spanner-sqlalchemy/commit/108d965c60b6ea817de7fed86dca3d20f923d975)), closes [#496](https://github.com/googleapis/python-spanner-sqlalchemy/issues/496) + + +### Bug Fixes + +* Add `existing_nullable` usage to `visit_column_type` ([#329](https://github.com/googleapis/python-spanner-sqlalchemy/issues/329)) ([273f03b](https://github.com/googleapis/python-spanner-sqlalchemy/commit/273f03bdf27c12317712a9939eedd25bd88c475a)) +* Map now() to current_timestamp ([#540](https://github.com/googleapis/python-spanner-sqlalchemy/issues/540)) ([4b24f33](https://github.com/googleapis/python-spanner-sqlalchemy/commit/4b24f335ff918c7404201db16d05ccc817626dfe)), closes [#497](https://github.com/googleapis/python-spanner-sqlalchemy/issues/497) +* Support storing columns for indices ([#485](https://github.com/googleapis/python-spanner-sqlalchemy/issues/485)) ([93579c8](https://github.com/googleapis/python-spanner-sqlalchemy/commit/93579c8d6298dd9a07b2ca2b9c451036e33d2e6f)) +* Support THEN RETURN for insert, update, delete ([#503](https://github.com/googleapis/python-spanner-sqlalchemy/issues/503)) ([ac64472](https://github.com/googleapis/python-spanner-sqlalchemy/commit/ac644726665213f234ce8ec4dea715c820a670e9)) + + +### Dependencies + +* Add nh3 ([#481](https://github.com/googleapis/python-spanner-sqlalchemy/issues/481)) ([3c2bcf9](https://github.com/googleapis/python-spanner-sqlalchemy/commit/3c2bcf9901ce132a6d5d5d3b1ad3608526a378b5)) +* Add proto plus ([#482](https://github.com/googleapis/python-spanner-sqlalchemy/issues/482)) ([8663453](https://github.com/googleapis/python-spanner-sqlalchemy/commit/86634531793cf01b46cefe87f74375ee59060638)) +* Update all deps ([#413](https://github.com/googleapis/python-spanner-sqlalchemy/issues/413)) ([25d9d2c](https://github.com/googleapis/python-spanner-sqlalchemy/commit/25d9d2c32638eb3e551921eecea435452c548bcb)) + + +### Documentation + +* Add sample for read-only transactions ([#533](https://github.com/googleapis/python-spanner-sqlalchemy/issues/533)) ([d2d72b6](https://github.com/googleapis/python-spanner-sqlalchemy/commit/d2d72b6fad4ea457114a50a2869d053798fed452)) +* Add sample for stale reads ([#539](https://github.com/googleapis/python-spanner-sqlalchemy/issues/539)) ([e9df810](https://github.com/googleapis/python-spanner-sqlalchemy/commit/e9df8105b18e03dbf3b746fed85ffe9da286b953)) +* Add samples for Spanner-specific features ([#492](https://github.com/googleapis/python-spanner-sqlalchemy/issues/492)) ([a6ed382](https://github.com/googleapis/python-spanner-sqlalchemy/commit/a6ed382be2a7105f9e8b2f855df3919e8c6750c9)) +* Cleanup the transaction section of README a bit ([#545](https://github.com/googleapis/python-spanner-sqlalchemy/issues/545)) ([c3b5df5](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c3b5df52c2fc62b11aa684c2d02dac95dd06ab59)) +* Fix readme typo ([#487](https://github.com/googleapis/python-spanner-sqlalchemy/issues/487)) ([b452b4f](https://github.com/googleapis/python-spanner-sqlalchemy/commit/b452b4f73d200b99fd800862c88304b67aa035c5)) + ## [1.7.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.6.2...v1.7.0) (2024-02-07) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 5c96bcc47d2a..fa7013985457 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.7.0" +__version__ = "1.8.0" From 00cd45cf71a7ecf33020f2cfe7d4da97e2905b2b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:29:03 +0100 Subject: [PATCH 369/582] chore(deps): update dependency google-api-core to v2.24.0 (#548) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 4f5d4af45053..98af9dfbbd00 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -271,9 +271,9 @@ gcp-releasetool==2.3.0 \ --hash=sha256:510516c6a2135e55503fd58f5c8e9d93506d8fba4ebed381a1eccb3d8f9b6740 \ --hash=sha256:804547a3d2e022924bceadcc453fc49e3059a42a607b99e55b1e2a2d10cb5323 # via -r requirements.in -google-api-core==2.23.0 \ - --hash=sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace \ - --hash=sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f +google-api-core==2.24.0 \ + --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ + --hash=sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf # via # google-cloud-core # google-cloud-storage diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d3b98e3f4822..00e15fcf8679 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -141,9 +141,9 @@ Deprecated==1.2.15 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.23.0 \ - --hash=sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace \ - --hash=sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f +google-api-core[grpc]==2.24.0 \ + --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ + --hash=sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf # via # google-cloud-core # google-cloud-spanner From a2386727e9cc50cacef1a4af8ea467beee34961d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:29:46 +0100 Subject: [PATCH 370/582] chore(deps): update dependency sqlparse to v0.5.3 (#549) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 00e15fcf8679..be868425f13f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -465,9 +465,9 @@ sqlalchemy==2.0.36 \ # via # -r requirements.in # alembic -sqlparse==0.5.2 \ - --hash=sha256:9e37b35e16d1cc652a2545f0997c1deb23ea28fa1f3eefe609eee3063c3b105f \ - --hash=sha256:e99bc85c78160918c3e1d9230834ab8d80fc06c59d03f8db2618f65f65dda55e +sqlparse==0.5.3 \ + --hash=sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272 \ + --hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca # via google-cloud-spanner tomli==2.2.1 \ --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ From 027aaf582a3ebc0826bd74577a78a7c8d10a33a0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:29:58 +0100 Subject: [PATCH 371/582] chore(deps): update dependency opentelemetry-api to v1.29.0 (#551) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index be868425f13f..a472af53efed 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -317,9 +317,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.28.2 \ - --hash=sha256:6fcec89e265beb258fe6b1acaaa3c8c705a934bd977b9f534a2b7c0d2d4275a6 \ - --hash=sha256:ecdc70c7139f17f9b0cf3742d57d7020e3e8315d6cffcdf1a12a905d45b19cc0 +opentelemetry-api==1.29.0 \ + --hash=sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8 \ + --hash=sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf # via # -r requirements.in # opentelemetry-instrumentation From 10048be7e3a9e0d6789198e5227ee9f228a1b5e7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:30:18 +0100 Subject: [PATCH 372/582] chore(deps): update dependency opentelemetry-sdk to v1.29.0 (#552) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a472af53efed..186c622ad51f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -329,9 +329,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.28.2 \ - --hash=sha256:5fed24c5497e10df30282456fe2910f83377797511de07d14cec0d3e0a1a3110 \ - --hash=sha256:93336c129556f1e3ccd21442b94d3521759541521861b2214c499571b85cb71b +opentelemetry-sdk==1.29.0 \ + --hash=sha256:173be3b5d3f8f7d671f20ea37056710217959e774e2749d984355d1f9391a30a \ + --hash=sha256:b0787ce6aade6ab84315302e72bd7a7f2f014b0fb1b7c3295b88afe014ed0643 # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 4032df057760d047b1cd905dc7a1037b6514c6fd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:30:31 +0100 Subject: [PATCH 373/582] chore(deps): update dependency google-auth to v2.37.0 (#553) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 98af9dfbbd00..18a113270c21 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -277,9 +277,9 @@ google-api-core==2.24.0 \ # via # google-cloud-core # google-cloud-storage -google-auth==2.36.0 \ - --hash=sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb \ - --hash=sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1 +google-auth==2.37.0 \ + --hash=sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00 \ + --hash=sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0 # via # gcp-releasetool # google-api-core diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 186c622ad51f..dae346909e64 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -147,9 +147,9 @@ google-api-core[grpc]==2.24.0 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.36.0 \ - --hash=sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb \ - --hash=sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1 +google-auth==2.37.0 \ + --hash=sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00 \ + --hash=sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0 # via # google-api-core # google-cloud-core From 1001f0ba5423542652417006c42f6a02000b7841 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:30:44 +0100 Subject: [PATCH 374/582] chore(deps): update dependency certifi to v2024.12.14 (#554) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 18a113270c21..e1fd39565ca7 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -24,9 +24,9 @@ cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via google-auth -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via requests cffi==1.17.1 \ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index dae346909e64..18a2c06fd27e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via google-auth -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via requests charset-normalizer==3.4.0 \ --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ From 6d141a1ba7af8528383499903834e67f8cdac50b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 17 Dec 2024 13:30:56 +0100 Subject: [PATCH 375/582] chore(deps): update dependency attrs to v24.3.0 (#555) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e1fd39565ca7..79171f19373e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -8,9 +8,9 @@ argcomplete==3.5.2 \ --hash=sha256:036d020d79048a5d525bc63880d7a4b8d1668566b8a76daf1144c0bbe0f63472 \ --hash=sha256:23146ed7ac4403b70bd6026402468942ceba34a6732255b9edf5b7354f68a6bb # via nox -attrs==24.2.0 \ - --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ - --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 +attrs==24.3.0 \ + --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \ + --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308 # via gcp-releasetool backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ From d44923c8c07a54d01da8ef62fd505b9df4e78029 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:09:37 +0100 Subject: [PATCH 376/582] build(deps): bump cryptography from 44.0.0 to 44.0.1 in /.kokoro (#571) Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.0 to 44.0.1. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/44.0.0...44.0.1) --- updated-dependencies: - dependency-name: cryptography dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../.kokoro/requirements.txt | 96 ++++++++----------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 79171f19373e..c60a90841a91 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -16,10 +16,6 @@ backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 # via -r requirements.in -bleach==6.2.0 \ - --hash=sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e \ - --hash=sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f - # via readme-renderer cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a @@ -216,41 +212,41 @@ colorlog==6.9.0 \ # via # gcp-docuploader # nox -commonmark==0.9.1 \ - --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ - --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 - # via rich -cryptography==44.0.0 \ - --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ - --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ - --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ - --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ - --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ - --hash=sha256:60eb32934076fa07e4316b7b2742fa52cbb190b42c2df2863dbc4230a0a9b385 \ - --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ - --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ - --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ - --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ - --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ - --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ - --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ - --hash=sha256:9abcc2e083cbe8dde89124a47e5e53ec38751f0d7dfd36801008f316a127d7ba \ - --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ - --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ - --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ - --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ - --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ - --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ - --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ - --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ - --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ - --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ - --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ - --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ - --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ - --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ - --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 - # via gcp-releasetool +cryptography==44.0.1 \ + --hash=sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7 \ + --hash=sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3 \ + --hash=sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183 \ + --hash=sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69 \ + --hash=sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a \ + --hash=sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62 \ + --hash=sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911 \ + --hash=sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7 \ + --hash=sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a \ + --hash=sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41 \ + --hash=sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83 \ + --hash=sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12 \ + --hash=sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864 \ + --hash=sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf \ + --hash=sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c \ + --hash=sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2 \ + --hash=sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b \ + --hash=sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0 \ + --hash=sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4 \ + --hash=sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9 \ + --hash=sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008 \ + --hash=sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862 \ + --hash=sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009 \ + --hash=sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7 \ + --hash=sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f \ + --hash=sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026 \ + --hash=sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f \ + --hash=sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd \ + --hash=sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420 \ + --hash=sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14 \ + --hash=sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00 + # via + # gcp-releasetool + # secretstorage distlib==0.3.9 \ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 @@ -339,9 +335,7 @@ idna==3.10 \ importlib-metadata==8.5.0 \ --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 - # via - # -r requirements.in - # twine + # via -r requirements.in jaraco-classes==3.4.0 \ --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 @@ -359,6 +353,9 @@ jaraco-functools==4.1.0 \ jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 + # via + # keyring + # secretstorage jinja2==3.1.4 \ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d @@ -483,6 +480,7 @@ packaging==24.2 \ # via # gcp-releasetool # nox + # twine pkginfo==1.12.0 \ --hash=sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf \ --hash=sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088 @@ -515,10 +513,6 @@ protobuf==5.29.1 \ # google-api-core # googleapis-common-protos # proto-plus -py==1.11.0 \ - --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ - --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 - # via nox pyasn1==0.6.1 \ --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 @@ -539,14 +533,10 @@ pygments==2.18.0 \ # via # readme-renderer # rich -PyJWT==2.10.1 \ +pyjwt==2.10.1 \ --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb # via gcp-releasetool -pyparsing==3.2.0 \ - --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ - --hash=sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c - # via packaging pyperclip==1.9.0 \ --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 # via gcp-releasetool @@ -645,10 +635,6 @@ virtualenv==20.28.0 \ --hash=sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0 \ --hash=sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa # via nox -webencodings==0.5.1 \ - --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ - --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 - # via bleach wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 From fdb701c9233c10ab9fa767bd3f3c180070235b67 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:12:15 +0100 Subject: [PATCH 377/582] chore(deps): update dependency alembic to v1.14.1 (#570) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 18a2c06fd27e..5e1e57df72b5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.14.0 \ - --hash=sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25 \ - --hash=sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b +alembic==1.14.1 \ + --hash=sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5 \ + --hash=sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From 4bf2e151b8b3b4308be738a7920dd92708f1e738 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:12:36 +0100 Subject: [PATCH 378/582] chore(deps): update dependency virtualenv to v20.29.2 (#568) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index c60a90841a91..028a2c8bcc5a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -631,9 +631,9 @@ urllib3==2.2.3 \ # via # requests # twine -virtualenv==20.28.0 \ - --hash=sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0 \ - --hash=sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa +virtualenv==20.29.2 \ + --hash=sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728 \ + --hash=sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a # via nox wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ From 324cd9acd96410f20ca83aab0d02a3f96f2ee9f2 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:15:04 +0100 Subject: [PATCH 379/582] chore(deps): update dependency pyparsing to v3.2.1 (#567) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 5e1e57df72b5..0a8ae727c13f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -386,9 +386,9 @@ pyasn1-modules==0.4.1 \ --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c # via google-auth -pyparsing==3.2.0 \ - --hash=sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 \ - --hash=sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c +pyparsing==3.2.1 \ + --hash=sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 \ + --hash=sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a # via -r requirements.in pyproject-hooks==1.2.0 \ --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ From 30e4550b58a8f33c9b812195aafe070b5fd57e40 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:16:13 +0100 Subject: [PATCH 380/582] chore(deps): update dependency jinja2 to v3.1.5 [security] (#563) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 028a2c8bcc5a..f24ba1f9adfa 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -356,9 +356,9 @@ jeepney==0.8.0 \ # via # keyring # secretstorage -jinja2==3.1.4 \ - --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ - --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d +Jinja2==3.1.5 \ + --hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \ + --hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb # via gcp-releasetool keyring==25.5.0 \ --hash=sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6 \ From 2f38ddf6d724d423afc79a2fb6cee941b0a77a94 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:17:08 +0100 Subject: [PATCH 381/582] chore(deps): update dependency argcomplete to v3.5.3 (#566) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f24ba1f9adfa..8e87207f49df 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes requirements.in # -argcomplete==3.5.2 \ - --hash=sha256:036d020d79048a5d525bc63880d7a4b8d1668566b8a76daf1144c0bbe0f63472 \ - --hash=sha256:23146ed7ac4403b70bd6026402468942ceba34a6732255b9edf5b7354f68a6bb +argcomplete==3.5.3 \ + --hash=sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61 \ + --hash=sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392 # via nox attrs==24.3.0 \ --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \ From fd6980ab9675a805e28175ca8a8b0a7070e2d665 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:18:05 +0100 Subject: [PATCH 382/582] chore(deps): update dependency cachetools to v5.5.1 (#573) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 8e87207f49df..ea5e1365dd98 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -16,9 +16,9 @@ backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 # via -r requirements.in -cachetools==5.5.0 \ - --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ - --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a +cachetools==5.5.1 \ + --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ + --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb # via google-auth certifi==2024.12.14 \ --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0a8ae727c13f..b59e2b235002 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==5.5.0 \ - --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ - --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a +cachetools==5.5.1 \ + --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ + --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb # via google-auth certifi==2024.12.14 \ --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ From 4bf93c9a1b9a4472ec69461ddf6eccc900f63222 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:19:37 +0100 Subject: [PATCH 383/582] chore(deps): update dependency deprecated to v1.2.18 (#574) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index b59e2b235002..61cffeb73969 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -135,9 +135,9 @@ click==8.1.7 \ # via # -r requirements.in # pip-tools -Deprecated==1.2.15 \ - --hash=sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320 \ - --hash=sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d +Deprecated==1.2.18 \ + --hash=sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d \ + --hash=sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec # via # opentelemetry-api # opentelemetry-semantic-conventions From d81c28359e319cea0459fd6aacfb7cd059e28132 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:23:14 +0100 Subject: [PATCH 384/582] chore(deps): update dependency keyring to v25.6.0 (#565) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index ea5e1365dd98..e2a1f28488ea 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -360,9 +360,9 @@ Jinja2==3.1.5 \ --hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \ --hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb # via gcp-releasetool -keyring==25.5.0 \ - --hash=sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6 \ - --hash=sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741 +keyring==25.6.0 \ + --hash=sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66 \ + --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd # via # gcp-releasetool # twine From 65856d4a68c5c9a7bd40a0c0fbb4a2713e648d11 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:44:02 +0100 Subject: [PATCH 385/582] chore(deps): update dependency charset-normalizer to v3.4.1 (#564) --- .../.kokoro/requirements.txt | 199 ++++++++---------- packages/sqlalchemy-spanner/requirements.txt | 199 ++++++++---------- 2 files changed, 186 insertions(+), 212 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index e2a1f28488ea..7351696510be 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -93,112 +93,99 @@ cffi==1.17.1 \ --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b # via cryptography -charset-normalizer==3.4.0 \ - --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ - --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ - --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ - --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ - --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ - --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ - --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ - --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ - --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ - --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ - --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ - --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ - --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ - --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ - --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ - --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ - --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ - --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ - --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ - --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ - --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ - --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ - --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ - --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ - --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ - --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ - --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ - --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ - --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ - --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ - --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ - --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ - --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ - --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ - --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ - --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ - --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ - --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ - --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ - --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ - --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ - --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ - --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ - --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ - --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ - --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ - --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ - --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ - --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ - --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ - --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ - --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ - --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ - --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ - --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ - --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ - --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ - --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ - --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ - --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ - --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ - --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ - --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ - --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ - --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ - --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ - --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ - --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ - --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ - --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ - --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ - --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ - --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ - --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ - --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ - --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ - --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ - --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ - --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ - --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ - --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ - --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ - --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ - --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ - --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ - --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ - --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ - --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ - --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ - --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ - --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ - --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ - --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ - --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ - --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ - --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ - --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ - --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ - --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ - --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ - --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ - --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ - --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ - --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ - --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 +charset-normalizer==3.4.1 \ + --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ + --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \ + --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \ + --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \ + --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \ + --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ + --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ + --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ + --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \ + --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ + --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \ + --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ + --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ + --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ + --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ + --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ + --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ + --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \ + --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ + --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ + --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \ + --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \ + --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \ + --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \ + --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \ + --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ + --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \ + --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ + --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ + --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ + --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \ + --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \ + --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ + --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ + --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ + --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \ + --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \ + --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ + --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ + --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ + --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \ + --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \ + --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \ + --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \ + --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \ + --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \ + --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \ + --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ + --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \ + --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ + --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ + --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ + --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \ + --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ + --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \ + --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ + --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ + --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \ + --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ + --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ + --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ + --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \ + --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ + --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ + --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \ + --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \ + --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ + --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ + --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ + --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ + --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ + --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ + --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ + --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ + --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ + --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ + --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ + --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \ + --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \ + --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ + --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ + --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \ + --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ + --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ + --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \ + --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ + --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ + --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \ + --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ + --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ + --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ + --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 # via requests click==8.0.4 \ --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 61cffeb73969..a38eaabcf7e9 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -22,112 +22,99 @@ certifi==2024.12.14 \ --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via requests -charset-normalizer==3.4.0 \ - --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ - --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ - --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ - --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ - --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ - --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ - --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ - --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ - --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ - --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ - --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ - --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ - --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ - --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ - --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ - --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ - --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ - --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ - --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ - --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ - --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ - --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ - --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ - --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ - --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ - --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ - --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ - --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ - --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ - --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ - --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ - --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ - --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ - --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ - --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ - --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ - --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ - --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ - --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ - --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ - --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ - --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ - --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ - --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ - --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ - --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ - --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ - --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ - --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ - --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ - --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ - --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ - --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ - --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ - --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ - --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ - --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ - --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ - --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ - --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ - --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ - --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ - --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ - --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ - --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ - --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ - --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ - --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ - --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ - --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ - --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ - --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ - --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ - --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ - --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ - --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ - --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ - --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ - --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ - --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ - --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ - --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ - --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ - --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ - --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ - --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ - --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ - --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ - --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ - --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ - --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ - --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ - --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ - --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ - --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ - --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ - --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ - --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ - --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ - --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ - --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ - --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ - --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ - --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ - --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 +charset-normalizer==3.4.1 \ + --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ + --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \ + --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \ + --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \ + --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \ + --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ + --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ + --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ + --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \ + --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ + --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \ + --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ + --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ + --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ + --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ + --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ + --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ + --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \ + --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ + --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ + --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \ + --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \ + --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \ + --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \ + --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \ + --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ + --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \ + --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ + --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ + --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ + --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \ + --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \ + --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ + --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ + --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ + --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \ + --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \ + --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ + --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ + --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ + --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \ + --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \ + --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \ + --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \ + --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \ + --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \ + --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \ + --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ + --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \ + --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ + --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ + --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ + --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \ + --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ + --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \ + --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ + --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ + --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \ + --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ + --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ + --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ + --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \ + --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ + --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ + --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \ + --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \ + --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ + --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ + --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ + --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ + --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ + --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ + --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ + --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ + --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ + --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ + --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ + --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \ + --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \ + --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ + --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ + --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \ + --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ + --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ + --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \ + --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ + --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ + --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \ + --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ + --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ + --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ + --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 # via requests click==8.1.7 \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ From 398fd6e81819423718458576ec8136e037acda34 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 14:44:31 +0100 Subject: [PATCH 386/582] chore(deps): update dependency urllib3 to v2.3.0 (#562) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 7351696510be..595732ebebb0 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -612,9 +612,9 @@ typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via -r requirements.in -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.3.0 \ + --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ + --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d # via # requests # twine diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a38eaabcf7e9..8013b92a8a4d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -497,9 +497,9 @@ typing-extensions==4.12.2 \ # alembic # opentelemetry-sdk # sqlalchemy -urllib3==2.2.3 \ - --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ - --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 +urllib3==2.3.0 \ + --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ + --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d # via requests wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ From 6dbcce147109455600e9a62b939d948d8451b48d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Feb 2025 16:02:36 +0100 Subject: [PATCH 387/582] chore(deps): update dependency nh3 to v0.2.20 (#557) --- .../.kokoro/requirements.txt | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 595732ebebb0..f5fe437325bc 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -430,30 +430,31 @@ more-itertools==10.5.0 \ # via # jaraco-classes # jaraco-functools -nh3==0.2.19 \ - --hash=sha256:00810cd5275f5c3f44b9eb0e521d1a841ee2f8023622de39ffc7d88bd533d8e0 \ - --hash=sha256:0b6820fc64f2ff7ef3e7253a093c946a87865c877b3889149a6d21d322ed8dbd \ - --hash=sha256:11270b16c1b012677e3e2dd166c1aa273388776bf99a3e3677179db5097ee16a \ - --hash=sha256:2b926f179eb4bce72b651bfdf76f8aa05d167b2b72bc2f3657fd319f40232adc \ - --hash=sha256:2eb021804e9df1761abeb844bb86648d77aa118a663c82f50ea04110d87ed707 \ - --hash=sha256:3805161c4e12088bd74752ba69630e915bc30fe666034f47217a2f16b16efc37 \ - --hash=sha256:5d4f5e2189861b352b73acb803b5f4bb409c2f36275d22717e27d4e0c217ae55 \ - --hash=sha256:75c7cafb840f24430b009f7368945cb5ca88b2b54bb384ebfba495f16bc9c121 \ - --hash=sha256:7e98621856b0a911c21faa5eef8f8ea3e691526c2433f9afc2be713cb6fbdb48 \ - --hash=sha256:833b3b5f1783ce95834a13030300cea00cbdfd64ea29260d01af9c4821da0aa9 \ - --hash=sha256:a7b928862daddb29805a1010a0282f77f4b8b238a37b5f76bc6c0d16d930fd22 \ - --hash=sha256:ac536a4b5c073fdadd8f5f4889adabe1cbdae55305366fb870723c96ca7f49c3 \ - --hash=sha256:b8eb7affc590e542fa7981ef508cd1644f62176bcd10d4429890fc629b47f0bc \ - --hash=sha256:c2e3f0d18cc101132fe10ab7ef5c4f41411297e639e23b64b5e888ccaad63f41 \ - --hash=sha256:d0adf00e2b2026fa10a42537b60d161e516f206781c7515e4e97e09f72a8c5d0 \ - --hash=sha256:d53a4577b6123ca1d7e8483fad3e13cb7eda28913d516bd0a648c1a473aa21a9 \ - --hash=sha256:d8325d51e47cb5b11f649d55e626d56c76041ba508cd59e0cb1cf687cc7612f1 \ - --hash=sha256:df8eac98fec80bd6f5fd0ae27a65de14f1e1a65a76d8e2237eb695f9cd1121d9 \ - --hash=sha256:e3dedd7858a21312f7675841529941035a2ac91057db13402c8fe907aa19205a \ - --hash=sha256:ec9c8bf86e397cb88c560361f60fdce478b5edb8b93f04ead419b72fbe937ea6 \ - --hash=sha256:ed06ed78f6b69d57463b46a04f68f270605301e69d80756a8adf7519002de57d \ - --hash=sha256:fc483dd8d20f8f8c010783a25a84db3bebeadced92d24d34b40d687f8043ac69 \ - --hash=sha256:fdb20740d24ab9f2a1341458a00a11205294e97e905de060eeab1ceca020c09c +nh3==0.2.20 \ + --hash=sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec \ + --hash=sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c \ + --hash=sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6 \ + --hash=sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38 \ + --hash=sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace \ + --hash=sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7 \ + --hash=sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b \ + --hash=sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784 \ + --hash=sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0 \ + --hash=sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150 \ + --hash=sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776 \ + --hash=sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330 \ + --hash=sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b \ + --hash=sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d \ + --hash=sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5 \ + --hash=sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5 \ + --hash=sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397 \ + --hash=sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886 \ + --hash=sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b \ + --hash=sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a \ + --hash=sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db \ + --hash=sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2 \ + --hash=sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a \ + --hash=sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208 # via # -r requirements.in # readme-renderer From f2727ddba8fa3ec994b3f82679d9fc9c53f2d327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Thu, 20 Feb 2025 18:04:00 +0100 Subject: [PATCH 388/582] docs: add test for using FOR UPDATE (#575) Spanner now supports FOR UPDATE clauses. This change adds a test to verify that FOR UPDATE clauses can be generated with the Spanner SQLAlchemy provider. See also https://cloud.google.com/spanner/docs/release-notes#January_27_2025 --- .../mockserver_tests/mock_server_test_base.py | 47 +++++++++++++++ .../test/mockserver_tests/test_basics.py | 35 +++++++++++ .../test_read_only_transaction.py | 54 ++--------------- .../test/mockserver_tests/test_stale_reads.py | 58 ++----------------- 4 files changed, 92 insertions(+), 102 deletions(-) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py index fa5ed4bdfaf4..a8fea8192438 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import Engine, create_engine from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -79,6 +80,52 @@ def add_single_result( MockServerTestBase.spanner_service.mock_spanner.add_result(sql, result) +def add_singer_query_result(sql: str): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="singers_id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="singers_name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Jane Doe", + ), + ( + "2", + "John Doe", + ), + ] + ) + add_result(sql, result) + + class MockServerTestBase(fixtures.TestBase): server: grpc.Server = None spanner_service: SpannerServicer = None diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 28ea1b86ad29..f895c9e413db 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -25,7 +25,9 @@ String, func, text, + BigInteger, ) +from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( FixedSizePool, @@ -41,6 +43,7 @@ add_result, add_single_result, add_update_count, + add_singer_query_result, ) @@ -179,3 +182,35 @@ def test_partitioned_dml(self): ) results = connection.execute(text(sql)).rowcount eq_(100, results) + + def test_select_for_update(self): + class Base(DeclarativeBase): + pass + + class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) + + query = ( + "SELECT singers.id AS singers_id, singers.name AS singers_name\n" + "FROM singers\n" + "WHERE singers.id = @a0\n" + " LIMIT @a1 FOR UPDATE" + ) + add_singer_query_result(query) + update = "UPDATE singers SET name=@a0 WHERE singers.id = @a1" + add_update_count(update, 1) + + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + singer = ( + session.query(Singer).filter(Singer.id == 1).with_for_update().first() + ) + singer.name = "New Name" + session.add(singer) + session.commit() diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py index 18abf69f3c62..013c0401b194 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py @@ -22,10 +22,10 @@ BeginTransactionRequest, TransactionOptions, ) -from test.mockserver_tests.mock_server_test_base import MockServerTestBase -from test.mockserver_tests.mock_server_test_base import add_result -import google.cloud.spanner_v1.types.type as spanner_type -import google.cloud.spanner_v1.types.result_set as result_set +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_singer_query_result, +) class TestReadOnlyTransaction(MockServerTestBase): @@ -71,49 +71,3 @@ def test_read_only_transaction(self): ), begin_request.options, ) - - -def add_singer_query_result(sql: str): - result = result_set.ResultSet( - dict( - metadata=result_set.ResultSetMetadata( - dict( - row_type=spanner_type.StructType( - dict( - fields=[ - spanner_type.StructType.Field( - dict( - name="singers_id", - type=spanner_type.Type( - dict(code=spanner_type.TypeCode.INT64) - ), - ) - ), - spanner_type.StructType.Field( - dict( - name="singers_name", - type=spanner_type.Type( - dict(code=spanner_type.TypeCode.STRING) - ), - ) - ), - ] - ) - ) - ) - ), - ) - ) - result.rows.extend( - [ - ( - "1", - "Jane Doe", - ), - ( - "2", - "John Doe", - ), - ] - ) - add_result(sql, result) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py index 02be066cde24..d3ac91e8fdb1 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py @@ -23,17 +23,17 @@ BeginTransactionRequest, TransactionOptions, ) -from test.mockserver_tests.mock_server_test_base import MockServerTestBase -from test.mockserver_tests.mock_server_test_base import add_result -import google.cloud.spanner_v1.types.type as spanner_type -import google.cloud.spanner_v1.types.result_set as result_set +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_singer_query_result, +) class TestStaleReads(MockServerTestBase): def test_stale_read_multi_use(self): from test.mockserver_tests.stale_read_model import Singer - add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") + add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", echo=True, @@ -82,7 +82,7 @@ def test_stale_read_multi_use(self): def test_stale_read_single_use(self): from test.mockserver_tests.stale_read_model import Singer - add_singer_query_result("SELECT singers.id, singers.name\n" + "FROM singers") + add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", echo=True, @@ -121,49 +121,3 @@ def test_stale_read_single_use(self): ), execute_request.transaction.single_use, ) - - -def add_singer_query_result(sql: str): - result = result_set.ResultSet( - dict( - metadata=result_set.ResultSetMetadata( - dict( - row_type=spanner_type.StructType( - dict( - fields=[ - spanner_type.StructType.Field( - dict( - name="singers_id", - type=spanner_type.Type( - dict(code=spanner_type.TypeCode.INT64) - ), - ) - ), - spanner_type.StructType.Field( - dict( - name="singers_name", - type=spanner_type.Type( - dict(code=spanner_type.TypeCode.STRING) - ), - ) - ), - ] - ) - ) - ) - ), - ) - ) - result.rows.extend( - [ - ( - "1", - "Jane Doe", - ), - ( - "2", - "John Doe", - ), - ] - ) - add_result(sql, result) From d4e4806bd0e65b8b897ae89eb427b97c6cdbacde Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:04:13 +0100 Subject: [PATCH 389/582] chore(deps): update dependency googleapis-common-protos to v1.67.0 (#584) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index f5fe437325bc..2f3ae1cabc76 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -311,9 +311,9 @@ google-resumable-media==2.7.2 \ --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 # via google-cloud-storage -googleapis-common-protos==1.66.0 \ - --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ - --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed +googleapis-common-protos==1.67.0 \ + --hash=sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86 \ + --hash=sha256:579de760800d13616f51cf8be00c876f00a9f146d3e6510e19d1f4111758b741 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8013b92a8a4d..44654b763163 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -148,9 +148,9 @@ google-cloud-spanner==3.51.0 \ --hash=sha256:2d01f33582526ebe7fab62034e92e722e512c21f6bc4abe27e03d86ef7ea576a \ --hash=sha256:346c2c20f64847883464fb0de5a6f9b48ecc6f79b032a2fb3a0aa088d9a9863f # via -r requirements.in -googleapis-common-protos[grpc]==1.66.0 \ - --hash=sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c \ - --hash=sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed +googleapis-common-protos[grpc]==1.67.0 \ + --hash=sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86 \ + --hash=sha256:579de760800d13616f51cf8be00c876f00a9f146d3e6510e19d1f4111758b741 # via # google-api-core # grpc-google-iam-v1 From 0d30bf0a0049f4b0f462452257ff5561f7351580 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:04:30 +0100 Subject: [PATCH 390/582] chore(deps): update dependency google-auth to v2.38.0 (#583) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 2f3ae1cabc76..1b1d3f98baf8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -260,9 +260,9 @@ google-api-core==2.24.0 \ # via # google-cloud-core # google-cloud-storage -google-auth==2.37.0 \ - --hash=sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00 \ - --hash=sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0 +google-auth==2.38.0 \ + --hash=sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4 \ + --hash=sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a # via # gcp-releasetool # google-api-core diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 44654b763163..f6e5eeb7fe35 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.24.0 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.37.0 \ - --hash=sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00 \ - --hash=sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0 +google-auth==2.38.0 \ + --hash=sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4 \ + --hash=sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a # via # google-api-core # google-cloud-core From e27c6eb9b9a75d5c48872672ed9a199b957dddbb Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:04:45 +0100 Subject: [PATCH 391/582] chore(deps): update dependency gcp-releasetool to v2.5.0 (#582) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 1b1d3f98baf8..bf31e0bd0d2d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -250,9 +250,9 @@ gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea # via -r requirements.in -gcp-releasetool==2.3.0 \ - --hash=sha256:510516c6a2135e55503fd58f5c8e9d93506d8fba4ebed381a1eccb3d8f9b6740 \ - --hash=sha256:804547a3d2e022924bceadcc453fc49e3059a42a607b99e55b1e2a2d10cb5323 +gcp-releasetool==2.5.0 \ + --hash=sha256:3ff79f53a8357b080ba9c66d7adb1282ff23fe1d46912c3f4d7a31d28553d539 \ + --hash=sha256:b6fe993c9f7fa90b6551585161efeaf7a92bf98d4676a5f933f23b3361ef3bb7 # via -r requirements.in google-api-core==2.24.0 \ --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ From 269bb782e5a628bab8b734116d14954236887b1f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:05:03 +0100 Subject: [PATCH 392/582] chore(deps): update dependency filelock to v3.17.0 (#581) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index bf31e0bd0d2d..d7c8b7c96c16 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -242,9 +242,9 @@ docutils==0.21.2 \ --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # via readme-renderer -filelock==3.16.1 \ - --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ - --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 +filelock==3.17.0 \ + --hash=sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338 \ + --hash=sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e # via virtualenv gcp-docuploader==0.6.5 \ --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ From 8e3d3fe94601c8d0325ff18df47a20fccbc5a940 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:05:17 +0100 Subject: [PATCH 393/582] chore(deps): update dependency wrapt to v1.17.2 (#580) --- packages/sqlalchemy-spanner/requirements.txt | 146 ++++++++++--------- 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f6e5eeb7fe35..787f9c8b7c8e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -505,72 +505,86 @@ wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via pip-tools -wrapt==1.17.0 \ - --hash=sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d \ - --hash=sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301 \ - --hash=sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635 \ - --hash=sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a \ - --hash=sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed \ - --hash=sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721 \ - --hash=sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801 \ - --hash=sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b \ - --hash=sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1 \ - --hash=sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88 \ - --hash=sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8 \ - --hash=sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0 \ - --hash=sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f \ - --hash=sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578 \ - --hash=sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7 \ - --hash=sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045 \ - --hash=sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada \ - --hash=sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d \ - --hash=sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b \ - --hash=sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a \ - --hash=sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977 \ - --hash=sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea \ - --hash=sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346 \ - --hash=sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13 \ - --hash=sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22 \ - --hash=sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339 \ - --hash=sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9 \ - --hash=sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181 \ - --hash=sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c \ - --hash=sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90 \ - --hash=sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a \ - --hash=sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489 \ - --hash=sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f \ - --hash=sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504 \ - --hash=sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea \ - --hash=sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569 \ - --hash=sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4 \ - --hash=sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce \ - --hash=sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab \ - --hash=sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a \ - --hash=sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f \ - --hash=sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c \ - --hash=sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9 \ - --hash=sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf \ - --hash=sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d \ - --hash=sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627 \ - --hash=sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d \ - --hash=sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4 \ - --hash=sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c \ - --hash=sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d \ - --hash=sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad \ - --hash=sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b \ - --hash=sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33 \ - --hash=sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371 \ - --hash=sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1 \ - --hash=sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393 \ - --hash=sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106 \ - --hash=sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df \ - --hash=sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379 \ - --hash=sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451 \ - --hash=sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b \ - --hash=sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575 \ - --hash=sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed \ - --hash=sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb \ - --hash=sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838 +wrapt==1.17.2 \ + --hash=sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f \ + --hash=sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c \ + --hash=sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a \ + --hash=sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b \ + --hash=sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555 \ + --hash=sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c \ + --hash=sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b \ + --hash=sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6 \ + --hash=sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8 \ + --hash=sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662 \ + --hash=sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061 \ + --hash=sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998 \ + --hash=sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb \ + --hash=sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62 \ + --hash=sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984 \ + --hash=sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392 \ + --hash=sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2 \ + --hash=sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306 \ + --hash=sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7 \ + --hash=sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3 \ + --hash=sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9 \ + --hash=sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6 \ + --hash=sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192 \ + --hash=sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317 \ + --hash=sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f \ + --hash=sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda \ + --hash=sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563 \ + --hash=sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a \ + --hash=sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f \ + --hash=sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d \ + --hash=sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9 \ + --hash=sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8 \ + --hash=sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82 \ + --hash=sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9 \ + --hash=sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845 \ + --hash=sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82 \ + --hash=sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125 \ + --hash=sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504 \ + --hash=sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b \ + --hash=sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7 \ + --hash=sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc \ + --hash=sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6 \ + --hash=sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40 \ + --hash=sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a \ + --hash=sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3 \ + --hash=sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a \ + --hash=sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72 \ + --hash=sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681 \ + --hash=sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438 \ + --hash=sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae \ + --hash=sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2 \ + --hash=sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb \ + --hash=sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5 \ + --hash=sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a \ + --hash=sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3 \ + --hash=sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8 \ + --hash=sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2 \ + --hash=sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22 \ + --hash=sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72 \ + --hash=sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061 \ + --hash=sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f \ + --hash=sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9 \ + --hash=sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04 \ + --hash=sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98 \ + --hash=sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9 \ + --hash=sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f \ + --hash=sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b \ + --hash=sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925 \ + --hash=sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6 \ + --hash=sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0 \ + --hash=sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9 \ + --hash=sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c \ + --hash=sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991 \ + --hash=sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6 \ + --hash=sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000 \ + --hash=sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb \ + --hash=sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119 \ + --hash=sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b \ + --hash=sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58 # via # deprecated # opentelemetry-instrumentation From 97c6689ee9f366420bf9e9bd8a736dbee43e6ccc Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:05:30 +0100 Subject: [PATCH 394/582] chore(deps): update dependency sqlalchemy to v2.0.38 (#579) --- packages/sqlalchemy-spanner/requirements.txt | 116 +++++++++---------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 787f9c8b7c8e..c0c723b98f80 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -391,64 +391,64 @@ rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 # via google-auth -sqlalchemy==2.0.36 \ - --hash=sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763 \ - --hash=sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436 \ - --hash=sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2 \ - --hash=sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588 \ - --hash=sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e \ - --hash=sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959 \ - --hash=sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d \ - --hash=sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575 \ - --hash=sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908 \ - --hash=sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8 \ - --hash=sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8 \ - --hash=sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545 \ - --hash=sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7 \ - --hash=sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971 \ - --hash=sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855 \ - --hash=sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c \ - --hash=sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71 \ - --hash=sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d \ - --hash=sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb \ - --hash=sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72 \ - --hash=sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f \ - --hash=sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5 \ - --hash=sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346 \ - --hash=sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24 \ - --hash=sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e \ - --hash=sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5 \ - --hash=sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08 \ - --hash=sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793 \ - --hash=sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88 \ - --hash=sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686 \ - --hash=sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b \ - --hash=sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2 \ - --hash=sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28 \ - --hash=sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d \ - --hash=sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5 \ - --hash=sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a \ - --hash=sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a \ - --hash=sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3 \ - --hash=sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf \ - --hash=sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5 \ - --hash=sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef \ - --hash=sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689 \ - --hash=sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c \ - --hash=sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b \ - --hash=sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07 \ - --hash=sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa \ - --hash=sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06 \ - --hash=sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1 \ - --hash=sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff \ - --hash=sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa \ - --hash=sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687 \ - --hash=sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4 \ - --hash=sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb \ - --hash=sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44 \ - --hash=sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c \ - --hash=sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e \ - --hash=sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53 +SQLAlchemy==2.0.38 \ + --hash=sha256:0398361acebb42975deb747a824b5188817d32b5c8f8aba767d51ad0cc7bb08d \ + --hash=sha256:0561832b04c6071bac3aad45b0d3bb6d2c4f46a8409f0a7a9c9fa6673b41bc03 \ + --hash=sha256:07258341402a718f166618470cde0c34e4cec85a39767dce4e24f61ba5e667ea \ + --hash=sha256:0a826f21848632add58bef4f755a33d45105d25656a0c849f2dc2df1c71f6f50 \ + --hash=sha256:1052723e6cd95312f6a6eff9a279fd41bbae67633415373fdac3c430eca3425d \ + --hash=sha256:12d5b06a1f3aeccf295a5843c86835033797fea292c60e72b07bcb5d820e6dd3 \ + --hash=sha256:12f5c9ed53334c3ce719155424dc5407aaa4f6cadeb09c5b627e06abb93933a1 \ + --hash=sha256:2a0ef3f98175d77180ffdc623d38e9f1736e8d86b6ba70bff182a7e68bed7727 \ + --hash=sha256:2f2951dc4b4f990a4b394d6b382accb33141d4d3bd3ef4e2b27287135d6bdd68 \ + --hash=sha256:3868acb639c136d98107c9096303d2d8e5da2880f7706f9f8c06a7f961961149 \ + --hash=sha256:386b7d136919bb66ced64d2228b92d66140de5fefb3c7df6bd79069a269a7b06 \ + --hash=sha256:3d3043375dd5bbcb2282894cbb12e6c559654c67b5fffb462fda815a55bf93f7 \ + --hash=sha256:3e35d5565b35b66905b79ca4ae85840a8d40d31e0b3e2990f2e7692071b179ca \ + --hash=sha256:402c2316d95ed90d3d3c25ad0390afa52f4d2c56b348f212aa9c8d072a40eee5 \ + --hash=sha256:40310db77a55512a18827488e592965d3dec6a3f1e3d8af3f8243134029daca3 \ + --hash=sha256:40e9cdbd18c1f84631312b64993f7d755d85a3930252f6276a77432a2b25a2f3 \ + --hash=sha256:49aa2cdd1e88adb1617c672a09bf4ebf2f05c9448c6dbeba096a3aeeb9d4d443 \ + --hash=sha256:57dd41ba32430cbcc812041d4de8d2ca4651aeefad2626921ae2a23deb8cd6ff \ + --hash=sha256:5dba1cdb8f319084f5b00d41207b2079822aa8d6a4667c0f369fce85e34b0c86 \ + --hash=sha256:5e1d9e429028ce04f187a9f522818386c8b076723cdbe9345708384f49ebcec6 \ + --hash=sha256:63178c675d4c80def39f1febd625a6333f44c0ba269edd8a468b156394b27753 \ + --hash=sha256:6493bc0eacdbb2c0f0d260d8988e943fee06089cd239bd7f3d0c45d1657a70e2 \ + --hash=sha256:64aa8934200e222f72fcfd82ee71c0130a9c07d5725af6fe6e919017d095b297 \ + --hash=sha256:665255e7aae5f38237b3a6eae49d2358d83a59f39ac21036413fab5d1e810578 \ + --hash=sha256:6db316d6e340f862ec059dc12e395d71f39746a20503b124edc255973977b728 \ + --hash=sha256:70065dfabf023b155a9c2a18f573e47e6ca709b9e8619b2e04c54d5bcf193178 \ + --hash=sha256:8455aa60da49cb112df62b4721bd8ad3654a3a02b9452c783e651637a1f21fa2 \ + --hash=sha256:8b0ac78898c50e2574e9f938d2e5caa8fe187d7a5b69b65faa1ea4648925b096 \ + --hash=sha256:8bf312ed8ac096d674c6aa9131b249093c1b37c35db6a967daa4c84746bc1bc9 \ + --hash=sha256:92f99f2623ff16bd4aaf786ccde759c1f676d39c7bf2855eb0b540e1ac4530c8 \ + --hash=sha256:9c8bcad7fc12f0cc5896d8e10fdf703c45bd487294a986903fe032c72201596b \ + --hash=sha256:9cd136184dd5f58892f24001cdce986f5d7e96059d004118d5410671579834a4 \ + --hash=sha256:9eb4fa13c8c7a2404b6a8e3772c17a55b1ba18bc711e25e4d6c0c9f5f541b02a \ + --hash=sha256:a2bc4e49e8329f3283d99840c136ff2cd1a29e49b5624a46a290f04dff48e079 \ + --hash=sha256:a5645cd45f56895cfe3ca3459aed9ff2d3f9aaa29ff7edf557fa7a23515a3725 \ + --hash=sha256:a9afbc3909d0274d6ac8ec891e30210563b2c8bdd52ebbda14146354e7a69373 \ + --hash=sha256:aa498d1392216fae47eaf10c593e06c34476ced9549657fca713d0d1ba5f7248 \ + --hash=sha256:afd776cf1ebfc7f9aa42a09cf19feadb40a26366802d86c1fba080d8e5e74bdd \ + --hash=sha256:b335a7c958bc945e10c522c069cd6e5804f4ff20f9a744dd38e748eb602cbbda \ + --hash=sha256:b3c4817dff8cef5697f5afe5fec6bc1783994d55a68391be24cb7d80d2dbc3a6 \ + --hash=sha256:b79ee64d01d05a5476d5cceb3c27b5535e6bb84ee0f872ba60d9a8cd4d0e6579 \ + --hash=sha256:b87a90f14c68c925817423b0424381f0e16d80fc9a1a1046ef202ab25b19a444 \ + --hash=sha256:bf89e0e4a30714b357f5d46b6f20e0099d38b30d45fa68ea48589faf5f12f62d \ + --hash=sha256:c058b84c3b24812c859300f3b5abf300daa34df20d4d4f42e9652a4d1c48c8a4 \ + --hash=sha256:c09a6ea87658695e527104cf857c70f79f14e9484605e205217aae0ec27b45fc \ + --hash=sha256:c57b8e0841f3fce7b703530ed70c7c36269c6d180ea2e02e36b34cb7288c50c7 \ + --hash=sha256:c9cea5b756173bb86e2235f2f871b406a9b9d722417ae31e5391ccaef5348f2c \ + --hash=sha256:cb39ed598aaf102251483f3e4675c5dd6b289c8142210ef76ba24aae0a8f8aba \ + --hash=sha256:e036549ad14f2b414c725349cce0772ea34a7ab008e9cd67f9084e4f371d1f32 \ + --hash=sha256:e185ea07a99ce8b8edfc788c586c538c4b1351007e614ceb708fd01b095ef33e \ + --hash=sha256:e5a4d82bdb4bf1ac1285a68eab02d253ab73355d9f0fe725a97e1e0fa689decb \ + --hash=sha256:eae27ad7580529a427cfdd52c87abb2dfb15ce2b7a3e0fc29fbb63e2ed6f8120 \ + --hash=sha256:ecef029b69843b82048c5b347d8e6049356aa24ed644006c9a9d7098c3bd3bfd \ + --hash=sha256:ee3bee874cb1fadee2ff2b79fc9fc808aa638670f28b2145074538d4a6a5028e \ + --hash=sha256:f0d3de936b192980209d7b5149e3c98977c3810d401482d05fb6d668d53c1c63 \ + --hash=sha256:f53c0d6a859b2db58332e0e6a921582a02c1677cc93d4cbb36fdf49709b327b2 \ + --hash=sha256:f9d57f1b3061b3e21476b0ad5f0397b112b94ace21d1f439f2db472e568178ae # via # -r requirements.in # alembic From 2cc75b2c1b5dce18c4e8f8f81b1bef80fec2b55d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:05:42 +0100 Subject: [PATCH 395/582] chore(deps): update dependency protobuf to v5.29.3 (#578) --- .../.kokoro/requirements.txt | 24 +++++++++---------- packages/sqlalchemy-spanner/requirements.txt | 24 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d7c8b7c96c16..425d0bc1ecb8 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -483,18 +483,18 @@ proto-plus==1.25.0 \ # via # -r requirements.in # google-api-core -protobuf==5.29.1 \ - --hash=sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c \ - --hash=sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331 \ - --hash=sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34 \ - --hash=sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110 \ - --hash=sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0 \ - --hash=sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853 \ - --hash=sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57 \ - --hash=sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb \ - --hash=sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d \ - --hash=sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155 \ - --hash=sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18 +protobuf==5.29.3 \ + --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ + --hash=sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7 \ + --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ + --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ + --hash=sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da \ + --hash=sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252 \ + --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ + --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ + --hash=sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107 \ + --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ + --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 # via # gcp-docuploader # gcp-releasetool diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c0c723b98f80..d254bc76f690 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -344,18 +344,18 @@ proto-plus==1.25.0 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.1 \ - --hash=sha256:012ce28d862ff417fd629285aca5d9772807f15ceb1a0dbd15b88f58c776c98c \ - --hash=sha256:027fbcc48cea65a6b17028510fdd054147057fa78f4772eb547b9274e5219331 \ - --hash=sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34 \ - --hash=sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110 \ - --hash=sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0 \ - --hash=sha256:50879eb0eb1246e3a5eabbbe566b44b10348939b7cc1b267567e8c3d07213853 \ - --hash=sha256:5a41deccfa5e745cef5c65a560c76ec0ed8e70908a67cc8f4da5fce588b50d57 \ - --hash=sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb \ - --hash=sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d \ - --hash=sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155 \ - --hash=sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18 +protobuf==5.29.3 \ + --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ + --hash=sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7 \ + --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ + --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ + --hash=sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da \ + --hash=sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252 \ + --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ + --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ + --hash=sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107 \ + --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ + --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 # via # google-api-core # google-cloud-spanner From 8bd681b5991522993363e7fcca725a024699581a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:05:55 +0100 Subject: [PATCH 396/582] chore(deps): update dependency mako to v1.3.9 (#577) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d254bc76f690..94355e98c859 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -237,9 +237,9 @@ importlib-metadata==8.5.0 \ --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 # via opentelemetry-api -Mako==1.3.8 \ - --hash=sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627 \ - --hash=sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8 +Mako==1.3.9 \ + --hash=sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1 \ + --hash=sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac # via alembic markupsafe==3.0.2 \ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ From a260729ca2528559257c29dfbbea2bd37b81013f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:06:08 +0100 Subject: [PATCH 397/582] chore(deps): update dependency google-api-core to v2.24.1 (#576) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 425d0bc1ecb8..b39e6585748a 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -254,9 +254,9 @@ gcp-releasetool==2.5.0 \ --hash=sha256:3ff79f53a8357b080ba9c66d7adb1282ff23fe1d46912c3f4d7a31d28553d539 \ --hash=sha256:b6fe993c9f7fa90b6551585161efeaf7a92bf98d4676a5f933f23b3361ef3bb7 # via -r requirements.in -google-api-core==2.24.0 \ - --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ - --hash=sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf +google-api-core==2.24.1 \ + --hash=sha256:bc78d608f5a5bf853b80bd70a795f703294de656c096c0968320830a4bc280f1 \ + --hash=sha256:f8b36f5456ab0dd99a1b693a40a31d1e7757beea380ad1b38faaf8941eae9d8a # via # google-cloud-core # google-cloud-storage diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 94355e98c859..8ec522b347b8 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -128,9 +128,9 @@ Deprecated==1.2.18 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.24.0 \ - --hash=sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9 \ - --hash=sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf +google-api-core[grpc]==2.24.1 \ + --hash=sha256:bc78d608f5a5bf853b80bd70a795f703294de656c096c0968320830a4bc280f1 \ + --hash=sha256:f8b36f5456ab0dd99a1b693a40a31d1e7757beea380ad1b38faaf8941eae9d8a # via # google-cloud-core # google-cloud-spanner From 956462a741243bbc8478814106430ec45baf6d6c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:14:43 +0100 Subject: [PATCH 398/582] chore(deps): update dependency grpcio to v1.70.0 (#588) --- packages/sqlalchemy-spanner/requirements.txt | 112 +++++++++---------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8ec522b347b8..0ded6b075226 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -163,62 +163,62 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.68.1 \ - --hash=sha256:025f790c056815b3bf53da850dd70ebb849fd755a4b1ac822cb65cd631e37d43 \ - --hash=sha256:04cfd68bf4f38f5bb959ee2361a7546916bd9a50f78617a346b3aeb2b42e2161 \ - --hash=sha256:0feb02205a27caca128627bd1df4ee7212db051019a9afa76f4bb6a1a80ca95e \ - --hash=sha256:1098f03dedc3b9810810568060dea4ac0822b4062f537b0f53aa015269be0a76 \ - --hash=sha256:12941d533f3cd45d46f202e3667be8ebf6bcb3573629c7ec12c3e211d99cfccf \ - --hash=sha256:255b1635b0ed81e9f91da4fcc8d43b7ea5520090b9a9ad9340d147066d1d3613 \ - --hash=sha256:298ee7f80e26f9483f0b6f94cc0a046caf54400a11b644713bb5b3d8eb387600 \ - --hash=sha256:2c4cec6177bf325eb6faa6bd834d2ff6aa8bb3b29012cceb4937b86f8b74323c \ - --hash=sha256:2cc1fd04af8399971bcd4f43bd98c22d01029ea2e56e69c34daf2bf8470e47f5 \ - --hash=sha256:334ab917792904245a028f10e803fcd5b6f36a7b2173a820c0b5b076555825e1 \ - --hash=sha256:3522c77d7e6606d6665ec8d50e867f13f946a4e00c7df46768f1c85089eae515 \ - --hash=sha256:37ea3be171f3cf3e7b7e412a98b77685eba9d4fd67421f4a34686a63a65d99f9 \ - --hash=sha256:390eee4225a661c5cd133c09f5da1ee3c84498dc265fd292a6912b65c421c78c \ - --hash=sha256:3aed6544e4d523cd6b3119b0916cef3d15ef2da51e088211e4d1eb91a6c7f4f1 \ - --hash=sha256:3ceb56c4285754e33bb3c2fa777d055e96e6932351a3082ce3559be47f8024f0 \ - --hash=sha256:44a8502dd5de653ae6a73e2de50a401d84184f0331d0ac3daeb044e66d5c5054 \ - --hash=sha256:4b177f5547f1b995826ef529d2eef89cca2f830dd8b2c99ffd5fde4da734ba73 \ - --hash=sha256:4efac5481c696d5cb124ff1c119a78bddbfdd13fc499e3bc0ca81e95fc573684 \ - --hash=sha256:52fbf85aa71263380d330f4fce9f013c0798242e31ede05fcee7fbe40ccfc20d \ - --hash=sha256:55857c71641064f01ff0541a1776bfe04a59db5558e82897d35a7793e525774c \ - --hash=sha256:66a24f3d45c33550703f0abb8b656515b0ab777970fa275693a2f6dc8e35f1c1 \ - --hash=sha256:6ab2d912ca39c51f46baf2a0d92aa265aa96b2443266fc50d234fa88bf877d8e \ - --hash=sha256:77d65165fc35cff6e954e7fd4229e05ec76102d4406d4576528d3a3635fc6172 \ - --hash=sha256:7dfc914cc31c906297b30463dde0b9be48e36939575eaf2a0a22a8096e69afe5 \ - --hash=sha256:7f20ebec257af55694d8f993e162ddf0d36bd82d4e57f74b31c67b3c6d63d8b2 \ - --hash=sha256:80af6f1e69c5e68a2be529990684abdd31ed6622e988bf18850075c81bb1ad6e \ - --hash=sha256:83bbf5807dc3ee94ce1de2dfe8a356e1d74101e4b9d7aa8c720cc4818a34aded \ - --hash=sha256:8720c25cd9ac25dd04ee02b69256d0ce35bf8a0f29e20577427355272230965a \ - --hash=sha256:8829924fffb25386995a31998ccbbeaa7367223e647e0122043dfc485a87c666 \ - --hash=sha256:8a3869a6661ec8f81d93f4597da50336718bde9eb13267a699ac7e0a1d6d0bea \ - --hash=sha256:8cb620037a2fd9eeee97b4531880e439ebfcd6d7d78f2e7dcc3726428ab5ef63 \ - --hash=sha256:919d7f18f63bcad3a0f81146188e90274fde800a94e35d42ffe9eadf6a9a6330 \ - --hash=sha256:95c87ce2a97434dffe7327a4071839ab8e8bffd0054cc74cbe971fba98aedd60 \ - --hash=sha256:963cc8d7d79b12c56008aabd8b457f400952dbea8997dd185f155e2f228db079 \ - --hash=sha256:96f473cdacfdd506008a5d7579c9f6a7ff245a9ade92c3c0265eb76cc591914f \ - --hash=sha256:9d1fae6bbf0816415b81db1e82fb3bf56f7857273c84dcbe68cbe046e58e1ccd \ - --hash=sha256:a0c8ddabef9c8f41617f213e527254c41e8b96ea9d387c632af878d05db9229c \ - --hash=sha256:a1b988b40f2fd9de5c820f3a701a43339d8dcf2cb2f1ca137e2c02671cc83ac1 \ - --hash=sha256:a47faedc9ea2e7a3b6569795c040aae5895a19dde0c728a48d3c5d7995fda385 \ - --hash=sha256:a8040f85dcb9830d8bbb033ae66d272614cec6faceee88d37a88a9bd1a7a704e \ - --hash=sha256:b33bd114fa5a83f03ec6b7b262ef9f5cac549d4126f1dc702078767b10c46ed9 \ - --hash=sha256:c08079b4934b0bf0a8847f42c197b1d12cba6495a3d43febd7e99ecd1cdc8d54 \ - --hash=sha256:c28848761a6520c5c6071d2904a18d339a796ebe6b800adc8b3f474c5ce3c3ad \ - --hash=sha256:cb400138e73969eb5e0535d1d06cae6a6f7a15f2cc74add320e2130b8179211a \ - --hash=sha256:cbb5780e2e740b6b4f2d208e90453591036ff80c02cc605fea1af8e6fc6b1bbe \ - --hash=sha256:ccf2ebd2de2d6661e2520dae293298a3803a98ebfc099275f113ce1f6c2a80f1 \ - --hash=sha256:d35740e3f45f60f3c37b1e6f2f4702c23867b9ce21c6410254c9c682237da68d \ - --hash=sha256:d99abcd61760ebb34bdff37e5a3ba333c5cc09feda8c1ad42547bea0416ada78 \ - --hash=sha256:ddda1aa22495d8acd9dfbafff2866438d12faec4d024ebc2e656784d96328ad0 \ - --hash=sha256:dffd29a2961f3263a16d73945b57cd44a8fd0b235740cb14056f0612329b345e \ - --hash=sha256:e4842e4872ae4ae0f5497bf60a0498fa778c192cc7a9e87877abd2814aca9475 \ - --hash=sha256:e8dbe3e00771bfe3d04feed8210fc6617006d06d9a2679b74605b9fed3e8362c \ - --hash=sha256:ee2e743e51cb964b4975de572aa8fb95b633f496f9fcb5e257893df3be854746 \ - --hash=sha256:eeb38ff04ab6e5756a2aef6ad8d94e89bb4a51ef96e20f45c44ba190fa0bcaad \ - --hash=sha256:f8261fa2a5f679abeb2a0a93ad056d765cdca1c47745eda3f2d87f874ff4b8c9 +grpcio==1.70.0 \ + --hash=sha256:0495c86a55a04a874c7627fd33e5beaee771917d92c0e6d9d797628ac40e7655 \ + --hash=sha256:07269ff4940f6fb6710951116a04cd70284da86d0a4368fd5a3b552744511f5a \ + --hash=sha256:0a5c78d5198a1f0aa60006cd6eb1c912b4a1520b6a3968e677dbcba215fabb40 \ + --hash=sha256:0ba0a173f4feacf90ee618fbc1a27956bfd21260cd31ced9bc707ef551ff7dc7 \ + --hash=sha256:0cd430b9215a15c10b0e7d78f51e8a39d6cf2ea819fd635a7214fae600b1da27 \ + --hash=sha256:0de706c0a5bb9d841e353f6343a9defc9fc35ec61d6eb6111802f3aa9fef29e1 \ + --hash=sha256:17325b0be0c068f35770f944124e8839ea3185d6d54862800fc28cc2ffad205a \ + --hash=sha256:2394e3381071045a706ee2eeb6e08962dd87e8999b90ac15c55f56fa5a8c9597 \ + --hash=sha256:27cc75e22c5dba1fbaf5a66c778e36ca9b8ce850bf58a9db887754593080d839 \ + --hash=sha256:2b0d02e4b25a5c1f9b6c7745d4fa06efc9fd6a611af0fb38d3ba956786b95199 \ + --hash=sha256:374d014f29f9dfdb40510b041792e0e2828a1389281eb590df066e1cc2b404e5 \ + --hash=sha256:3b0f01f6ed9994d7a0b27eeddea43ceac1b7e6f3f9d86aeec0f0064b8cf50fdb \ + --hash=sha256:4119fed8abb7ff6c32e3d2255301e59c316c22d31ab812b3fbcbaf3d0d87cc68 \ + --hash=sha256:412faabcc787bbc826f51be261ae5fa996b21263de5368a55dc2cf824dc5090e \ + --hash=sha256:4f1937f47c77392ccd555728f564a49128b6a197a05a5cd527b796d36f3387d0 \ + --hash=sha256:5413549fdf0b14046c545e19cfc4eb1e37e9e1ebba0ca390a8d4e9963cab44d2 \ + --hash=sha256:558c386ecb0148f4f99b1a65160f9d4b790ed3163e8610d11db47838d452512d \ + --hash=sha256:58ad9ba575b39edef71f4798fdb5c7b6d02ad36d47949cd381d4392a5c9cbcd3 \ + --hash=sha256:5ea67c72101d687d44d9c56068328da39c9ccba634cabb336075fae2eab0d04b \ + --hash=sha256:7385b1cb064734005204bc8994eed7dcb801ed6c2eda283f613ad8c6c75cf873 \ + --hash=sha256:7c73c42102e4a5ec76608d9b60227d917cea46dff4d11d372f64cbeb56d259d0 \ + --hash=sha256:8058667a755f97407fca257c844018b80004ae8035565ebc2812cc550110718d \ + --hash=sha256:879a61bf52ff8ccacbedf534665bb5478ec8e86ad483e76fe4f729aaef867cab \ + --hash=sha256:880bfb43b1bb8905701b926274eafce5c70a105bc6b99e25f62e98ad59cb278e \ + --hash=sha256:8d1584a68d5922330025881e63a6c1b54cc8117291d382e4fa69339b6d914c56 \ + --hash=sha256:95469d1977429f45fe7df441f586521361e235982a0b39e33841549143ae2851 \ + --hash=sha256:9e654c4b17d07eab259d392e12b149c3a134ec52b11ecdc6a515b39aceeec898 \ + --hash=sha256:a31d7e3b529c94e930a117b2175b2efd179d96eb3c7a21ccb0289a8ab05b645c \ + --hash=sha256:aa47688a65643afd8b166928a1da6247d3f46a2784d301e48ca1cc394d2ffb40 \ + --hash=sha256:aa573896aeb7d7ce10b1fa425ba263e8dddd83d71530d1322fd3a16f31257b4a \ + --hash=sha256:aba19419aef9b254e15011b230a180e26e0f6864c90406fdbc255f01d83bc83c \ + --hash=sha256:ac073fe1c4cd856ebcf49e9ed6240f4f84d7a4e6ee95baa5d66ea05d3dd0df7f \ + --hash=sha256:b3c76701428d2df01964bc6479422f20e62fcbc0a37d82ebd58050b86926ef8c \ + --hash=sha256:b745d2c41b27650095e81dea7091668c040457483c9bdb5d0d9de8f8eb25e59f \ + --hash=sha256:bb491125103c800ec209d84c9b51f1c60ea456038e4734688004f377cfacc113 \ + --hash=sha256:c1af8e15b0f0fe0eac75195992a63df17579553b0c4af9f8362cc7cc99ccddf4 \ + --hash=sha256:c78b339869f4dbf89881e0b6fbf376313e4f845a42840a7bdf42ee6caed4b11f \ + --hash=sha256:cb5277db254ab7586769e490b7b22f4ddab3876c490da0a1a9d7c695ccf0bf77 \ + --hash=sha256:cbce24409beaee911c574a3d75d12ffb8c3e3dd1b813321b1d7a96bbcac46bf4 \ + --hash=sha256:cd24d2d9d380fbbee7a5ac86afe9787813f285e684b0271599f95a51bce33528 \ + --hash=sha256:ce7df14b2dcd1102a2ec32f621cc9fab6695effef516efbc6b063ad749867295 \ + --hash=sha256:d24035d49e026353eb042bf7b058fb831db3e06d52bee75c5f2f3ab453e71aca \ + --hash=sha256:d405b005018fd516c9ac529f4b4122342f60ec1cee181788249372524e6db429 \ + --hash=sha256:d63764963412e22f0491d0d32833d71087288f4e24cbcddbae82476bfa1d81fd \ + --hash=sha256:dbe41ad140df911e796d4463168e33ef80a24f5d21ef4d1e310553fcd2c4a386 \ + --hash=sha256:dfa089a734f24ee5f6880c83d043e4f46bf812fcea5181dcb3a572db1e79e01c \ + --hash=sha256:e27585831aa6b57b9250abaf147003e126cd3a6c6ca0c531a01996f31709bed1 \ + --hash=sha256:e7831a0fc1beeeb7759f737f5acd9fdcda520e955049512d68fda03d91186eea \ + --hash=sha256:ed9718f17fbdb472e33b869c77a16d0b55e166b100ec57b016dc7de9c8d236bf \ + --hash=sha256:ef4c14508299b1406c32bdbb9fb7b47612ab979b04cf2b27686ea31882387cff \ + --hash=sha256:f19375f0300b96c0117aca118d400e76fede6db6e91f3c34b7b035822e06c35f \ + --hash=sha256:f2af68a6f5c8f78d56c145161544ad0febbd7479524a59c16b3e25053f39c87f \ + --hash=sha256:f32090238b720eb585248654db8e3afc87b48d26ac423c8dde8334a232ff53c9 \ + --hash=sha256:fe9dbd916df3b60e865258a8c72ac98f3ac9e2a9542dcb72b7a34d236242a5ce \ + --hash=sha256:ff4a8112a79464919bb21c18e956c54add43ec9a4850e3949da54f61c241a4a6 # via # google-api-core # googleapis-common-protos From 7302b30cf3a3aa78381b9e9eeab7565a09127251 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:14:59 +0100 Subject: [PATCH 399/582] chore(deps): update opentelemetry-python monorepo to v1.30.0 (#595) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0ded6b075226..d29d01295324 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -304,9 +304,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.29.0 \ - --hash=sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8 \ - --hash=sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf +opentelemetry-api==1.30.0 \ + --hash=sha256:375893400c1435bf623f7dfb3bcd44825fe6b56c34d0667c542ea8257b1a1240 \ + --hash=sha256:d5f5284890d73fdf47f843dda3210edf37a38d66f44f2b5aedc1e89ed455dc09 # via # -r requirements.in # opentelemetry-instrumentation @@ -316,9 +316,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.29.0 \ - --hash=sha256:173be3b5d3f8f7d671f20ea37056710217959e774e2749d984355d1f9391a30a \ - --hash=sha256:b0787ce6aade6ab84315302e72bd7a7f2f014b0fb1b7c3295b88afe014ed0643 +opentelemetry-sdk==1.30.0 \ + --hash=sha256:14fe7afc090caad881addb6926cec967129bd9260c4d33ae6a217359f6b61091 \ + --hash=sha256:c9287a9e4a7614b9946e933a67168450b9ab35f08797eb9bc77d998fa480fa18 # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 5158e817d9f13da4831a67f7c5661ded49d7db46 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:15:17 +0100 Subject: [PATCH 400/582] chore(deps): update dependency pygments to v2.19.1 (#593) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b39e6585748a..fc237017679f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -515,9 +515,9 @@ pycparser==2.22 \ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc # via cffi -pygments==2.18.0 \ - --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ - --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a +Pygments==2.19.1 \ + --hash=sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f \ + --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c # via # readme-renderer # rich From e5a5141b128e0c9fcd164e9a2c4e9040e90f7595 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:15:31 +0100 Subject: [PATCH 401/582] chore(deps): update dependency grpcio-status to v1.70.0 (#589) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d29d01295324..e444d99071ff 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -225,9 +225,9 @@ grpcio==1.70.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.68.1 \ - --hash=sha256:66f3d8847f665acfd56221333d66f7ad8927903d87242a482996bdb45e8d28fd \ - --hash=sha256:e1378d036c81a1610d7b4c7a146cd663dd13fcc915cf4d7d053929dba5bbb6e1 +grpcio-status==1.70.0 \ + --hash=sha256:0e7b42816512433b18b9d764285ff029bde059e9d41f8fe10a60631bd8348101 \ + --hash=sha256:fc5a2ae2b9b1c1969cc49f3262676e6854aa2398ec69cb5bd6c47cd501904a85 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 6be11133cbe82c64f74949ba26024e914e2058e9 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:15:45 +0100 Subject: [PATCH 402/582] chore(deps): update dependency pkginfo to v1.12.1.2 (#585) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index fc237017679f..b2cbbf845284 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -469,9 +469,9 @@ packaging==24.2 \ # gcp-releasetool # nox # twine -pkginfo==1.12.0 \ - --hash=sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf \ - --hash=sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088 +pkginfo==1.12.1.2 \ + --hash=sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b \ + --hash=sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343 # via twine platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ From a04a6ab9400b468b4bac225903efebf927d68593 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:16:01 +0100 Subject: [PATCH 403/582] chore(deps): update dependency google-cloud-spanner to v3.52.0 (#586) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e444d99071ff..edfa06462177 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -144,9 +144,9 @@ google-cloud-core==2.4.1 \ --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 # via google-cloud-spanner -google-cloud-spanner==3.51.0 \ - --hash=sha256:2d01f33582526ebe7fab62034e92e722e512c21f6bc4abe27e03d86ef7ea576a \ - --hash=sha256:346c2c20f64847883464fb0de5a6f9b48ecc6f79b032a2fb3a0aa088d9a9863f +google-cloud-spanner==3.52.0 \ + --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ + --hash=sha256:d6c30a7ad9742bbe93dc5fc11293f0b339714d1dbf395b541ca9c8942d5ecf3f # via -r requirements.in googleapis-common-protos[grpc]==1.67.0 \ --hash=sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86 \ From 6bec8be3ce3d65e9bb0ee26ec9b353fb8c54a821 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:16:14 +0100 Subject: [PATCH 404/582] chore(deps): update dependency grpc-google-iam-v1 to v0.14.0 (#587) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index edfa06462177..dca72781393f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -155,9 +155,9 @@ googleapis-common-protos[grpc]==1.67.0 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -grpc-google-iam-v1==0.13.1 \ - --hash=sha256:3ff4b2fd9d990965e410965253c0da6f66205d5a8291c4c31c6ebecca18a9001 \ - --hash=sha256:c3e86151a981811f30d5e7330f271cee53e73bb87755e88cc3b6f0c7b5fe374e +grpc-google-iam-v1==0.14.0 \ + --hash=sha256:c66e07aa642e39bb37950f9e7f491f70dad150ac9801263b42b2814307c2df99 \ + --hash=sha256:fb4a084b30099ba3ab07d61d620a0d4429570b13ff53bd37bac75235f98b7da4 # via google-cloud-spanner grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ From d73b4f993cce1dd4ccf452744613c9e97caa75e0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:16:28 +0100 Subject: [PATCH 405/582] chore(deps): update dependency importlib-metadata to v8.6.1 (#590) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index b2cbbf845284..762d415bb211 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -319,9 +319,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.5.0 \ - --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ - --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 +importlib-metadata==8.6.1 \ + --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ + --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 # via -r requirements.in jaraco-classes==3.4.0 \ --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index dca72781393f..cd117559b2f7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -233,9 +233,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.5.0 \ - --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \ - --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7 +importlib-metadata==8.6.1 \ + --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ + --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 # via opentelemetry-api Mako==1.3.9 \ --hash=sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1 \ From 4b5bd6511ca2abc3559786291b8b18157fea520f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:16:45 +0100 Subject: [PATCH 406/582] chore(deps): update dependency more-itertools to v10.6.0 (#591) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 762d415bb211..95264ec23b03 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -424,9 +424,9 @@ mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba # via markdown-it-py -more-itertools==10.5.0 \ - --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ - --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 +more-itertools==10.6.0 \ + --hash=sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b \ + --hash=sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89 # via # jaraco-classes # jaraco-functools From f37aef728b0477c174f5e0ab773037b127d7ecdf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:16:59 +0100 Subject: [PATCH 407/582] chore(deps): update dependency proto-plus to v1.26.0 (#592) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 95264ec23b03..d1fe66725bc2 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -477,9 +477,9 @@ platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb # via virtualenv -proto-plus==1.25.0 \ - --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ - --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 +proto-plus==1.26.0 \ + --hash=sha256:6e93d5f5ca267b54300880fff156b6a3386b3fa3f43b1da62e680fc0c586ef22 \ + --hash=sha256:bf2dfaa3da281fc3187d12d224c707cb57214fb2c22ba854eb0c105a3fb2d4d7 # via # -r requirements.in # google-api-core diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index cd117559b2f7..f52eeccb5f96 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -338,9 +338,9 @@ pip-tools==7.4.1 \ --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \ --hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9 # via -r requirements.in -proto-plus==1.25.0 \ - --hash=sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961 \ - --hash=sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91 +proto-plus==1.26.0 \ + --hash=sha256:6e93d5f5ca267b54300880fff156b6a3386b3fa3f43b1da62e680fc0c586ef22 \ + --hash=sha256:bf2dfaa3da281fc3187d12d224c707cb57214fb2c22ba854eb0c105a3fb2d4d7 # via # google-api-core # google-cloud-spanner From 0ce4a928ca452f2e8b5565f2464c95d25a97ead3 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:17:14 +0100 Subject: [PATCH 408/582] chore(deps): update dependency attrs to v25 (#596) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index d1fe66725bc2..84fff5743f7f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -8,9 +8,9 @@ argcomplete==3.5.3 \ --hash=sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61 \ --hash=sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392 # via nox -attrs==24.3.0 \ - --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \ - --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308 +attrs==25.1.0 \ + --hash=sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e \ + --hash=sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a # via gcp-releasetool backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ From 8e029040a600157f0b26872f4501bdfc9afeac50 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 20 Feb 2025 18:17:27 +0100 Subject: [PATCH 409/582] chore(deps): update dependency certifi to v2025 (#597) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 84fff5743f7f..570940fd8c8f 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.5.1 \ --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb # via google-auth -certifi==2024.12.14 \ - --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ - --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db +certifi==2025.1.31 \ + --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ + --hash=sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe # via requests cffi==1.17.1 \ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f52eeccb5f96..cc55ccdbd9d5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.5.1 \ --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb # via google-auth -certifi==2024.12.14 \ - --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ - --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db +certifi==2025.1.31 \ + --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ + --hash=sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe # via requests charset-normalizer==3.4.1 \ --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ From ebb8345f7342ad9b2ed5a2b39382499c2cacd0c0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 21 Feb 2025 12:22:02 +0100 Subject: [PATCH 410/582] chore(deps): update dependency googleapis-common-protos to v1.68.0 (#602) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 570940fd8c8f..8fe9e0ee605e 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -311,9 +311,9 @@ google-resumable-media==2.7.2 \ --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 # via google-cloud-storage -googleapis-common-protos==1.67.0 \ - --hash=sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86 \ - --hash=sha256:579de760800d13616f51cf8be00c876f00a9f146d3e6510e19d1f4111758b741 +googleapis-common-protos==1.68.0 \ + --hash=sha256:95d38161f4f9af0d9423eed8fb7b64ffd2568c3464eb542ff02c5bfa1953ab3c \ + --hash=sha256:aaf179b2f81df26dfadac95def3b16a95064c76a5f45f07e4c68a21bb371c4ac # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index cc55ccdbd9d5..54db9c9bba98 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -148,9 +148,9 @@ google-cloud-spanner==3.52.0 \ --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ --hash=sha256:d6c30a7ad9742bbe93dc5fc11293f0b339714d1dbf395b541ca9c8942d5ecf3f # via -r requirements.in -googleapis-common-protos[grpc]==1.67.0 \ - --hash=sha256:21398025365f138be356d5923e9168737d94d46a72aefee4a6110a1f23463c86 \ - --hash=sha256:579de760800d13616f51cf8be00c876f00a9f146d3e6510e19d1f4111758b741 +googleapis-common-protos[grpc]==1.68.0 \ + --hash=sha256:95d38161f4f9af0d9423eed8fb7b64ffd2568c3464eb542ff02c5bfa1953ab3c \ + --hash=sha256:aaf179b2f81df26dfadac95def3b16a95064c76a5f45f07e4c68a21bb371c4ac # via # google-api-core # grpc-google-iam-v1 From 9969a9ea2b122761ffef6bb0fcdae38cd89c5d27 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 21 Feb 2025 12:27:21 +0100 Subject: [PATCH 411/582] chore(deps): update dependency google-cloud-core to v2.4.2 (#601) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 8fe9e0ee605e..0141cf7715c1 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -268,9 +268,9 @@ google-auth==2.38.0 \ # google-api-core # google-cloud-core # google-cloud-storage -google-cloud-core==2.4.1 \ - --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ - --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 +google-cloud-core==2.4.2 \ + --hash=sha256:7459c3e83de7cb8b9ecfec9babc910efb4314030c56dd798eaad12c426f7d180 \ + --hash=sha256:a4fcb0e2fcfd4bfe963837fad6d10943754fd79c1a50097d68540b6eb3d67f35 # via google-cloud-storage google-cloud-storage==2.19.0 \ --hash=sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 54db9c9bba98..cce7f0686cb3 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -140,9 +140,9 @@ google-auth==2.38.0 \ # via # google-api-core # google-cloud-core -google-cloud-core==2.4.1 \ - --hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \ - --hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61 +google-cloud-core==2.4.2 \ + --hash=sha256:7459c3e83de7cb8b9ecfec9babc910efb4314030c56dd798eaad12c426f7d180 \ + --hash=sha256:a4fcb0e2fcfd4bfe963837fad6d10943754fd79c1a50097d68540b6eb3d67f35 # via google-cloud-spanner google-cloud-spanner==3.52.0 \ --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ From 8cd68416146a4242ca02978b52791d0d22adeebf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 21 Feb 2025 12:30:34 +0100 Subject: [PATCH 412/582] chore(deps): update dependency cachetools to v5.5.2 (#600) --- packages/sqlalchemy-spanner/.kokoro/requirements.txt | 6 +++--- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt index 0141cf7715c1..83eae438e76d 100644 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ b/packages/sqlalchemy-spanner/.kokoro/requirements.txt @@ -16,9 +16,9 @@ backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 # via -r requirements.in -cachetools==5.5.1 \ - --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ - --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb +cachetools==5.5.2 \ + --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ + --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth certifi==2025.1.31 \ --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index cce7f0686cb3..48751f90e6e1 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==5.5.1 \ - --hash=sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95 \ - --hash=sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb +cachetools==5.5.2 \ + --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ + --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth certifi==2025.1.31 \ --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ From fdd51b716153c2fa7b420d0b10f82beb186e9832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 21 Feb 2025 13:32:48 +0100 Subject: [PATCH 413/582] feat: support request and transaction tags (#558) * feat: support transaction and request tags in dbapi Adds support for setting transaction tags and request tags in dbapi. This makes these options available to frameworks that depend on dbapi, like SQLAlchemy and Django. Towards https://github.com/googleapis/python-spanner-sqlalchemy/issues/525 * test: add test for transaction tags * test: fix test cases --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 8 + .../test/mockserver_tests/tags_model.py | 28 ++++ .../test/mockserver_tests/test_basics.py | 6 +- .../test/mockserver_tests/test_tags.py | 139 ++++++++++++++++++ 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/tags_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e6042e3166cc..0c8e0c87c5c7 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -180,6 +180,14 @@ def pre_exec(self): if priority is not None: self._dbapi_connection.connection.request_priority = priority + transaction_tag = self.execution_options.get("transaction_tag") + if transaction_tag: + self._dbapi_connection.connection.transaction_tag = transaction_tag + + request_tag = self.execution_options.get("request_tag") + if request_tag: + self.cursor.request_tag = request_tag + def fire_sequence(self, seq, type_): """Builds a statement for fetching next value of the sequence.""" return self._execute_scalar( diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/tags_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/tags_model.py new file mode 100644 index 000000000000..9965dbf03dfa --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/tags_model.py @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index f895c9e413db..29bffa82d799 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -74,8 +74,12 @@ def test_sqlalchemy_select1(self): with engine.connect().execution_options( isolation_level="AUTOCOMMIT" ) as connection: - results = connection.execute(select(1)).fetchall() + results = connection.execute( + select(1).execution_options(request_tag="my-tag") + ).fetchall() self.verify_select1(results) + request: ExecuteSqlRequest = self.spanner_service.requests[1] + eq_("my-tag", request.request_options.request_tag) def test_sqlalchemy_select_now(self): now = datetime.datetime.now(datetime.UTC) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py new file mode 100644 index 000000000000..c422bc5edd19 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py @@ -0,0 +1,139 @@ +# Copyright 2024 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine, select +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + BeginTransactionRequest, + CommitRequest, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_update_count, +) +from test.mockserver_tests.mock_server_test_base import add_result +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestStaleReads(MockServerTestBase): + def test_request_tag(self): + from test.mockserver_tests.tags_model import Singer + + add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine.execution_options(read_only=True)) as session: + # Execute two queries in a read-only transaction. + session.scalars( + select(Singer).execution_options(request_tag="my-tag-1") + ).all() + session.scalars( + select(Singer).execution_options(request_tag="my-tag-2") + ).all() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], ExecuteSqlRequest) + # Verify that we got a request tag for the queries. + eq_("my-tag-1", requests[2].request_options.request_tag) + eq_("my-tag-2", requests[3].request_options.request_tag) + + def test_transaction_tag(self): + from test.mockserver_tests.tags_model import Singer + + add_singer_query_result("SELECT singers.id, singers.name\n" + "FROM singers") + add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session( + engine.execution_options(transaction_tag="my-transaction-tag") + ) as session: + # Execute a query and an insert statement in a read/write transaction. + session.scalars( + select(Singer).execution_options(request_tag="my-tag-1") + ).all() + session.add(Singer(id=1, name="Some Singer")) + session.commit() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(5, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], ExecuteSqlRequest) + is_instance_of(requests[4], CommitRequest) + for request in requests[2:]: + eq_("my-transaction-tag", request.request_options.transaction_tag) + + +def add_singer_query_result(sql: str): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="singers_id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="singers_name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Jane Doe", + ), + ( + "2", + "John Doe", + ), + ] + ) + add_result(sql, result) From fd6811cfe55bdcf58e39739a6b6a14b582f44f0f Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 08:30:32 +0100 Subject: [PATCH 414/582] chore(main): release 1.9.0 (#603) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 12 ++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index fccd8630dd26..716e2b0aef55 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.9.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.8.0...v1.9.0) (2025-02-21) + + +### Features + +* Support request and transaction tags ([#558](https://github.com/googleapis/python-spanner-sqlalchemy/issues/558)) ([c4496fd](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c4496fd73c2afe0f519fed0264abe2abb9d022b9)) + + +### Documentation + +* Add test for using FOR UPDATE ([#575](https://github.com/googleapis/python-spanner-sqlalchemy/issues/575)) ([8419ae4](https://github.com/googleapis/python-spanner-sqlalchemy/commit/8419ae4ef07ba5b5e3134586c475cfcaeda240b5)) + ## [1.8.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.7.0...v1.8.0) (2024-12-09) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index fa7013985457..7d6b472bcf15 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.8.0" +__version__ = "1.9.0" From 87b26d6918432e1960f3e841c4b3579b634bb482 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Mon, 10 Mar 2025 11:03:57 -0400 Subject: [PATCH 415/582] chore: remove unused files (#614) --- packages/sqlalchemy-spanner/.kokoro/build.sh | 6 - .../.kokoro/docker/docs/Dockerfile | 59 -- .../.kokoro/docker/docs/fetch_gpg_keys.sh | 37 - .../.kokoro/publish-docs.sh | 57 -- .../sqlalchemy-spanner/.kokoro/release.sh | 25 - .../.kokoro/release/common.cfg | 40 -- .../.kokoro/release/release.cfg | 1 - .../.kokoro/requirements.in | 13 - .../.kokoro/requirements.txt | 633 ------------------ 9 files changed, 871 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile delete mode 100755 packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh delete mode 100755 packages/sqlalchemy-spanner/.kokoro/publish-docs.sh delete mode 100755 packages/sqlalchemy-spanner/.kokoro/release.sh delete mode 100644 packages/sqlalchemy-spanner/.kokoro/release/common.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/release/release.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/requirements.in delete mode 100644 packages/sqlalchemy-spanner/.kokoro/requirements.txt diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh index 0985afd04bf2..072d854fde5d 100755 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ b/packages/sqlalchemy-spanner/.kokoro/build.sh @@ -21,12 +21,6 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") export GOOGLE_CLOUD_PROJECT=$(cat "${KOKORO_GFILE_DIR}/project-id.json") -# Remove old nox -python3 -m pip uninstall --yes --quiet nox-automation - -# Install nox -python3 -m pip install --require-hashes -r .kokoro/requirements.txt -python3 -m pip install --upgrade --quiet nox python3 -m nox --version # If this is a continuous build, send the test log to the FlakyBot. diff --git a/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile b/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile deleted file mode 100644 index e2bfb5b860c6..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/docker/docs/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -from ubuntu:24.04 - -ENV DEBIAN_FRONTEND noninteractive - -# Ensure local Python is preferred over distribution Python. -ENV PATH /usr/local/bin:$PATH - -# Install dependencies. -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-transport-https \ - build-essential \ - ca-certificates \ - curl \ - dirmngr \ - git \ - gpg-agent \ - graphviz \ - libbz2-dev \ - libdb5.3-dev \ - libexpat1-dev \ - libffi-dev \ - liblzma-dev \ - libreadline-dev \ - libsnappy-dev \ - libssl-dev \ - libsqlite3-dev \ - portaudio19-dev \ - python3-distutils \ - redis-server \ - software-properties-common \ - ssh \ - sudo \ - tcl \ - tcl-dev \ - tk \ - tk-dev \ - uuid-dev \ - wget \ - zlib1g-dev \ - && add-apt-repository universe \ - && apt-get update \ - && apt-get -y install jq \ - && apt-get clean autoclean \ - && apt-get autoremove -y \ - && rm -rf /var/lib/apt/lists/* \ - && rm -f /var/cache/apt/archives/*.deb - -RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3.8 /tmp/get-pip.py \ - && rm /tmp/get-pip.py - -CMD ["python3.8"] diff --git a/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh b/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh deleted file mode 100755 index 2b2b7e953816..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/docker/docs/fetch_gpg_keys.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -# A script to fetch gpg keys with retry. -# Avoid jinja parsing the file. -# - -function retry { - if [[ "${#}" -le 1 ]]; then - echo "Usage: ${0} retry_count commands.." - exit 1 - fi - local retries=${1} - local command="${@:2}" - until [[ "${retries}" -le 0 ]]; do - $command && return 0 - if [[ $? -ne 0 ]]; then - echo "command failed, retrying" - ((retries--)) - fi - done - return 1 -} - -# 3.6.9, 3.7.5 (Ned Deily) -retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ - 0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D - -# 3.8.0 (Łukasz Langa) -retry 3 gpg --keyserver ha.pool.sks-keyservers.net --recv-keys \ - E3FF2839C048B25C084DEBE9B26995E310250568 - -# diff --git a/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh b/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh deleted file mode 100755 index e504a188ca65..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/publish-docs.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -set -eo pipefail - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -export PATH="${HOME}/.local/bin:${PATH}" - -# Install nox -python3 -m pip install --require-hashes -r requirements.txt -python3 -m pip install --user --upgrade --quiet nox -python3 -m nox --version - -# build docs -nox -s docs - -python3 -m pip install --user gcp-docuploader - -# create metadata -python3 -m docuploader create-metadata \ - --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3 setup.py --version) \ - --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3 setup.py --name) \ - --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ - --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ - --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) - -cat docs.metadata - -# upload docs -python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}" - - -# docfx yaml files -nox -s docfx - -# create metadata. -python3 -m docuploader create-metadata \ - --name=$(jq --raw-output '.name // empty' .repo-metadata.json) \ - --version=$(python3 setup.py --version) \ - --language=$(jq --raw-output '.language // empty' .repo-metadata.json) \ - --distribution-name=$(python3 setup.py --name) \ - --product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \ - --github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \ - --issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json) - -cat docs.metadata - -# upload docs -python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}" diff --git a/packages/sqlalchemy-spanner/.kokoro/release.sh b/packages/sqlalchemy-spanner/.kokoro/release.sh deleted file mode 100755 index 2d0cee72b9de..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/release.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -set -eo pipefail - -# Start the releasetool reporter -python3 -m pip install --require-hashes -r github/python-spanner-sqlalchemy/.kokoro/requirements.txt -python3 -m pip install gcp-releasetool -python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script - -# Ensure that we have the latest versions of Twine, Wheel, and Setuptools. -python3 -m pip install --upgrade twine wheel setuptools - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Move into the package, build the distribution and upload. -TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1") -cd github/python-spanner-sqlalchemy -python3 setup.py sdist bdist_wheel -twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/* diff --git a/packages/sqlalchemy-spanner/.kokoro/release/common.cfg b/packages/sqlalchemy-spanner/.kokoro/release/common.cfg deleted file mode 100644 index 92607a27a9eb..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/release/common.cfg +++ /dev/null @@ -1,40 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner-sqlalchemy/.kokoro/release.sh" -} - -# Fetch PyPI password -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "google-cloud-pypi-token-keystore-1" - } - } -} - -# Tokens needed to report release status back to GitHub -env_vars: { - key: "SECRET_MANAGER_KEYS" - value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" -} diff --git a/packages/sqlalchemy-spanner/.kokoro/release/release.cfg b/packages/sqlalchemy-spanner/.kokoro/release/release.cfg deleted file mode 100644 index 8f43917d92fe..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/release/release.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.in b/packages/sqlalchemy-spanner/.kokoro/requirements.in deleted file mode 100644 index b52510c98e0d..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.in +++ /dev/null @@ -1,13 +0,0 @@ -gcp-docuploader -gcp-releasetool -importlib-metadata -typing-extensions -twine -wheel -setuptools -nox -nh3 -proto-plus -tomli -jaraco.context -backports.tarfile diff --git a/packages/sqlalchemy-spanner/.kokoro/requirements.txt b/packages/sqlalchemy-spanner/.kokoro/requirements.txt deleted file mode 100644 index 83eae438e76d..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/requirements.txt +++ /dev/null @@ -1,633 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --generate-hashes requirements.in -# -argcomplete==3.5.3 \ - --hash=sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61 \ - --hash=sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392 - # via nox -attrs==25.1.0 \ - --hash=sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e \ - --hash=sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a - # via gcp-releasetool -backports-tarfile==1.2.0 \ - --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ - --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 - # via -r requirements.in -cachetools==5.5.2 \ - --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ - --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a - # via google-auth -certifi==2025.1.31 \ - --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ - --hash=sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe - # via requests -cffi==1.17.1 \ - --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ - --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ - --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ - --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ - --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ - --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ - --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ - --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ - --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ - --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ - --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ - --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ - --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ - --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ - --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ - --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ - --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ - --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ - --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ - --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ - --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ - --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ - --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ - --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ - --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ - --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ - --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ - --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ - --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ - --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ - --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ - --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ - --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ - --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ - --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ - --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ - --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ - --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ - --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ - --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ - --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ - --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ - --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ - --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ - --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ - --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ - --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ - --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ - --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ - --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ - --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ - --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ - --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ - --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ - --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ - --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ - --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ - --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ - --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ - --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ - --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ - --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ - --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ - --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ - --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ - --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ - --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b - # via cryptography -charset-normalizer==3.4.1 \ - --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ - --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \ - --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \ - --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \ - --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \ - --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ - --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ - --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ - --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \ - --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ - --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \ - --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ - --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ - --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ - --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ - --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ - --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ - --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \ - --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ - --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ - --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \ - --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \ - --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \ - --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \ - --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \ - --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ - --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \ - --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ - --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ - --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ - --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \ - --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \ - --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ - --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ - --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ - --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \ - --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \ - --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ - --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ - --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ - --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \ - --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \ - --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \ - --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \ - --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \ - --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \ - --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \ - --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ - --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \ - --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ - --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ - --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ - --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \ - --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ - --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \ - --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ - --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ - --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \ - --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ - --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ - --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ - --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \ - --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ - --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ - --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \ - --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \ - --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ - --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ - --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ - --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ - --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ - --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ - --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ - --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ - --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ - --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ - --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ - --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \ - --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \ - --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ - --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ - --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \ - --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ - --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ - --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \ - --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ - --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ - --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \ - --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ - --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ - --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ - --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 - # via requests -click==8.0.4 \ - --hash=sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1 \ - --hash=sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb - # via - # gcp-docuploader - # gcp-releasetool -colorlog==6.9.0 \ - --hash=sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff \ - --hash=sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2 - # via - # gcp-docuploader - # nox -cryptography==44.0.1 \ - --hash=sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7 \ - --hash=sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3 \ - --hash=sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183 \ - --hash=sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69 \ - --hash=sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a \ - --hash=sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62 \ - --hash=sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911 \ - --hash=sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7 \ - --hash=sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a \ - --hash=sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41 \ - --hash=sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83 \ - --hash=sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12 \ - --hash=sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864 \ - --hash=sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf \ - --hash=sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c \ - --hash=sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2 \ - --hash=sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b \ - --hash=sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0 \ - --hash=sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4 \ - --hash=sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9 \ - --hash=sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008 \ - --hash=sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862 \ - --hash=sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009 \ - --hash=sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7 \ - --hash=sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f \ - --hash=sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026 \ - --hash=sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f \ - --hash=sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd \ - --hash=sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420 \ - --hash=sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14 \ - --hash=sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00 - # via - # gcp-releasetool - # secretstorage -distlib==0.3.9 \ - --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ - --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 - # via virtualenv -docutils==0.21.2 \ - --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ - --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 - # via readme-renderer -filelock==3.17.0 \ - --hash=sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338 \ - --hash=sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e - # via virtualenv -gcp-docuploader==0.6.5 \ - --hash=sha256:30221d4ac3e5a2b9c69aa52fdbef68cc3f27d0e6d0d90e220fc024584b8d2318 \ - --hash=sha256:b7458ef93f605b9d46a4bf3a8dc1755dad1f31d030c8679edf304e343b347eea - # via -r requirements.in -gcp-releasetool==2.5.0 \ - --hash=sha256:3ff79f53a8357b080ba9c66d7adb1282ff23fe1d46912c3f4d7a31d28553d539 \ - --hash=sha256:b6fe993c9f7fa90b6551585161efeaf7a92bf98d4676a5f933f23b3361ef3bb7 - # via -r requirements.in -google-api-core==2.24.1 \ - --hash=sha256:bc78d608f5a5bf853b80bd70a795f703294de656c096c0968320830a4bc280f1 \ - --hash=sha256:f8b36f5456ab0dd99a1b693a40a31d1e7757beea380ad1b38faaf8941eae9d8a - # via - # google-cloud-core - # google-cloud-storage -google-auth==2.38.0 \ - --hash=sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4 \ - --hash=sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a - # via - # gcp-releasetool - # google-api-core - # google-cloud-core - # google-cloud-storage -google-cloud-core==2.4.2 \ - --hash=sha256:7459c3e83de7cb8b9ecfec9babc910efb4314030c56dd798eaad12c426f7d180 \ - --hash=sha256:a4fcb0e2fcfd4bfe963837fad6d10943754fd79c1a50097d68540b6eb3d67f35 - # via google-cloud-storage -google-cloud-storage==2.19.0 \ - --hash=sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba \ - --hash=sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2 - # via gcp-docuploader -google-crc32c==1.6.0 \ - --hash=sha256:05e2d8c9a2f853ff116db9706b4a27350587f341eda835f46db3c0a8c8ce2f24 \ - --hash=sha256:18e311c64008f1f1379158158bb3f0c8d72635b9eb4f9545f8cf990c5668e59d \ - --hash=sha256:236c87a46cdf06384f614e9092b82c05f81bd34b80248021f729396a78e55d7e \ - --hash=sha256:35834855408429cecf495cac67ccbab802de269e948e27478b1e47dfb6465e57 \ - --hash=sha256:386122eeaaa76951a8196310432c5b0ef3b53590ef4c317ec7588ec554fec5d2 \ - --hash=sha256:40b05ab32a5067525670880eb5d169529089a26fe35dce8891127aeddc1950e8 \ - --hash=sha256:48abd62ca76a2cbe034542ed1b6aee851b6f28aaca4e6551b5599b6f3ef175cc \ - --hash=sha256:50cf2a96da226dcbff8671233ecf37bf6e95de98b2a2ebadbfdf455e6d05df42 \ - --hash=sha256:51c4f54dd8c6dfeb58d1df5e4f7f97df8abf17a36626a217f169893d1d7f3e9f \ - --hash=sha256:5bcc90b34df28a4b38653c36bb5ada35671ad105c99cfe915fb5bed7ad6924aa \ - --hash=sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b \ - --hash=sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc \ - --hash=sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760 \ - --hash=sha256:91ca8145b060679ec9176e6de4f89b07363d6805bd4760631ef254905503598d \ - --hash=sha256:a184243544811e4a50d345838a883733461e67578959ac59964e43cca2c791e7 \ - --hash=sha256:a9e4b426c3702f3cd23b933436487eb34e01e00327fac20c9aebb68ccf34117d \ - --hash=sha256:bb0966e1c50d0ef5bc743312cc730b533491d60585a9a08f897274e57c3f70e0 \ - --hash=sha256:bb8b3c75bd157010459b15222c3fd30577042a7060e29d42dabce449c087f2b3 \ - --hash=sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3 \ - --hash=sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00 \ - --hash=sha256:d2952396dc604544ea7476b33fe87faedc24d666fb0c2d5ac971a2b9576ab871 \ - --hash=sha256:d8797406499f28b5ef791f339594b0b5fdedf54e203b5066675c406ba69d705c \ - --hash=sha256:d9e9913f7bd69e093b81da4535ce27af842e7bf371cde42d1ae9e9bd382dc0e9 \ - --hash=sha256:e2806553238cd076f0a55bddab37a532b53580e699ed8e5606d0de1f856b5205 \ - --hash=sha256:ebab974b1687509e5c973b5c4b8b146683e101e102e17a86bd196ecaa4d099fc \ - --hash=sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d \ - --hash=sha256:f7a1fc29803712f80879b0806cb83ab24ce62fc8daf0569f2204a0cfd7f68ed4 - # via - # google-cloud-storage - # google-resumable-media -google-resumable-media==2.7.2 \ - --hash=sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa \ - --hash=sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0 - # via google-cloud-storage -googleapis-common-protos==1.68.0 \ - --hash=sha256:95d38161f4f9af0d9423eed8fb7b64ffd2568c3464eb542ff02c5bfa1953ab3c \ - --hash=sha256:aaf179b2f81df26dfadac95def3b16a95064c76a5f45f07e4c68a21bb371c4ac - # via google-api-core -idna==3.10 \ - --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ - --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 - # via requests -importlib-metadata==8.6.1 \ - --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ - --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 - # via -r requirements.in -jaraco-classes==3.4.0 \ - --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \ - --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 - # via keyring -jaraco-context==6.0.1 \ - --hash=sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3 \ - --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4 - # via - # -r requirements.in - # keyring -jaraco-functools==4.1.0 \ - --hash=sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d \ - --hash=sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649 - # via keyring -jeepney==0.8.0 \ - --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ - --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 - # via - # keyring - # secretstorage -Jinja2==3.1.5 \ - --hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \ - --hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb - # via gcp-releasetool -keyring==25.6.0 \ - --hash=sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66 \ - --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd - # via - # gcp-releasetool - # twine -markdown-it-py==3.0.0 \ - --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ - --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb - # via rich -markupsafe==3.0.2 \ - --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ - --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ - --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ - --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ - --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ - --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ - --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ - --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ - --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ - --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ - --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ - --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ - --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ - --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ - --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ - --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ - --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ - --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ - --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ - --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ - --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ - --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ - --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ - --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ - --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ - --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ - --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ - --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ - --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ - --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ - --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ - --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ - --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ - --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ - --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ - --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ - --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ - --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ - --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ - --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ - --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ - --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ - --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ - --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ - --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ - --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ - --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ - --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ - --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ - --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ - --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ - --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ - --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ - --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ - --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ - --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ - --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ - --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ - --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ - --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ - --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 - # via jinja2 -mdurl==0.1.2 \ - --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ - --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba - # via markdown-it-py -more-itertools==10.6.0 \ - --hash=sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b \ - --hash=sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89 - # via - # jaraco-classes - # jaraco-functools -nh3==0.2.20 \ - --hash=sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec \ - --hash=sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c \ - --hash=sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6 \ - --hash=sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38 \ - --hash=sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace \ - --hash=sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7 \ - --hash=sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b \ - --hash=sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784 \ - --hash=sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0 \ - --hash=sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150 \ - --hash=sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776 \ - --hash=sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330 \ - --hash=sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b \ - --hash=sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d \ - --hash=sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5 \ - --hash=sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5 \ - --hash=sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397 \ - --hash=sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886 \ - --hash=sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b \ - --hash=sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a \ - --hash=sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db \ - --hash=sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2 \ - --hash=sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a \ - --hash=sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208 - # via - # -r requirements.in - # readme-renderer -nox==2024.10.9 \ - --hash=sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab \ - --hash=sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95 - # via -r requirements.in -packaging==24.2 \ - --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ - --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f - # via - # gcp-releasetool - # nox - # twine -pkginfo==1.12.1.2 \ - --hash=sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b \ - --hash=sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343 - # via twine -platformdirs==4.3.6 \ - --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ - --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb - # via virtualenv -proto-plus==1.26.0 \ - --hash=sha256:6e93d5f5ca267b54300880fff156b6a3386b3fa3f43b1da62e680fc0c586ef22 \ - --hash=sha256:bf2dfaa3da281fc3187d12d224c707cb57214fb2c22ba854eb0c105a3fb2d4d7 - # via - # -r requirements.in - # google-api-core -protobuf==5.29.3 \ - --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ - --hash=sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7 \ - --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ - --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ - --hash=sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da \ - --hash=sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252 \ - --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ - --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ - --hash=sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107 \ - --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ - --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 - # via - # gcp-docuploader - # gcp-releasetool - # google-api-core - # googleapis-common-protos - # proto-plus -pyasn1==0.6.1 \ - --hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \ - --hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034 - # via - # pyasn1-modules - # rsa -pyasn1-modules==0.4.1 \ - --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ - --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c - # via google-auth -pycparser==2.22 \ - --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ - --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc - # via cffi -Pygments==2.19.1 \ - --hash=sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f \ - --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c - # via - # readme-renderer - # rich -pyjwt==2.10.1 \ - --hash=sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953 \ - --hash=sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb - # via gcp-releasetool -pyperclip==1.9.0 \ - --hash=sha256:b7de0142ddc81bfc5c7507eea19da920b92252b548b96186caf94a5e2527d310 - # via gcp-releasetool -python-dateutil==2.9.0.post0 \ - --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ - --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 - # via gcp-releasetool -readme-renderer==44.0 \ - --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 \ - --hash=sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1 - # via twine -requests==2.32.3 \ - --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ - --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 - # via - # gcp-releasetool - # google-api-core - # google-cloud-storage - # requests-toolbelt - # twine -requests-toolbelt==1.0.0 \ - --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ - --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 - # via twine -rfc3986==2.0.0 \ - --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ - --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c - # via twine -rich==13.9.4 \ - --hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \ - --hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90 - # via twine -rsa==4.9 \ - --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ - --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 - # via google-auth -secretstorage==3.3.3 \ - --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ - --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 - # via keyring -six==1.17.0 \ - --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \ - --hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81 - # via - # gcp-docuploader - # python-dateutil -tomli==2.2.1 \ - --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ - --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ - --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ - --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ - --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ - --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ - --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ - --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ - --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ - --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ - --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ - --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ - --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ - --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ - --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ - --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ - --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ - --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ - --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ - --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ - --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ - --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ - --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ - --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ - --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ - --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ - --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ - --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ - --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ - --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ - --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ - --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 - # via -r requirements.in -twine==6.0.1 \ - --hash=sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27 \ - --hash=sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218 - # via -r requirements.in -typing-extensions==4.12.2 \ - --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ - --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 - # via -r requirements.in -urllib3==2.3.0 \ - --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ - --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d - # via - # requests - # twine -virtualenv==20.29.2 \ - --hash=sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728 \ - --hash=sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a - # via nox -wheel==0.45.1 \ - --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ - --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 - # via -r requirements.in -zipp==3.21.0 \ - --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ - --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 - # via importlib-metadata From d2fa7af218646ba3e1437b956864a73084a1e8bd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 18:59:49 +0100 Subject: [PATCH 416/582] chore(deps): update dependency googleapis-common-protos to v1.69.1 (#609) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 48751f90e6e1..8c07469a9d8d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -148,9 +148,9 @@ google-cloud-spanner==3.52.0 \ --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ --hash=sha256:d6c30a7ad9742bbe93dc5fc11293f0b339714d1dbf395b541ca9c8942d5ecf3f # via -r requirements.in -googleapis-common-protos[grpc]==1.68.0 \ - --hash=sha256:95d38161f4f9af0d9423eed8fb7b64ffd2568c3464eb542ff02c5bfa1953ab3c \ - --hash=sha256:aaf179b2f81df26dfadac95def3b16a95064c76a5f45f07e4c68a21bb371c4ac +googleapis-common-protos[grpc]==1.69.1 \ + --hash=sha256:4077f27a6900d5946ee5a369fab9c8ded4c0ef1c6e880458ea2f70c14f7b70d5 \ + --hash=sha256:e20d2d8dda87da6fe7340afbbdf4f0bcb4c8fae7e6cadf55926c31f946b0b9b1 # via # google-api-core # grpc-google-iam-v1 From 46a3b9ce81bdf3af21f7bf3875b07f1b6e63eabe Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 19:01:16 +0100 Subject: [PATCH 417/582] chore(deps): update dependency click to v8.1.8 (#560) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8c07469a9d8d..17107a3bb210 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -116,9 +116,9 @@ charset-normalizer==3.4.1 \ --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 # via requests -click==8.1.7 \ - --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ - --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de +click==8.1.8 \ + --hash=sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2 \ + --hash=sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a # via # -r requirements.in # pip-tools From a39fd55191a3dfca56b34b784ed8cc026f5de9c1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 19:02:48 +0100 Subject: [PATCH 418/582] chore(deps): update dependency grpc-google-iam-v1 to v0.14.1 (#608) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 17107a3bb210..989a32c927c3 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -155,9 +155,9 @@ googleapis-common-protos[grpc]==1.69.1 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -grpc-google-iam-v1==0.14.0 \ - --hash=sha256:c66e07aa642e39bb37950f9e7f491f70dad150ac9801263b42b2814307c2df99 \ - --hash=sha256:fb4a084b30099ba3ab07d61d620a0d4429570b13ff53bd37bac75235f98b7da4 +grpc-google-iam-v1==0.14.1 \ + --hash=sha256:14149f37af0e5779fa8a22a8ae588663269e8a479d9c2e69a5056e589bf8a891 \ + --hash=sha256:b4eca35b2231dd76066ebf1728f3cd30d51034db946827ef63ef138da14eea16 # via google-cloud-spanner grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ From 058b2ae8c7104a8dcde0789374f760004650dbf9 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 19:05:12 +0100 Subject: [PATCH 419/582] chore(deps): update dependency alembic to v1.15.1 (#615) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 989a32c927c3..be0e35b126f6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.14.1 \ - --hash=sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5 \ - --hash=sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213 +alembic==1.15.1 \ + --hash=sha256:197de710da4b3e91cf66a826a5b31b5d59a127ab41bd0fc42863e2902ce2bbbe \ + --hash=sha256:e1a1c738577bca1f27e68728c910cd389b9a92152ff91d902da649c192e30c49 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From cc057fb6d3b178184ed14f4a48d9e1a0ae59852b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 19:10:25 +0100 Subject: [PATCH 420/582] chore(deps): update dependency google-api-core to v2.24.2 (#617) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index be0e35b126f6..695b501b1169 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -128,9 +128,9 @@ Deprecated==1.2.18 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.24.1 \ - --hash=sha256:bc78d608f5a5bf853b80bd70a795f703294de656c096c0968320830a4bc280f1 \ - --hash=sha256:f8b36f5456ab0dd99a1b693a40a31d1e7757beea380ad1b38faaf8941eae9d8a +google-api-core[grpc]==2.24.2 \ + --hash=sha256:810a63ac95f3c441b7c0e43d344e372887f62ce9071ba972eacf32672e072de9 \ + --hash=sha256:81718493daf06d96d6bc76a91c23874dbf2fac0adbbf542831b805ee6e974696 # via # google-cloud-core # google-cloud-spanner From 9dc1807017c1646b84bd04315b47cd2b3f1dbe89 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 10 Mar 2025 19:10:44 +0100 Subject: [PATCH 421/582] chore(deps): update dependency proto-plus to v1.26.1 (#618) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 695b501b1169..564741328c67 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -338,9 +338,9 @@ pip-tools==7.4.1 \ --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \ --hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9 # via -r requirements.in -proto-plus==1.26.0 \ - --hash=sha256:6e93d5f5ca267b54300880fff156b6a3386b3fa3f43b1da62e680fc0c586ef22 \ - --hash=sha256:bf2dfaa3da281fc3187d12d224c707cb57214fb2c22ba854eb0c105a3fb2d4d7 +proto-plus==1.26.1 \ + --hash=sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66 \ + --hash=sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012 # via # google-api-core # google-cloud-spanner From 2a600f2cdaece81906bbd4d43ca4f58ec2b2fc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 17 Mar 2025 08:58:42 +0100 Subject: [PATCH 422/582] feat: support AUTO_INCREMENT and IDENTITY columns (#610) * feat: support AUTO_INCREMENT and IDENTITY columns Adds support for IDENTITY and AUTO_INCREMENT columns to the Spanner dialect. These are used by default for primary key generation. By default, IDENTITY columns using a backing bit-reversed sequence are used for primary key generation. The sequence kind to use can be configured by setting the attribute default_sequence_kind on the Spanner dialect. The use of AUTO_INCREMENT columns instead of IDENTITY can be configured by setting the use_auto_increment attribute on the Spanner dialect. * test: add system test + fix conformance 1.3 test * docs: add sample and update README * chore: minor cleanup --- packages/sqlalchemy-spanner/README.rst | 40 ++-- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 39 +++- .../auto_generated_primary_key_sample.py | 64 ++++++ packages/sqlalchemy-spanner/samples/model.py | 13 +- .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../mockserver_tests/auto_increment_model.py | 28 +++ .../mockserver_tests/test_auto_increment.py | 200 ++++++++++++++++++ .../test/mockserver_tests/test_basics.py | 6 +- .../test/mockserver_tests/test_json.py | 3 +- .../test/mockserver_tests/test_quickstart.py | 6 +- .../test/system/test_basics.py | 26 ++- 11 files changed, 393 insertions(+), 37 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/auto_generated_primary_key_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/auto_increment_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 1ec9dfc90f80..927848dc77a2 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -293,29 +293,23 @@ This, however, may require to manually repeat a long list of operations, execute 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. -Auto-incremented IDs -~~~~~~~~~~~~~~~~~~~~ - -Cloud Spanner doesn't support autoincremented IDs mechanism due to -performance reasons (`see for more -details `__). -We recommend that you use the Python -`uuid `__ module to -generate primary key fields to avoid creating monotonically increasing -keys. - -Though it's not encouraged to do so, in case you *need* the feature, you -can simulate it manually as follows: - -.. code:: python - - with engine.begin() as connection: - top_id = connection.execute( - select([user.c.user_id]).order_by(user.c.user_id.desc()).limit(1) - ).fetchone() - next_id = top_id[0] + 1 if top_id else 1 - - connection.execute(user.insert(), {"user_id": next_id}) +Auto-increment primary keys +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Spanner uses IDENTITY columns for auto-increment primary key values. +IDENTITY columns use a backing bit-reversed sequence to generate unique +values that are safe to use as primary values in Spanner. These values +work the same as standard auto-increment values, except that they are +not monotonically increasing. This prevents hot-spotting for tables that +receive a large number of writes. + +`See this documentation page for more details `__. + +Auto-generated primary keys must be returned by Spanner after each insert +statement using a ``THEN RETURN`` clause. ``THEN RETURN`` clauses are not +supported with `Batch DML `__. +It is therefore recommended to use for example client-side generated UUIDs +as primary key values instead. Query hints ~~~~~~~~~~~ diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 0c8e0c87c5c7..9670327fddec 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -409,11 +409,34 @@ def get_column_specification(self, column, **kwargs): if not column.nullable: colspec += " NOT NULL" + has_identity = ( + hasattr(column, "identity") + and column.identity is not None + and self.dialect.supports_identity_columns + ) default = self.get_column_default_string(column) - if default is not None: - colspec += " DEFAULT (" + default + ")" - if hasattr(column, "computed") and column.computed is not None: + if ( + column.primary_key + and column is column.table._autoincrement_column + and not has_identity + and default is None + ): + if ( + hasattr(self.dialect, "use_auto_increment") + and self.dialect.use_auto_increment + ): + colspec += " AUTO_INCREMENT" + else: + sequence_kind = getattr( + self.dialect, "default_sequence_kind", "BIT_REVERSED_POSITIVE" + ) + colspec += " GENERATED BY DEFAULT AS IDENTITY (%s)" % sequence_kind + elif has_identity: + colspec += " " + self.process(column.identity) + elif default is not None: + colspec += " DEFAULT (" + default + ")" + elif hasattr(column, "computed") and column.computed is not None: colspec += " " + self.process(column.computed) return colspec @@ -526,6 +549,12 @@ def visit_create_index( return text def get_identity_options(self, identity_options): + text = ["bit_reversed_positive"] + if identity_options.start is not None: + text.append("start counter with %d" % identity_options.start) + return " ".join(text) + + def get_sequence_options(self, identity_options): text = ["sequence_kind = 'bit_reversed_positive'"] if identity_options.start is not None: text.append("start_with_counter = %d" % identity_options.start) @@ -534,7 +563,7 @@ def get_identity_options(self, identity_options): def visit_create_sequence(self, create, prefix=None, **kw): """Builds a ``CREATE SEQUENCE`` statement for the sequence.""" text = "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element) - options = self.get_identity_options(create.element) + options = self.get_sequence_options(create.element) if options: text += " OPTIONS (" + options + ")" return text @@ -628,11 +657,13 @@ class SpannerDialect(DefaultDialect): supports_default_values = False supports_sequences = True sequences_optional = False + supports_identity_columns = True supports_native_enum = True supports_native_boolean = True supports_native_decimal = True supports_statement_cache = True + postfetch_lastrowid = False insert_returning = True update_returning = True delete_returning = True diff --git a/packages/sqlalchemy-spanner/samples/auto_generated_primary_key_sample.py b/packages/sqlalchemy-spanner/samples/auto_generated_primary_key_sample.py new file mode 100644 index 000000000000..6c74be6f7d19 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/auto_generated_primary_key_sample.py @@ -0,0 +1,64 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Venue + + +# Shows how to use an IDENTITY column for primary key generation. IDENTITY +# columns use a backing bit-reversed sequence to generate unique values that are +# safe to use for primary keys in Spanner. +# +# IDENTITY columns are used by default by the Spanner SQLAlchemy dialect for +# standard primary key columns. +# +# id: Mapped[int] = mapped_column(primary_key=True) +# +# This leads to the following table definition: +# +# CREATE TABLE ticket_sales ( +# id INT64 NOT NULL GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), +# ... +# ) PRIMARY KEY (id) +def auto_generated_primary_key_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + + # Add a line like the following to use AUTO_INCREMENT instead of IDENTITY + # when creating tables in SQLAlchemy. + # https://cloud.google.com/spanner/docs/primary-key-default-value#serial-auto-increment + + # engine.dialect.use_auto_increment = True + # Base.metadata.create_all(engine) + + with Session(engine) as session: + # Venue automatically generates a primary key value using an IDENTITY + # column. We therefore do not need to specify a primary key value when + # we create an instance of Venue. + venue = Venue(code="CH", name="Concert Hall", active=True) + session.add_all([venue]) + session.commit() + + print("Inserted a venue with ID %d" % venue.id) + + +if __name__ == "__main__": + run_sample(auto_generated_primary_key_sample) diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index 13a4c83d757a..65fc4a41f219 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -31,8 +31,7 @@ ForeignKeyConstraint, Sequence, TextClause, - func, - FetchedValue, + Index, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship @@ -45,6 +44,10 @@ class Base(DeclarativeBase): # This allows inserts to use Batch DML, as the primary key value does not need # to be returned from Spanner using a THEN RETURN clause. # +# The Venue model uses a standard auto-generated integer primary key. This uses +# an IDENTITY column in Spanner. IDENTITY columns use a backing bit-reversed +# sequence to generate unique values that are safe to use for primary keys. +# # The TicketSale model uses a bit-reversed sequence for primary key generation. # This is achieved by creating a bit-reversed sequence and assigning the id # column of the model a server_default value that gets the next value from that @@ -117,7 +120,11 @@ class Track(Base): class Venue(Base): __tablename__ = "venues" - code: Mapped[str] = mapped_column(String(10), primary_key=True) + __table_args__ = (Index("venues_code_unique", "code", unique=True),) + # Venue uses a standard auto-generated primary key. + # This translates to an IDENTITY column in Spanner. + id: Mapped[int] = mapped_column(primary_key=True) + code: Mapped[str] = mapped_column(String(10)) name: Mapped[str] = mapped_column(String(200), nullable=False) description: Mapped[str] = mapped_column(JSON, nullable=True) active: Mapped[bool] = mapped_column(Boolean, nullable=False) diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 35b744dc87be..67c3fae58c1b 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -22,6 +22,11 @@ def hello_world(session): _sample(session) +@nox.session() +def auto_generated_primary_key(session): + _sample(session) + + @nox.session() def bit_reversed_sequence(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/auto_increment_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/auto_increment_model.py new file mode 100644 index 000000000000..eb67ab8996e3 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/auto_increment_model.py @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py new file mode 100644 index 000000000000..6bc5e2c04267 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py @@ -0,0 +1,200 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + CommitRequest, + BeginTransactionRequest, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, + add_update_count, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestAutoIncrement(MockServerTestBase): + def test_create_table(self): + from test.mockserver_tests.auto_increment_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + + def test_create_auto_increment_table(self): + from test.mockserver_tests.auto_increment_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + engine.dialect.use_auto_increment = True + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid INT64 NOT NULL AUTO_INCREMENT, \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + + def test_create_table_with_specific_sequence_kind(self): + from test.mockserver_tests.auto_increment_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + engine.dialect.default_sequence_kind = "non_existing_kind" + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (non_existing_kind), \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + + def test_insert_row(self): + from test.mockserver_tests.auto_increment_model import Singer + + self.add_insert_result( + "INSERT INTO singers (name) VALUES (@a0) THEN RETURN singers.id" + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + singer = Singer(name="Test") + session.add(singer) + # Flush the session to send the insert statement to the database. + session.flush() + eq_(987654321, singer.id) + session.commit() + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) + + def test_insert_row_with_pk_value(self): + from test.mockserver_tests.auto_increment_model import Singer + + # SQLAlchemy should not use a THEN RETURN clause when a value for the + # primary key has been set on the model. + add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + # Manually specify a value for the primary key. + singer = Singer(id=1, name="Test") + session.add(singer) + # Flush the session to send the insert statement to the database. + session.flush() + eq_(1, singer.id) + session.commit() + + def add_insert_result(self, sql): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ) + ] + ) + ) + ) + ), + stats=result_set.ResultSetStats( + dict( + row_count_exact=1, + ) + ), + ) + ) + result.rows.extend([("987654321",)]) + add_result(sql, result) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 29bffa82d799..36aee22c56f4 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -127,7 +127,8 @@ def test_create_table(self): eq_(1, len(requests[0].statements)) eq_( "CREATE TABLE users (\n" - "\tuser_id INT64 NOT NULL, \n" + "\tuser_id INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" "\tuser_name STRING(16) NOT NULL\n" ") PRIMARY KEY (user_id)", requests[0].statements[0], @@ -163,7 +164,8 @@ def test_create_multiple_tables(self): for i in range(2): eq_( f"CREATE TABLE table{i} (\n" - "\tid INT64 NOT NULL, \n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" "\tvalue STRING(16) NOT NULL" "\n) PRIMARY KEY (id)", requests[0].statements[i], diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py index d38eb7043045..6395fe3a3b25 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py @@ -58,7 +58,8 @@ def test_create_table(self): eq_(1, len(requests[0].statements)) eq_( "CREATE TABLE venues (\n" - "\tid INT64 NOT NULL, \n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" "\tname STRING(MAX) NOT NULL, \n" "\tdescription JSON\n" ") PRIMARY KEY (id)", diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py index 0b31f9e2addf..c7db636e2883 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py @@ -53,7 +53,8 @@ def test_create_tables(self): eq_(2, len(requests[0].statements)) eq_( "CREATE TABLE user_account (\n" - "\tid INT64 NOT NULL, \n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" "\tname STRING(30) NOT NULL, \n" "\tfullname STRING(MAX)\n" ") PRIMARY KEY (id)", @@ -61,7 +62,8 @@ def test_create_tables(self): ) eq_( "CREATE TABLE address (\n" - "\tid INT64 NOT NULL, \n" + "\tid INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" "\temail_address STRING(MAX) NOT NULL, \n" "\tuser_id INT64 NOT NULL, \n" "\tFOREIGN KEY(user_id) REFERENCES user_account (id)\n" diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index e3099912f48f..e5411988eda5 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -24,10 +24,11 @@ MetaData, Boolean, BIGINT, + select, ) from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.types import REAL -from sqlalchemy.testing import eq_ +from sqlalchemy.testing import eq_, is_true from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -50,6 +51,12 @@ def define_tables(cls, metadata): numbers.c.prime.desc(), spanner_storing=[numbers.c.alternative_name], ) + Table( + "users", + metadata, + Column("ID", Integer, primary_key=True), + Column("name", String(20)), + ) def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) @@ -69,7 +76,7 @@ def test_reflect(self, connection): engine = connection.engine meta: MetaData = MetaData() meta.reflect(bind=engine) - eq_(1, len(meta.tables)) + eq_(2, len(meta.tables)) table = meta.tables["numbers"] eq_(5, len(table.columns)) eq_("number", table.columns[0].name) @@ -127,6 +134,11 @@ class Number(Base): prime: Mapped[bool] = mapped_column(Boolean) ln: Mapped[float] = mapped_column(REAL) + class User(Base): + __tablename__ = "users" + ID: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(20)) + engine = connection.engine with Session(engine) as session: number = Number( @@ -134,3 +146,13 @@ class Number(Base): ) session.add(number) session.commit() + + with Session(engine) as session: + user = User(name="Test") + session.add(user) + session.commit() + + statement = select(User).filter_by(name="Test") + users = session.scalars(statement).all() + eq_(1, len(users)) + is_true(users[0].ID > 0) From 19583c9387862a725e8733db67354b375658ded0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:00:37 +0100 Subject: [PATCH 423/582] chore(deps): update dependency google-cloud-core to v2.4.3 (#619) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 564741328c67..141b115cc360 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -140,9 +140,9 @@ google-auth==2.38.0 \ # via # google-api-core # google-cloud-core -google-cloud-core==2.4.2 \ - --hash=sha256:7459c3e83de7cb8b9ecfec9babc910efb4314030c56dd798eaad12c426f7d180 \ - --hash=sha256:a4fcb0e2fcfd4bfe963837fad6d10943754fd79c1a50097d68540b6eb3d67f35 +google-cloud-core==2.4.3 \ + --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ + --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner google-cloud-spanner==3.52.0 \ --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ From f0c8560b853ce0971702cee352b900ce1a19cbfd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:03:40 +0100 Subject: [PATCH 424/582] chore(deps): update dependency grpcio to v1.71.0 (#620) --- packages/sqlalchemy-spanner/requirements.txt | 108 +++++++++---------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 141b115cc360..19897e66a878 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -163,62 +163,58 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.70.0 \ - --hash=sha256:0495c86a55a04a874c7627fd33e5beaee771917d92c0e6d9d797628ac40e7655 \ - --hash=sha256:07269ff4940f6fb6710951116a04cd70284da86d0a4368fd5a3b552744511f5a \ - --hash=sha256:0a5c78d5198a1f0aa60006cd6eb1c912b4a1520b6a3968e677dbcba215fabb40 \ - --hash=sha256:0ba0a173f4feacf90ee618fbc1a27956bfd21260cd31ced9bc707ef551ff7dc7 \ - --hash=sha256:0cd430b9215a15c10b0e7d78f51e8a39d6cf2ea819fd635a7214fae600b1da27 \ - --hash=sha256:0de706c0a5bb9d841e353f6343a9defc9fc35ec61d6eb6111802f3aa9fef29e1 \ - --hash=sha256:17325b0be0c068f35770f944124e8839ea3185d6d54862800fc28cc2ffad205a \ - --hash=sha256:2394e3381071045a706ee2eeb6e08962dd87e8999b90ac15c55f56fa5a8c9597 \ - --hash=sha256:27cc75e22c5dba1fbaf5a66c778e36ca9b8ce850bf58a9db887754593080d839 \ - --hash=sha256:2b0d02e4b25a5c1f9b6c7745d4fa06efc9fd6a611af0fb38d3ba956786b95199 \ - --hash=sha256:374d014f29f9dfdb40510b041792e0e2828a1389281eb590df066e1cc2b404e5 \ - --hash=sha256:3b0f01f6ed9994d7a0b27eeddea43ceac1b7e6f3f9d86aeec0f0064b8cf50fdb \ - --hash=sha256:4119fed8abb7ff6c32e3d2255301e59c316c22d31ab812b3fbcbaf3d0d87cc68 \ - --hash=sha256:412faabcc787bbc826f51be261ae5fa996b21263de5368a55dc2cf824dc5090e \ - --hash=sha256:4f1937f47c77392ccd555728f564a49128b6a197a05a5cd527b796d36f3387d0 \ - --hash=sha256:5413549fdf0b14046c545e19cfc4eb1e37e9e1ebba0ca390a8d4e9963cab44d2 \ - --hash=sha256:558c386ecb0148f4f99b1a65160f9d4b790ed3163e8610d11db47838d452512d \ - --hash=sha256:58ad9ba575b39edef71f4798fdb5c7b6d02ad36d47949cd381d4392a5c9cbcd3 \ - --hash=sha256:5ea67c72101d687d44d9c56068328da39c9ccba634cabb336075fae2eab0d04b \ - --hash=sha256:7385b1cb064734005204bc8994eed7dcb801ed6c2eda283f613ad8c6c75cf873 \ - --hash=sha256:7c73c42102e4a5ec76608d9b60227d917cea46dff4d11d372f64cbeb56d259d0 \ - --hash=sha256:8058667a755f97407fca257c844018b80004ae8035565ebc2812cc550110718d \ - --hash=sha256:879a61bf52ff8ccacbedf534665bb5478ec8e86ad483e76fe4f729aaef867cab \ - --hash=sha256:880bfb43b1bb8905701b926274eafce5c70a105bc6b99e25f62e98ad59cb278e \ - --hash=sha256:8d1584a68d5922330025881e63a6c1b54cc8117291d382e4fa69339b6d914c56 \ - --hash=sha256:95469d1977429f45fe7df441f586521361e235982a0b39e33841549143ae2851 \ - --hash=sha256:9e654c4b17d07eab259d392e12b149c3a134ec52b11ecdc6a515b39aceeec898 \ - --hash=sha256:a31d7e3b529c94e930a117b2175b2efd179d96eb3c7a21ccb0289a8ab05b645c \ - --hash=sha256:aa47688a65643afd8b166928a1da6247d3f46a2784d301e48ca1cc394d2ffb40 \ - --hash=sha256:aa573896aeb7d7ce10b1fa425ba263e8dddd83d71530d1322fd3a16f31257b4a \ - --hash=sha256:aba19419aef9b254e15011b230a180e26e0f6864c90406fdbc255f01d83bc83c \ - --hash=sha256:ac073fe1c4cd856ebcf49e9ed6240f4f84d7a4e6ee95baa5d66ea05d3dd0df7f \ - --hash=sha256:b3c76701428d2df01964bc6479422f20e62fcbc0a37d82ebd58050b86926ef8c \ - --hash=sha256:b745d2c41b27650095e81dea7091668c040457483c9bdb5d0d9de8f8eb25e59f \ - --hash=sha256:bb491125103c800ec209d84c9b51f1c60ea456038e4734688004f377cfacc113 \ - --hash=sha256:c1af8e15b0f0fe0eac75195992a63df17579553b0c4af9f8362cc7cc99ccddf4 \ - --hash=sha256:c78b339869f4dbf89881e0b6fbf376313e4f845a42840a7bdf42ee6caed4b11f \ - --hash=sha256:cb5277db254ab7586769e490b7b22f4ddab3876c490da0a1a9d7c695ccf0bf77 \ - --hash=sha256:cbce24409beaee911c574a3d75d12ffb8c3e3dd1b813321b1d7a96bbcac46bf4 \ - --hash=sha256:cd24d2d9d380fbbee7a5ac86afe9787813f285e684b0271599f95a51bce33528 \ - --hash=sha256:ce7df14b2dcd1102a2ec32f621cc9fab6695effef516efbc6b063ad749867295 \ - --hash=sha256:d24035d49e026353eb042bf7b058fb831db3e06d52bee75c5f2f3ab453e71aca \ - --hash=sha256:d405b005018fd516c9ac529f4b4122342f60ec1cee181788249372524e6db429 \ - --hash=sha256:d63764963412e22f0491d0d32833d71087288f4e24cbcddbae82476bfa1d81fd \ - --hash=sha256:dbe41ad140df911e796d4463168e33ef80a24f5d21ef4d1e310553fcd2c4a386 \ - --hash=sha256:dfa089a734f24ee5f6880c83d043e4f46bf812fcea5181dcb3a572db1e79e01c \ - --hash=sha256:e27585831aa6b57b9250abaf147003e126cd3a6c6ca0c531a01996f31709bed1 \ - --hash=sha256:e7831a0fc1beeeb7759f737f5acd9fdcda520e955049512d68fda03d91186eea \ - --hash=sha256:ed9718f17fbdb472e33b869c77a16d0b55e166b100ec57b016dc7de9c8d236bf \ - --hash=sha256:ef4c14508299b1406c32bdbb9fb7b47612ab979b04cf2b27686ea31882387cff \ - --hash=sha256:f19375f0300b96c0117aca118d400e76fede6db6e91f3c34b7b035822e06c35f \ - --hash=sha256:f2af68a6f5c8f78d56c145161544ad0febbd7479524a59c16b3e25053f39c87f \ - --hash=sha256:f32090238b720eb585248654db8e3afc87b48d26ac423c8dde8334a232ff53c9 \ - --hash=sha256:fe9dbd916df3b60e865258a8c72ac98f3ac9e2a9542dcb72b7a34d236242a5ce \ - --hash=sha256:ff4a8112a79464919bb21c18e956c54add43ec9a4850e3949da54f61c241a4a6 +grpcio==1.71.0 \ + --hash=sha256:0ab8b2864396663a5b0b0d6d79495657ae85fa37dcb6498a2669d067c65c11ea \ + --hash=sha256:0fa05ee31a20456b13ae49ad2e5d585265f71dd19fbd9ef983c28f926d45d0a7 \ + --hash=sha256:0ff35c8d807c1c7531d3002be03221ff9ae15712b53ab46e2a0b4bb271f38537 \ + --hash=sha256:1be857615e26a86d7363e8a163fade914595c81fec962b3d514a4b1e8760467b \ + --hash=sha256:20e8f653abd5ec606be69540f57289274c9ca503ed38388481e98fa396ed0b41 \ + --hash=sha256:22c3bc8d488c039a199f7a003a38cb7635db6656fa96437a8accde8322ce2366 \ + --hash=sha256:24e867651fc67717b6f896d5f0cac0ec863a8b5fb7d6441c2ab428f52c651c6b \ + --hash=sha256:2b85f7820475ad3edec209d3d89a7909ada16caab05d3f2e08a7e8ae3200a55c \ + --hash=sha256:39983a9245d37394fd59de71e88c4b295eb510a3555e0a847d9965088cdbd033 \ + --hash=sha256:3d081e859fb1ebe176de33fc3adb26c7d46b8812f906042705346b314bde32c3 \ + --hash=sha256:469f42a0b410883185eab4689060a20488a1a0a00f8bbb3cbc1061197b4c5a79 \ + --hash=sha256:47be9584729534660416f6d2a3108aaeac1122f6b5bdbf9fd823e11fe6fbaa29 \ + --hash=sha256:4be74ddeeb92cc87190e0e376dbc8fc7736dbb6d3d454f2fa1f5be1dee26b9d7 \ + --hash=sha256:4dd0dfbe4d5eb1fcfec9490ca13f82b089a309dc3678e2edabc144051270a66e \ + --hash=sha256:5b08d03ace7aca7b2fadd4baf291139b4a5f058805a8327bfe9aece7253b6d67 \ + --hash=sha256:63e41b91032f298b3e973b3fa4093cbbc620c875e2da7b93e249d4728b54559a \ + --hash=sha256:652350609332de6dac4ece254e5d7e1ff834e203d6afb769601f286886f6f3a8 \ + --hash=sha256:693bc706c031aeb848849b9d1c6b63ae6bcc64057984bb91a542332b75aa4c3d \ + --hash=sha256:74258dce215cb1995083daa17b379a1a5a87d275387b7ffe137f1d5131e2cfbb \ + --hash=sha256:789d5e2a3a15419374b7b45cd680b1e83bbc1e52b9086e49308e2c0b5bbae6e3 \ + --hash=sha256:7c9c80ac6091c916db81131d50926a93ab162a7e97e4428ffc186b6e80d6dda4 \ + --hash=sha256:7d6ac9481d9d0d129224f6d5934d5832c4b1cddb96b59e7eba8416868909786a \ + --hash=sha256:85da336e3649a3d2171e82f696b5cad2c6231fdd5bad52616476235681bee5b3 \ + --hash=sha256:8700a2a57771cc43ea295296330daaddc0d93c088f0a35cc969292b6db959bf3 \ + --hash=sha256:8997d6785e93308f277884ee6899ba63baafa0dfb4729748200fcc537858a509 \ + --hash=sha256:9182e0063112e55e74ee7584769ec5a0b4f18252c35787f48738627e23a62b97 \ + --hash=sha256:9b91879d6da1605811ebc60d21ab6a7e4bae6c35f6b63a061d61eb818c8168f6 \ + --hash=sha256:a2242d6950dc892afdf9e951ed7ff89473aaf744b7d5727ad56bdaace363722b \ + --hash=sha256:a371e6b6a5379d3692cc4ea1cb92754d2a47bdddeee755d3203d1f84ae08e03e \ + --hash=sha256:a76d39b5fafd79ed604c4be0a869ec3581a172a707e2a8d7a4858cb05a5a7637 \ + --hash=sha256:ad9f30838550695b5eb302add33f21f7301b882937460dd24f24b3cc5a95067a \ + --hash=sha256:b2266862c5ad664a380fbbcdbdb8289d71464c42a8c29053820ee78ba0119e5d \ + --hash=sha256:b78a99cd1ece4be92ab7c07765a0b038194ded2e0a26fd654591ee136088d8d7 \ + --hash=sha256:c200cb6f2393468142eb50ab19613229dcc7829b5ccee8b658a36005f6669fdd \ + --hash=sha256:c30f393f9d5ff00a71bb56de4aa75b8fe91b161aeb61d39528db6b768d7eac69 \ + --hash=sha256:c6a0a28450c16809f94e0b5bfe52cabff63e7e4b97b44123ebf77f448534d07d \ + --hash=sha256:cebc1b34ba40a312ab480ccdb396ff3c529377a2fce72c45a741f7215bfe8379 \ + --hash=sha256:d2c170247315f2d7e5798a22358e982ad6eeb68fa20cf7a820bb74c11f0736e7 \ + --hash=sha256:d35a95f05a8a2cbe8e02be137740138b3b2ea5f80bd004444e4f9a1ffc511e32 \ + --hash=sha256:d5170929109450a2c031cfe87d6716f2fae39695ad5335d9106ae88cc32dc84c \ + --hash=sha256:d6aa986318c36508dc1d5001a3ff169a15b99b9f96ef5e98e13522c506b37eef \ + --hash=sha256:d6de81c9c00c8a23047136b11794b3584cdc1460ed7cbc10eada50614baa1444 \ + --hash=sha256:dc1a1231ed23caac1de9f943d031f1bc38d0f69d2a3b243ea0d664fc1fbd7fec \ + --hash=sha256:e6beeea5566092c5e3c4896c6d1d307fb46b1d4bdf3e70c8340b190a69198594 \ + --hash=sha256:e6d8de076528f7c43a2f576bc311799f89d795aa6c9b637377cc2b1616473804 \ + --hash=sha256:e6f83a583ed0a5b08c5bc7a3fe860bb3c2eac1f03f1f63e0bc2091325605d2b7 \ + --hash=sha256:f250ff44843d9a0615e350c77f890082102a0318d66a99540f54769c8766ab73 \ + --hash=sha256:f71574afdf944e6652203cd1badcda195b2a27d9c83e6d88dc1ce3cfb73b31a5 \ + --hash=sha256:f903017db76bf9cc2b2d8bdd37bf04b505bbccad6be8a81e1542206875d0e9db \ + --hash=sha256:f9a412f55bb6e8f3bb000e020dbc1e709627dcb3a56f6431fa7076b4c1aab0db \ + --hash=sha256:f9c30c464cb2ddfbc2ddf9400287701270fdc0f14be5f08a1e3939f1e749b455 # via # google-api-core # googleapis-common-protos From af789c51b656473a4e600b4047041bfb2b16dc1b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:06:31 +0100 Subject: [PATCH 425/582] chore(deps): update dependency grpcio-status to v1.71.0 (#621) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 19897e66a878..5d973c6d86b9 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -221,9 +221,9 @@ grpcio==1.71.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.70.0 \ - --hash=sha256:0e7b42816512433b18b9d764285ff029bde059e9d41f8fe10a60631bd8348101 \ - --hash=sha256:fc5a2ae2b9b1c1969cc49f3262676e6854aa2398ec69cb5bd6c47cd501904a85 +grpcio-status==1.71.0 \ + --hash=sha256:11405fed67b68f406b3f3c7c5ae5104a79d2d309666d10d61b152e91d28fb968 \ + --hash=sha256:843934ef8c09e3e858952887467f8256aac3910c55f077a359a65b2b3cde3e68 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 68bc4d9714768260c195c20eb0504006deaeae5e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:08:13 +0100 Subject: [PATCH 426/582] chore(deps): update dependency sqlalchemy to v2.0.39 (#622) --- packages/sqlalchemy-spanner/requirements.txt | 101 ++++++++----------- 1 file changed, 43 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 5d973c6d86b9..fa717b3494ba 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -387,64 +387,49 @@ rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 # via google-auth -SQLAlchemy==2.0.38 \ - --hash=sha256:0398361acebb42975deb747a824b5188817d32b5c8f8aba767d51ad0cc7bb08d \ - --hash=sha256:0561832b04c6071bac3aad45b0d3bb6d2c4f46a8409f0a7a9c9fa6673b41bc03 \ - --hash=sha256:07258341402a718f166618470cde0c34e4cec85a39767dce4e24f61ba5e667ea \ - --hash=sha256:0a826f21848632add58bef4f755a33d45105d25656a0c849f2dc2df1c71f6f50 \ - --hash=sha256:1052723e6cd95312f6a6eff9a279fd41bbae67633415373fdac3c430eca3425d \ - --hash=sha256:12d5b06a1f3aeccf295a5843c86835033797fea292c60e72b07bcb5d820e6dd3 \ - --hash=sha256:12f5c9ed53334c3ce719155424dc5407aaa4f6cadeb09c5b627e06abb93933a1 \ - --hash=sha256:2a0ef3f98175d77180ffdc623d38e9f1736e8d86b6ba70bff182a7e68bed7727 \ - --hash=sha256:2f2951dc4b4f990a4b394d6b382accb33141d4d3bd3ef4e2b27287135d6bdd68 \ - --hash=sha256:3868acb639c136d98107c9096303d2d8e5da2880f7706f9f8c06a7f961961149 \ - --hash=sha256:386b7d136919bb66ced64d2228b92d66140de5fefb3c7df6bd79069a269a7b06 \ - --hash=sha256:3d3043375dd5bbcb2282894cbb12e6c559654c67b5fffb462fda815a55bf93f7 \ - --hash=sha256:3e35d5565b35b66905b79ca4ae85840a8d40d31e0b3e2990f2e7692071b179ca \ - --hash=sha256:402c2316d95ed90d3d3c25ad0390afa52f4d2c56b348f212aa9c8d072a40eee5 \ - --hash=sha256:40310db77a55512a18827488e592965d3dec6a3f1e3d8af3f8243134029daca3 \ - --hash=sha256:40e9cdbd18c1f84631312b64993f7d755d85a3930252f6276a77432a2b25a2f3 \ - --hash=sha256:49aa2cdd1e88adb1617c672a09bf4ebf2f05c9448c6dbeba096a3aeeb9d4d443 \ - --hash=sha256:57dd41ba32430cbcc812041d4de8d2ca4651aeefad2626921ae2a23deb8cd6ff \ - --hash=sha256:5dba1cdb8f319084f5b00d41207b2079822aa8d6a4667c0f369fce85e34b0c86 \ - --hash=sha256:5e1d9e429028ce04f187a9f522818386c8b076723cdbe9345708384f49ebcec6 \ - --hash=sha256:63178c675d4c80def39f1febd625a6333f44c0ba269edd8a468b156394b27753 \ - --hash=sha256:6493bc0eacdbb2c0f0d260d8988e943fee06089cd239bd7f3d0c45d1657a70e2 \ - --hash=sha256:64aa8934200e222f72fcfd82ee71c0130a9c07d5725af6fe6e919017d095b297 \ - --hash=sha256:665255e7aae5f38237b3a6eae49d2358d83a59f39ac21036413fab5d1e810578 \ - --hash=sha256:6db316d6e340f862ec059dc12e395d71f39746a20503b124edc255973977b728 \ - --hash=sha256:70065dfabf023b155a9c2a18f573e47e6ca709b9e8619b2e04c54d5bcf193178 \ - --hash=sha256:8455aa60da49cb112df62b4721bd8ad3654a3a02b9452c783e651637a1f21fa2 \ - --hash=sha256:8b0ac78898c50e2574e9f938d2e5caa8fe187d7a5b69b65faa1ea4648925b096 \ - --hash=sha256:8bf312ed8ac096d674c6aa9131b249093c1b37c35db6a967daa4c84746bc1bc9 \ - --hash=sha256:92f99f2623ff16bd4aaf786ccde759c1f676d39c7bf2855eb0b540e1ac4530c8 \ - --hash=sha256:9c8bcad7fc12f0cc5896d8e10fdf703c45bd487294a986903fe032c72201596b \ - --hash=sha256:9cd136184dd5f58892f24001cdce986f5d7e96059d004118d5410671579834a4 \ - --hash=sha256:9eb4fa13c8c7a2404b6a8e3772c17a55b1ba18bc711e25e4d6c0c9f5f541b02a \ - --hash=sha256:a2bc4e49e8329f3283d99840c136ff2cd1a29e49b5624a46a290f04dff48e079 \ - --hash=sha256:a5645cd45f56895cfe3ca3459aed9ff2d3f9aaa29ff7edf557fa7a23515a3725 \ - --hash=sha256:a9afbc3909d0274d6ac8ec891e30210563b2c8bdd52ebbda14146354e7a69373 \ - --hash=sha256:aa498d1392216fae47eaf10c593e06c34476ced9549657fca713d0d1ba5f7248 \ - --hash=sha256:afd776cf1ebfc7f9aa42a09cf19feadb40a26366802d86c1fba080d8e5e74bdd \ - --hash=sha256:b335a7c958bc945e10c522c069cd6e5804f4ff20f9a744dd38e748eb602cbbda \ - --hash=sha256:b3c4817dff8cef5697f5afe5fec6bc1783994d55a68391be24cb7d80d2dbc3a6 \ - --hash=sha256:b79ee64d01d05a5476d5cceb3c27b5535e6bb84ee0f872ba60d9a8cd4d0e6579 \ - --hash=sha256:b87a90f14c68c925817423b0424381f0e16d80fc9a1a1046ef202ab25b19a444 \ - --hash=sha256:bf89e0e4a30714b357f5d46b6f20e0099d38b30d45fa68ea48589faf5f12f62d \ - --hash=sha256:c058b84c3b24812c859300f3b5abf300daa34df20d4d4f42e9652a4d1c48c8a4 \ - --hash=sha256:c09a6ea87658695e527104cf857c70f79f14e9484605e205217aae0ec27b45fc \ - --hash=sha256:c57b8e0841f3fce7b703530ed70c7c36269c6d180ea2e02e36b34cb7288c50c7 \ - --hash=sha256:c9cea5b756173bb86e2235f2f871b406a9b9d722417ae31e5391ccaef5348f2c \ - --hash=sha256:cb39ed598aaf102251483f3e4675c5dd6b289c8142210ef76ba24aae0a8f8aba \ - --hash=sha256:e036549ad14f2b414c725349cce0772ea34a7ab008e9cd67f9084e4f371d1f32 \ - --hash=sha256:e185ea07a99ce8b8edfc788c586c538c4b1351007e614ceb708fd01b095ef33e \ - --hash=sha256:e5a4d82bdb4bf1ac1285a68eab02d253ab73355d9f0fe725a97e1e0fa689decb \ - --hash=sha256:eae27ad7580529a427cfdd52c87abb2dfb15ce2b7a3e0fc29fbb63e2ed6f8120 \ - --hash=sha256:ecef029b69843b82048c5b347d8e6049356aa24ed644006c9a9d7098c3bd3bfd \ - --hash=sha256:ee3bee874cb1fadee2ff2b79fc9fc808aa638670f28b2145074538d4a6a5028e \ - --hash=sha256:f0d3de936b192980209d7b5149e3c98977c3810d401482d05fb6d668d53c1c63 \ - --hash=sha256:f53c0d6a859b2db58332e0e6a921582a02c1677cc93d4cbb36fdf49709b327b2 \ - --hash=sha256:f9d57f1b3061b3e21476b0ad5f0397b112b94ace21d1f439f2db472e568178ae +SQLAlchemy==2.0.39 \ + --hash=sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c \ + --hash=sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c \ + --hash=sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c \ + --hash=sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d \ + --hash=sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7 \ + --hash=sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7 \ + --hash=sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338 \ + --hash=sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70 \ + --hash=sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a \ + --hash=sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e \ + --hash=sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530 \ + --hash=sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249 \ + --hash=sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02 \ + --hash=sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde \ + --hash=sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538 \ + --hash=sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0 \ + --hash=sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e \ + --hash=sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47 \ + --hash=sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22 \ + --hash=sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875 \ + --hash=sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787 \ + --hash=sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b \ + --hash=sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8 \ + --hash=sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42 \ + --hash=sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f \ + --hash=sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716 \ + --hash=sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd \ + --hash=sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92 \ + --hash=sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109 \ + --hash=sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304 \ + --hash=sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c \ + --hash=sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4 \ + --hash=sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4 \ + --hash=sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a \ + --hash=sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f \ + --hash=sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9 \ + --hash=sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e \ + --hash=sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b \ + --hash=sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4 \ + --hash=sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41 \ + --hash=sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5 \ + --hash=sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87 # via # -r requirements.in # alembic From f4219b9513a702c8d227b5995d6127293f03cbc8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:13:29 +0100 Subject: [PATCH 427/582] chore(deps): update opentelemetry-python monorepo to v1.31.0 (#623) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index fa717b3494ba..619ded5f59b9 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -300,9 +300,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.30.0 \ - --hash=sha256:375893400c1435bf623f7dfb3bcd44825fe6b56c34d0667c542ea8257b1a1240 \ - --hash=sha256:d5f5284890d73fdf47f843dda3210edf37a38d66f44f2b5aedc1e89ed455dc09 +opentelemetry-api==1.31.0 \ + --hash=sha256:145b72c6c16977c005c568ec32f4946054ab793d8474a17fd884b0397582c5f2 \ + --hash=sha256:d8da59e83e8e3993b4726e4c1023cd46f57c4d5a73142e239247e7d814309de1 # via # -r requirements.in # opentelemetry-instrumentation @@ -312,9 +312,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.30.0 \ - --hash=sha256:14fe7afc090caad881addb6926cec967129bd9260c4d33ae6a217359f6b61091 \ - --hash=sha256:c9287a9e4a7614b9946e933a67168450b9ab35f08797eb9bc77d998fa480fa18 +opentelemetry-sdk==1.31.0 \ + --hash=sha256:452d7d5b3c1db2e5e4cb64abede0ddd20690cb244a559c73a59652fdf6726070 \ + --hash=sha256:97c9a03865e69723725fb64fe04343a488c3e61e684eb804bd7d6da2215dfc60 # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 335a0500ec918a037492484bd39771acb88ab11e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 17 Mar 2025 09:16:06 +0100 Subject: [PATCH 428/582] chore(deps): update dependency google-cloud-spanner to v3.53.0 (#624) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 619ded5f59b9..c183046cf0c7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.52.0 \ - --hash=sha256:b18cc9b8d97866c80297c878175fa86af9244cd0c13455970192f8318d646e8a \ - --hash=sha256:d6c30a7ad9742bbe93dc5fc11293f0b339714d1dbf395b541ca9c8942d5ecf3f +google-cloud-spanner==3.53.0 \ + --hash=sha256:0c7be3134b74928cf928d1f73b58c722fc2014346de1240a0cc8ffdd3222f606 \ + --hash=sha256:be863394521b44df3c5a118c00c4b7c978d4437adb49e359e39b3d76362a7e60 # via -r requirements.in googleapis-common-protos[grpc]==1.69.1 \ --hash=sha256:4077f27a6900d5946ee5a369fab9c8ded4c0ef1c6e880458ea2f70c14f7b70d5 \ From 1242f851e35dd27471e05dfaee31ac2d5d06c842 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 09:16:45 +0100 Subject: [PATCH 429/582] chore(main): release 1.10.0 (#625) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 716e2b0aef55..3fa83c271a8d 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.10.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.9.0...v1.10.0) (2025-03-17) + + +### Features + +* Support AUTO_INCREMENT and IDENTITY columns ([#610](https://github.com/googleapis/python-spanner-sqlalchemy/issues/610)) ([f67ebe8](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f67ebe888ef4da8d94ff6d1e1d7f4cd5de37616c)) + ## [1.9.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.8.0...v1.9.0) (2025-02-21) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 7d6b472bcf15..c11faefc8070 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.9.0" +__version__ = "1.10.0" From 6bfb66a862812b5a310d475ec35fab38026cdb33 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 19:56:46 +0200 Subject: [PATCH 430/582] chore(deps): update dependency googleapis-common-protos to v1.70.0 (#626) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c183046cf0c7..69b2ec004ef7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -148,9 +148,9 @@ google-cloud-spanner==3.53.0 \ --hash=sha256:0c7be3134b74928cf928d1f73b58c722fc2014346de1240a0cc8ffdd3222f606 \ --hash=sha256:be863394521b44df3c5a118c00c4b7c978d4437adb49e359e39b3d76362a7e60 # via -r requirements.in -googleapis-common-protos[grpc]==1.69.1 \ - --hash=sha256:4077f27a6900d5946ee5a369fab9c8ded4c0ef1c6e880458ea2f70c14f7b70d5 \ - --hash=sha256:e20d2d8dda87da6fe7340afbbdf4f0bcb4c8fae7e6cadf55926c31f946b0b9b1 +googleapis-common-protos[grpc]==1.70.0 \ + --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ + --hash=sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8 # via # google-api-core # grpc-google-iam-v1 From 4d46dcc25f339195c47f1752738dcf127960b8f1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 19:57:07 +0200 Subject: [PATCH 431/582] chore(deps): update opentelemetry-python monorepo to v1.32.1 (#629) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 69b2ec004ef7..7826cdd30754 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -300,9 +300,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.31.0 \ - --hash=sha256:145b72c6c16977c005c568ec32f4946054ab793d8474a17fd884b0397582c5f2 \ - --hash=sha256:d8da59e83e8e3993b4726e4c1023cd46f57c4d5a73142e239247e7d814309de1 +opentelemetry-api==1.32.1 \ + --hash=sha256:a5be71591694a4d9195caf6776b055aa702e964d961051a0715d05f8632c32fb \ + --hash=sha256:bbd19f14ab9f15f0e85e43e6a958aa4cb1f36870ee62b7fd205783a112012724 # via # -r requirements.in # opentelemetry-instrumentation @@ -312,9 +312,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.31.0 \ - --hash=sha256:452d7d5b3c1db2e5e4cb64abede0ddd20690cb244a559c73a59652fdf6726070 \ - --hash=sha256:97c9a03865e69723725fb64fe04343a488c3e61e684eb804bd7d6da2215dfc60 +opentelemetry-sdk==1.32.1 \ + --hash=sha256:8ef373d490961848f525255a42b193430a0637e064dd132fd2a014d94792a092 \ + --hash=sha256:bba37b70a08038613247bc42beee5a81b0ddca422c7d7f1b097b32bf1c7e2f17 # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 8bba697c09c11ca8235db25bbc4cc2765151bdff Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 19:57:30 +0200 Subject: [PATCH 432/582] chore(deps): update dependency typing-extensions to v4.13.2 (#631) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7826cdd30754..54c8ce37c654 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -471,9 +471,9 @@ tomli==2.2.1 \ --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in -typing-extensions==4.12.2 \ - --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ - --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 +typing-extensions==4.13.2 \ + --hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c \ + --hash=sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef # via # alembic # opentelemetry-sdk From be7316e8d121e8667eee32810c648177f33ba56f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:02:29 +0200 Subject: [PATCH 433/582] chore(deps): update dependency pyparsing to v3.2.3 (#630) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 54c8ce37c654..84d7a4e70e10 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -369,9 +369,9 @@ pyasn1-modules==0.4.1 \ --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c # via google-auth -pyparsing==3.2.1 \ - --hash=sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 \ - --hash=sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a +pyparsing==3.2.3 \ + --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \ + --hash=sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be # via -r requirements.in pyproject-hooks==1.2.0 \ --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ From 1b57974476afdf75c16cc0278989efed4fe53169 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:02:51 +0200 Subject: [PATCH 434/582] chore(deps): update dependency grpc-google-iam-v1 to v0.14.2 (#627) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 84d7a4e70e10..aeb74bdbb089 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -155,9 +155,9 @@ googleapis-common-protos[grpc]==1.70.0 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -grpc-google-iam-v1==0.14.1 \ - --hash=sha256:14149f37af0e5779fa8a22a8ae588663269e8a479d9c2e69a5056e589bf8a891 \ - --hash=sha256:b4eca35b2231dd76066ebf1728f3cd30d51034db946827ef63ef138da14eea16 +grpc-google-iam-v1==0.14.2 \ + --hash=sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351 \ + --hash=sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20 # via google-cloud-spanner grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ From 646df1e0186b029bad95a03df3902a8cd1e651c4 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:06:18 +0200 Subject: [PATCH 435/582] chore(deps): update dependency sqlalchemy to v2.0.40 (#632) --- packages/sqlalchemy-spanner/requirements.txt | 101 +++++++++++-------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index aeb74bdbb089..c01338c28a8b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -387,49 +387,64 @@ rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 # via google-auth -SQLAlchemy==2.0.39 \ - --hash=sha256:018ee97c558b499b58935c5a152aeabf6d36b3d55d91656abeb6d93d663c0c4c \ - --hash=sha256:01da15490c9df352fbc29859d3c7ba9cd1377791faeeb47c100832004c99472c \ - --hash=sha256:04545042969833cb92e13b0a3019549d284fd2423f318b6ba10e7aa687690a3c \ - --hash=sha256:08cf721bbd4391a0e765fe0fe8816e81d9f43cece54fdb5ac465c56efafecb3d \ - --hash=sha256:23c5aa33c01bd898f879db158537d7e7568b503b15aad60ea0c8da8109adf3e7 \ - --hash=sha256:2d7332868ce891eda48896131991f7f2be572d65b41a4050957242f8e935d5d7 \ - --hash=sha256:2ed107331d188a286611cea9022de0afc437dd2d3c168e368169f27aa0f61338 \ - --hash=sha256:34d5c49f18778a3665d707e6286545a30339ad545950773d43977e504815fa70 \ - --hash=sha256:35e72518615aa5384ef4fae828e3af1b43102458b74a8c481f69af8abf7e802a \ - --hash=sha256:3eb14ba1a9d07c88669b7faf8f589be67871d6409305e73e036321d89f1d904e \ - --hash=sha256:412c6c126369ddae171c13987b38df5122cb92015cba6f9ee1193b867f3f1530 \ - --hash=sha256:4600c7a659d381146e1160235918826c50c80994e07c5b26946a3e7ec6c99249 \ - --hash=sha256:463ecfb907b256e94bfe7bcb31a6d8c7bc96eca7cbe39803e448a58bb9fcad02 \ - --hash=sha256:4a06e6c8e31c98ddc770734c63903e39f1947c9e3e5e4bef515c5491b7737dde \ - --hash=sha256:4b2de1523d46e7016afc7e42db239bd41f2163316935de7c84d0e19af7e69538 \ - --hash=sha256:4dabd775fd66cf17f31f8625fc0e4cfc5765f7982f94dc09b9e5868182cb71c0 \ - --hash=sha256:52607d0ebea43cf214e2ee84a6a76bc774176f97c5a774ce33277514875a718e \ - --hash=sha256:5493a8120d6fc185f60e7254fc056a6742f1db68c0f849cfc9ab46163c21df47 \ - --hash=sha256:5d2d1fe548def3267b4c70a8568f108d1fed7cbbeccb9cc166e05af2abc25c22 \ - --hash=sha256:5dfbc543578058c340360f851ddcecd7a1e26b0d9b5b69259b526da9edfa8875 \ - --hash=sha256:67de057fbcb04a066171bd9ee6bcb58738d89378ee3cabff0bffbf343ae1c787 \ - --hash=sha256:6827f8c1b2f13f1420545bd6d5b3f9e0b85fe750388425be53d23c760dcf176b \ - --hash=sha256:6b35e07f1d57b79b86a7de8ecdcefb78485dab9851b9638c2c793c50203b2ae8 \ - --hash=sha256:7399d45b62d755e9ebba94eb89437f80512c08edde8c63716552a3aade61eb42 \ - --hash=sha256:78f1b79132a69fe8bd6b5d91ef433c8eb40688ba782b26f8c9f3d2d9ca23626f \ - --hash=sha256:79f4f502125a41b1b3b34449e747a6abfd52a709d539ea7769101696bdca6716 \ - --hash=sha256:7a8517b6d4005facdbd7eb4e8cf54797dbca100a7df459fdaff4c5123265c1cd \ - --hash=sha256:7bd5c5ee1448b6408734eaa29c0d820d061ae18cb17232ce37848376dcfa3e92 \ - --hash=sha256:7f5243357e6da9a90c56282f64b50d29cba2ee1f745381174caacc50d501b109 \ - --hash=sha256:871f55e478b5a648c08dd24af44345406d0e636ffe021d64c9b57a4a11518304 \ - --hash=sha256:87a1ce1f5e5dc4b6f4e0aac34e7bb535cb23bd4f5d9c799ed1633b65c2bcad8c \ - --hash=sha256:8a10ca7f8a1ea0fd5630f02feb055b0f5cdfcd07bb3715fc1b6f8cb72bf114e4 \ - --hash=sha256:995c2bacdddcb640c2ca558e6760383dcdd68830160af92b5c6e6928ffd259b4 \ - --hash=sha256:9f03143f8f851dd8de6b0c10784363712058f38209e926723c80654c1b40327a \ - --hash=sha256:a1c6b0a5e3e326a466d809b651c63f278b1256146a377a528b6938a279da334f \ - --hash=sha256:a28f9c238f1e143ff42ab3ba27990dfb964e5d413c0eb001b88794c5c4a528a9 \ - --hash=sha256:bf555f3e25ac3a70c67807b2949bfe15f377a40df84b71ab2c58d8593a1e036e \ - --hash=sha256:c457a38351fb6234781d054260c60e531047e4d07beca1889b558ff73dc2014b \ - --hash=sha256:c4c433f78c2908ae352848f56589c02b982d0e741b7905228fad628999799de4 \ - --hash=sha256:d9f119e7736967c0ea03aff91ac7d04555ee038caf89bb855d93bbd04ae85b41 \ - --hash=sha256:f2bcb085faffcacf9319b1b1445a7e1cfdc6fb46c03f2dce7bc2d9a4b3c1cdc5 \ - --hash=sha256:fe193d3ae297c423e0e567e240b4324d6b6c280a048e64c77a3ea6886cc2aa87 +SQLAlchemy==2.0.40 \ + --hash=sha256:00a494ea6f42a44c326477b5bee4e0fc75f6a80c01570a32b57e89cf0fbef85a \ + --hash=sha256:0bb933a650323e476a2e4fbef8997a10d0003d4da996aad3fd7873e962fdde4d \ + --hash=sha256:110179728e442dae85dd39591beb74072ae4ad55a44eda2acc6ec98ead80d5f2 \ + --hash=sha256:15d08d5ef1b779af6a0909b97be6c1fd4298057504eb6461be88bd1696cb438e \ + --hash=sha256:16d325ea898f74b26ffcd1cf8c593b0beed8714f0317df2bed0d8d1de05a8f26 \ + --hash=sha256:1abb387710283fc5983d8a1209d9696a4eae9db8d7ac94b402981fe2fe2e39ad \ + --hash=sha256:1ffdf9c91428e59744f8e6f98190516f8e1d05eec90e936eb08b257332c5e870 \ + --hash=sha256:2be94d75ee06548d2fc591a3513422b873490efb124048f50556369a834853b0 \ + --hash=sha256:2cbafc8d39ff1abdfdda96435f38fab141892dc759a2165947d1a8fffa7ef596 \ + --hash=sha256:2ee5f9999a5b0e9689bed96e60ee53c3384f1a05c2dd8068cc2e8361b0df5b7a \ + --hash=sha256:32587e2e1e359276957e6fe5dad089758bc042a971a8a09ae8ecf7a8fe23d07a \ + --hash=sha256:35904d63412db21088739510216e9349e335f142ce4a04b69e2528020ee19ed4 \ + --hash=sha256:37a5c21ab099a83d669ebb251fddf8f5cee4d75ea40a5a1653d9c43d60e20867 \ + --hash=sha256:37f7a0f506cf78c80450ed1e816978643d3969f99c4ac6b01104a6fe95c5490a \ + --hash=sha256:46628ebcec4f23a1584fb52f2abe12ddb00f3bb3b7b337618b80fc1b51177aff \ + --hash=sha256:4a4c5a2905a9ccdc67a8963e24abd2f7afcd4348829412483695c59e0af9a705 \ + --hash=sha256:4aeb939bcac234b88e2d25d5381655e8353fe06b4e50b1c55ecffe56951d18c2 \ + --hash=sha256:50f5885bbed261fc97e2e66c5156244f9704083a674b8d17f24c72217d29baf5 \ + --hash=sha256:519624685a51525ddaa7d8ba8265a1540442a2ec71476f0e75241eb8263d6f51 \ + --hash=sha256:5434223b795be5c5ef8244e5ac98056e290d3a99bdcc539b916e282b160dda00 \ + --hash=sha256:55028d7a3ebdf7ace492fab9895cbc5270153f75442a0472d8516e03159ab364 \ + --hash=sha256:5654d1ac34e922b6c5711631f2da497d3a7bffd6f9f87ac23b35feea56098011 \ + --hash=sha256:574aea2c54d8f1dd1699449f332c7d9b71c339e04ae50163a3eb5ce4c4325ee4 \ + --hash=sha256:5cfa124eda500ba4b0d3afc3e91ea27ed4754e727c7f025f293a22f512bcd4c9 \ + --hash=sha256:5ea9181284754d37db15156eb7be09c86e16e50fbe77610e9e7bee09291771a1 \ + --hash=sha256:641ee2e0834812d657862f3a7de95e0048bdcb6c55496f39c6fa3d435f6ac6ad \ + --hash=sha256:650490653b110905c10adac69408380688cefc1f536a137d0d69aca1069dc1d1 \ + --hash=sha256:6959738971b4745eea16f818a2cd086fb35081383b078272c35ece2b07012716 \ + --hash=sha256:6cfedff6878b0e0d1d0a50666a817ecd85051d12d56b43d9d425455e608b5ba0 \ + --hash=sha256:7e0505719939e52a7b0c65d20e84a6044eb3712bb6f239c6b1db77ba8e173a37 \ + --hash=sha256:8b6b28d303b9d57c17a5164eb1fd2d5119bb6ff4413d5894e74873280483eeb5 \ + --hash=sha256:8bb131ffd2165fae48162c7bbd0d97c84ab961deea9b8bab16366543deeab625 \ + --hash=sha256:915866fd50dd868fdcc18d61d8258db1bf9ed7fbd6dfec960ba43365952f3b01 \ + --hash=sha256:9408fd453d5f8990405cc9def9af46bfbe3183e6110401b407c2d073c3388f47 \ + --hash=sha256:957f8d85d5e834397ef78a6109550aeb0d27a53b5032f7a57f2451e1adc37e98 \ + --hash=sha256:9c7a80ed86d6aaacb8160a1caef6680d4ddd03c944d985aecee940d168c411d1 \ + --hash=sha256:9d3b31d0a1c44b74d3ae27a3de422dfccd2b8f0b75e51ecb2faa2bf65ab1ba0d \ + --hash=sha256:a669cbe5be3c63f75bcbee0b266779706f1a54bcb1000f302685b87d1b8c1500 \ + --hash=sha256:a8aae085ea549a1eddbc9298b113cffb75e514eadbb542133dd2b99b5fb3b6af \ + --hash=sha256:ae9597cab738e7cc823f04a704fb754a9249f0b6695a6aeb63b74055cd417a96 \ + --hash=sha256:afe63b208153f3a7a2d1a5b9df452b0673082588933e54e7c8aac457cf35e758 \ + --hash=sha256:b5a5bbe29c10c5bfd63893747a1bf6f8049df607638c786252cb9243b86b6706 \ + --hash=sha256:baf7cee56bd552385c1ee39af360772fbfc2f43be005c78d1140204ad6148438 \ + --hash=sha256:bb19e30fdae77d357ce92192a3504579abe48a66877f476880238a962e5b96db \ + --hash=sha256:bece9527f5a98466d67fb5d34dc560c4da964240d8b09024bb21c1246545e04e \ + --hash=sha256:c0cae71e20e3c02c52f6b9e9722bca70e4a90a466d59477822739dc31ac18b4b \ + --hash=sha256:c268b5100cfeaa222c40f55e169d484efa1384b44bf9ca415eae6d556f02cb08 \ + --hash=sha256:c7b927155112ac858357ccf9d255dd8c044fd9ad2dc6ce4c4149527c901fa4c3 \ + --hash=sha256:c884de19528e0fcd9dc34ee94c810581dd6e74aef75437ff17e696c2bfefae3e \ + --hash=sha256:cd2f75598ae70bcfca9117d9e51a3b06fe29edd972fdd7fd57cc97b4dbf3b08a \ + --hash=sha256:cf0e99cdb600eabcd1d65cdba0d3c91418fee21c4aa1d28db47d095b1064a7d8 \ + --hash=sha256:d827099289c64589418ebbcaead0145cd19f4e3e8a93919a0100247af245fa00 \ + --hash=sha256:e8040680eaacdce4d635f12c55c714f3d4c7f57da2bc47a01229d115bd319191 \ + --hash=sha256:f0fda83e113bb0fb27dc003685f32a5dcb99c9c4f41f4fa0838ac35265c23b5c \ + --hash=sha256:f1ea21bef99c703f44444ad29c2c1b6bd55d202750b6de8e06a955380f4725d7 \ + --hash=sha256:f6bacab7514de6146a1976bc56e1545bee247242fab030b89e5f70336fc0003e \ + --hash=sha256:fe147fcd85aaed53ce90645c91ed5fca0cc88a797314c70dfd9d35925bd5d106 # via # -r requirements.in # alembic From 867ff6e4c20ca84c6bda40bb0296308712ff04f0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:14:38 +0200 Subject: [PATCH 436/582] chore(deps): update dependency pyasn1-modules to v0.4.2 (#633) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c01338c28a8b..d9f32379306f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -365,9 +365,9 @@ pyasn1==0.6.1 \ # via # pyasn1-modules # rsa -pyasn1-modules==0.4.1 \ - --hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \ - --hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c +pyasn1-modules==0.4.2 \ + --hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \ + --hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6 # via google-auth pyparsing==3.2.3 \ --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \ From 3fa73e6461585baf1b4ad5e1e9c9b21689e30a74 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:17:43 +0200 Subject: [PATCH 437/582] chore(deps): update dependency alembic to v1.15.2 (#634) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d9f32379306f..26a8ec6fcc61 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.15.1 \ - --hash=sha256:197de710da4b3e91cf66a826a5b31b5d59a127ab41bd0fc42863e2902ce2bbbe \ - --hash=sha256:e1a1c738577bca1f27e68728c910cd389b9a92152ff91d902da649c192e30c49 +alembic==1.15.2 \ + --hash=sha256:1c72391bbdeffccfe317eefba686cb9a3c078005478885413b95c3b26c57a8a7 \ + --hash=sha256:2e76bd916d547f6900ec4bb5a90aeac1485d2c92536923d0b138c02b126edc53 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From 3124e24a0a67f09e3544860514b9ce4a865cc53f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:18:07 +0200 Subject: [PATCH 438/582] chore(deps): update dependency protobuf to v5.29.4 (#636) --- packages/sqlalchemy-spanner/requirements.txt | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 26a8ec6fcc61..97555f6799e4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -340,18 +340,18 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.3 \ - --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ - --hash=sha256:0eb32bfa5219fc8d4111803e9a690658aa2e6366384fd0851064b963b6d1f2a7 \ - --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ - --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ - --hash=sha256:6ce8cc3389a20693bfde6c6562e03474c40851b44975c9b2bf6df7d8c4f864da \ - --hash=sha256:84a57163a0ccef3f96e4b6a20516cedcf5bb3a95a657131c5c3ac62200d23252 \ - --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ - --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ - --hash=sha256:b89c115d877892a512f79a8114564fb435943b59067615894c3b13cd3e1fa107 \ - --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ - --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 +protobuf==5.29.4 \ + --hash=sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7 \ + --hash=sha256:1832f0515b62d12d8e6ffc078d7e9eb06969aa6dc13c13e1036e39d73bebc2de \ + --hash=sha256:307ecba1d852ec237e9ba668e087326a67564ef83e45a0189a772ede9e854dd0 \ + --hash=sha256:3fde11b505e1597f71b875ef2fc52062b6a9740e5f7c8997ce878b6009145862 \ + --hash=sha256:476cb7b14914c780605a8cf62e38c2a85f8caff2e28a6a0bad827ec7d6c85d68 \ + --hash=sha256:4f1dfcd7997b31ef8f53ec82781ff434a28bf71d9102ddde14d076adcfc78c99 \ + --hash=sha256:678974e1e3a9b975b8bc2447fca458db5f93a2fb6b0c8db46b6675b5b5346812 \ + --hash=sha256:aec4962f9ea93c431d5714ed1be1c93f13e1a8618e70035ba2b0564d9e633f2e \ + --hash=sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d \ + --hash=sha256:d7d3f7d1d5a66ed4942d4fefb12ac4b14a29028b209d4bfb25c68ae172059922 \ + --hash=sha256:fd32223020cb25a2cc100366f1dedc904e2d71d9322403224cdde5fdced0dabe # via # google-api-core # google-cloud-spanner From 3bba24ce00d6a3b52d6835728a23e7e8bb46ba67 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:20:32 +0200 Subject: [PATCH 439/582] chore(deps): update dependency mako to v1.3.10 (#642) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 97555f6799e4..0c2391ab70f5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -233,9 +233,9 @@ importlib-metadata==8.6.1 \ --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 # via opentelemetry-api -Mako==1.3.9 \ - --hash=sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1 \ - --hash=sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac +Mako==1.3.10 \ + --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ + --hash=sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59 # via alembic markupsafe==3.0.2 \ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ From bb11a77b685534c4f29fe25e80e9410973f543cb Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 1 May 2025 20:22:29 +0200 Subject: [PATCH 440/582] chore(deps): update dependency rsa to v4.9.1 (#643) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0c2391ab70f5..103d3f674757 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -383,9 +383,9 @@ requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 # via google-api-core -rsa==4.9 \ - --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ - --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 +rsa==4.9.1 \ + --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ + --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth SQLAlchemy==2.0.40 \ --hash=sha256:00a494ea6f42a44c326477b5bee4e0fc75f6a80c01570a32b57e89cf0fbef85a \ From 9bd6a97f7b143ae8777a83c38e60cdaf3f11985d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:21:51 +0200 Subject: [PATCH 441/582] chore(deps): update dependency certifi to v2025.4.26 (#644) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 103d3f674757..588b3910d6f2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.5.2 \ --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth -certifi==2025.1.31 \ - --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ - --hash=sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe +certifi==2025.4.26 \ + --hash=sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6 \ + --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3 # via requests charset-normalizer==3.4.1 \ --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ From cd81171234ed8e2177c11a976535b71728eb2f0c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:27:12 +0200 Subject: [PATCH 442/582] chore(deps): update dependency google-auth to v2.39.0 (#645) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 588b3910d6f2..197cb94af129 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.24.2 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.38.0 \ - --hash=sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4 \ - --hash=sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a +google-auth==2.39.0 \ + --hash=sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2 \ + --hash=sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7 # via # google-api-core # google-cloud-core From c514d9f1770527d6ffd315e6ba2fddd0044cc075 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:28:51 +0200 Subject: [PATCH 443/582] chore(deps): update dependency google-cloud-spanner to v3.54.0 (#646) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 197cb94af129..c3065a2571a6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.53.0 \ - --hash=sha256:0c7be3134b74928cf928d1f73b58c722fc2014346de1240a0cc8ffdd3222f606 \ - --hash=sha256:be863394521b44df3c5a118c00c4b7c978d4437adb49e359e39b3d76362a7e60 +google-cloud-spanner==3.54.0 \ + --hash=sha256:81987b3fc7d9930e03f51bcb6c6567db62838b00bdfa82aeb708584f0536fc0c \ + --hash=sha256:eef44f1207d6fae52819099cadfb225a19596e6551216831de6cbc245725efe4 # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ From 847dd53a1c9cbf5d405e238f18617f3274d36459 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:30:30 +0200 Subject: [PATCH 444/582] chore(deps): update dependency importlib-metadata to v8.7.0 (#647) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c3065a2571a6..e008a64df2b7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -229,9 +229,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.6.1 \ - --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ - --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 +importlib-metadata==8.7.0 \ + --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ + --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd # via opentelemetry-api Mako==1.3.10 \ --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ From abf23cb467449524dbb590a80a71c16024602924 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:32:17 +0200 Subject: [PATCH 445/582] chore(deps): update dependency urllib3 to v2.4.0 (#648) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e008a64df2b7..7707f962d02e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -493,9 +493,9 @@ typing-extensions==4.13.2 \ # alembic # opentelemetry-sdk # sqlalchemy -urllib3==2.3.0 \ - --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ - --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d +urllib3==2.4.0 \ + --hash=sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466 \ + --hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813 # via requests wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ From 2712a03ded9fbf50f0f8014e28d28d1bd743af15 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 2 May 2025 10:52:01 +0200 Subject: [PATCH 446/582] chore(deps): update dependency packaging to v25 (#649) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7707f962d02e..5283838aefcf 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -320,9 +320,9 @@ opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ --hash=sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f # via opentelemetry-sdk -packaging==24.2 \ - --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ - --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f +packaging==25.0 \ + --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ + --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f # via # -r requirements.in # build From 3637b43afd64ee96347d526b6e32f54df7141b72 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 2 May 2025 08:04:16 -0400 Subject: [PATCH 447/582] fix: include schema when creating indices (#637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bug: include schema when creating indices Fixes an issue where indices aren't able to be created for tables in schemas. At present, `vist_create_index` emits SQL like ```sql CREATE INDEX index_name (col) ON schema_name.table_name ``` which results in an error when creating the table: ``` Index index_name cannot index a table/index schema_name.table_name which is in a different named schema. ``` because the name needs to be prefixed by schema. `vist_drop_index` does emit the correct SQL with the schema prefix. ```sql DROP INDEX schema_name.index_name ``` This is due to an odd issue where the base class's `visit_create_index` method has in its signature `include_schema=False`: https://github.com/sqlalchemy/sqlalchemy/blob/299284cec65076fd4c76bf1efaae60b60f4d4f7b/lib/sqlalchemy/sql/compiler.py#L6828C23-L6828C43 but `visit_drop_index` hard-codes the value to `True`: https://github.com/sqlalchemy/sqlalchemy/blob/299284cec65076fd4c76bf1efaae60b60f4d4f7b/lib/sqlalchemy/sql/compiler.py#L6870 The dialects handle this by hard-coding `include_schema=True` in `visit_create_index`, e.g. sqlite: https://github.com/sqlalchemy/sqlalchemy/blob/299284cec65076fd4c76bf1efaae60b60f4d4f7b/lib/sqlalchemy/dialects/sqlite/base.py#L1740 The difference in defaults is odd in the base class, but it seems like include_schema=True is the appropriate setting for Spanner. * chore: override default instead of always passing in True --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 2 +- .../test/mockserver_tests/test_basics.py | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 9670327fddec..2c4238a4ca4b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -529,7 +529,7 @@ def post_create_table(self, table): return post_cmds def visit_create_index( - self, create, include_schema=False, include_table_schema=True, **kw + self, create, include_schema=True, include_table_schema=True, **kw ): text = super().visit_create_index( create, include_schema, include_table_schema, **kw diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 36aee22c56f4..6db248d6a14e 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -21,6 +21,7 @@ MetaData, Table, Column, + Index, Integer, String, func, @@ -134,6 +135,47 @@ def test_create_table(self): requests[0].statements[0], ) + def test_create_table_in_schema(self): + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="schema" AND TABLE_NAME="users" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + metadata = MetaData() + Table( + "users", + metadata, + Column("user_id", Integer, primary_key=True), + Column("user_name", String(16), nullable=False), + Index("ix_users_user_id", "user_id"), + schema="schema", + ) + metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(2, len(requests[0].statements)) + + eq_( + "CREATE TABLE schema.users (\n" + "\tuser_id INT64 NOT NULL " + "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" + "\tuser_name STRING(16) NOT NULL\n" + ") PRIMARY KEY (user_id)", + requests[0].statements[0], + ) + eq_( + "CREATE INDEX schema.ix_users_user_id ON schema.users (user_id)", + requests[0].statements[1], + ) + def test_create_multiple_tables(self): for i in range(2): add_result( From e2a0d90a27f916ae1e16fe8d82f751d94cf24c49 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 2 May 2025 10:46:51 -0400 Subject: [PATCH 448/582] feat: support schemas in queries and dml statements (#639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support named schemas Add support for SELECT, UPDATE and DELETE statements against tables in schemas. Schema names are not allowed in Spanner SELECT statements. We need to avoid generating SQL like ```sql SELECT schema.tbl.id FROM schema.tbl ``` To do so, we alias the table in order to produce SQL like: ```sql SELECT tbl_1.id, tbl_1.col FROM schema.tbl AS tbl_1 ``` * feat: backwards-compatible include_table=False when returning In sqlalchemy 2.0, it's: ```python self._label_select_column(None, c, True, False, {}, include_table=False) ``` In older versions, it's ```python self._label_select_column(None, c, True, False, {'include_table': False}) ``` So instead, forward a flag to `vist_column` which can set this kwarg safely itself. * test: add mock server tests to guarantee exact SQL generation --------- Co-authored-by: Knut Olav LΓΈite --- packages/sqlalchemy-spanner/README.rst | 1 - .../sqlalchemy_spanner/sqlalchemy_spanner.py | 101 +++++++++++++++++- .../mockserver_tests/test_auto_increment.py | 4 +- .../test/mockserver_tests/test_basics.py | 50 +++++++++ .../test_bit_reversed_sequence.py | 2 +- .../test/system/test_basics.py | 50 +++++++++ 6 files changed, 202 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 927848dc77a2..2a195455c895 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -465,7 +465,6 @@ Other limitations ~~~~~~~~~~~~~~~~~ - WITH RECURSIVE statement is not supported. -- Named schemas are not supported. - Temporary tables are not supported. - Numeric type dimensions (scale and precision) are constant. See the `docs `__. diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 2c4238a4ca4b..e5559c65718f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -233,6 +233,10 @@ class SpannerSQLCompiler(SQLCompiler): compound_keywords = _compound_keywords + def __init__(self, *args, **kwargs): + self.tablealiases = {} + super().__init__(*args, **kwargs) + def get_from_hint_text(self, _, text): """Return a hint text. @@ -378,8 +382,11 @@ def limit_clause(self, select, **kw): return text def returning_clause(self, stmt, returning_cols, **kw): + # Set the spanner_is_returning flag which is passed to visit_column. columns = [ - self._label_select_column(None, c, True, False, {}) + self._label_select_column( + None, c, True, False, {"spanner_is_returning": True} + ) for c in expression._select_iterables(returning_cols) ] @@ -391,6 +398,98 @@ def visit_sequence(self, seq, **kw): seq ) + def visit_table(self, table, spanner_aliased=False, iscrud=False, **kwargs): + """Produces the table name. + + Schema names are not allowed in Spanner SELECT statements. We + need to avoid generating SQL like + + SELECT schema.tbl.id + FROM schema.tbl + + To do so, we alias the table in order to produce SQL like: + + SELECT tbl_1.id, tbl_1.col + FROM schema.tbl AS tbl_1 + + And do similar for UPDATE and DELETE statements. + + This closely mirrors the mssql dialect which also avoids + schema-qualified columns in SELECTs, although the behaviour is + currently behind a deprecated 'legacy_schema_aliasing' flag. + """ + if spanner_aliased is table or self.isinsert: + return super().visit_table(table, **kwargs) + + # Add an alias for schema-qualified tables. + # Tables in the default schema are not aliased and follow the + # standard SQLAlchemy code path. + alias = self._schema_aliased_table(table) + if alias is not None: + return self.process(alias, spanner_aliased=table, **kwargs) + else: + return super().visit_table(table, **kwargs) + + def visit_alias(self, alias, **kw): + """Produces alias statements.""" + # translate for schema-qualified table aliases + kw["spanner_aliased"] = alias.element + return super().visit_alias(alias, **kw) + + def visit_column( + self, column, add_to_result_map=None, spanner_is_returning=False, **kw + ): + """Produces column expressions. + + In tandem with visit_table, replaces schema-qualified column + names with column names qualified against an alias. + """ + if column.table is not None and not self.isinsert or self.is_subquery(): + # translate for schema-qualified table aliases + t = self._schema_aliased_table(column.table) + if t is not None: + converted = elements._corresponding_column_or_error(t, column) + if add_to_result_map is not None: + add_to_result_map( + column.name, + column.name, + (column, column.name, column.key), + column.type, + ) + + return super().visit_column(converted, **kw) + if spanner_is_returning: + # Set include_table=False because although table names are + # allowed in RETURNING clauses, schema names are not. We + # can't use the same aliasing trick above that we use with + # other statements, because INSERT statements don't result + # in visit_table calls and INSERT table names can't be + # aliased. Statements like: + # + # INSERT INTO table (id, name) + # SELECT id, name FROM another_table + # THEN RETURN another_table.id + # + # aren't legal, so the columns remain unambiguous when not + # qualified by table name. + kw["include_table"] = False + + return super().visit_column(column, add_to_result_map=add_to_result_map, **kw) + + def _schema_aliased_table(self, table): + """Creates an alias for the table if it is schema-qualified. + + If the table is schema-qualified, returns an alias for the + table and caches the alias for future references to the + table. If the table is not schema-qualified, returns None. + """ + if getattr(table, "schema", None) is not None: + if table not in self.tablealiases: + self.tablealiases[table] = table.alias() + return self.tablealiases[table] + else: + return None + class SpannerDDLCompiler(DDLCompiler): """Spanner DDL statements compiler.""" diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py index 6bc5e2c04267..7fa245e822c3 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py @@ -125,9 +125,7 @@ def test_create_table_with_specific_sequence_kind(self): def test_insert_row(self): from test.mockserver_tests.auto_increment_model import Singer - self.add_insert_result( - "INSERT INTO singers (name) VALUES (@a0) THEN RETURN singers.id" - ) + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 6db248d6a14e..e14458299b4a 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -262,3 +262,53 @@ class Singer(Base): singer.name = "New Name" session.add(singer) session.commit() + + def test_select_table_in_named_schema(self): + class Base(DeclarativeBase): + pass + + class Singer(Base): + __tablename__ = "singers" + __table_args__ = {"schema": "my_schema"} + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) + + query = ( + "SELECT" + " singers_1.id AS my_schema_singers_id," + " singers_1.name AS my_schema_singers_name\n" + "FROM my_schema.singers AS singers_1\n" + "WHERE singers_1.id = @a0\n" + " LIMIT @a1" + ) + add_singer_query_result(query) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + insert = "INSERT INTO my_schema.singers (name) VALUES (@a0) THEN RETURN id" + add_single_result(insert, "id", TypeCode.INT64, [("1",)]) + with Session(engine) as session: + singer = Singer(name="New Name") + session.add(singer) + session.commit() + + update = ( + "UPDATE my_schema.singers AS singers_1 " + "SET name=@a0 " + "WHERE singers_1.id = @a1" + ) + add_update_count(update, 1) + with Session(engine) as session: + singer = session.query(Singer).filter(Singer.id == 1).first() + singer.name = "New Name" + session.add(singer) + session.commit() + + delete = "DELETE FROM my_schema.singers AS singers_1 WHERE singers_1.id = @a0" + add_update_count(delete, 1) + with Session(engine) as session: + singer = session.query(Singer).filter(Singer.id == 1).first() + session.delete(singer) + session.commit() diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py index a18bc08e808a..9e7a81a8e510 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py @@ -110,7 +110,7 @@ def test_insert_row(self): add_result( "INSERT INTO singers (id, name) " "VALUES ( GET_NEXT_SEQUENCE_VALUE(SEQUENCE singer_id), @a0) " - "THEN RETURN singers.id", + "THEN RETURN id", result, ) engine = create_engine( diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index e5411988eda5..3001052db5e4 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -25,6 +25,8 @@ Boolean, BIGINT, select, + update, + delete, ) from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.types import REAL @@ -58,6 +60,16 @@ def define_tables(cls, metadata): Column("name", String(20)), ) + with cls.bind.begin() as conn: + conn.execute(text("CREATE SCHEMA IF NOT EXISTS schema")) + Table( + "users", + metadata, + Column("ID", Integer, primary_key=True), + Column("name", String(20)), + schema="schema", + ) + def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) eq_("Hello World", greeting.fetchone()[0]) @@ -139,6 +151,12 @@ class User(Base): ID: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(20)) + class SchemaUser(Base): + __tablename__ = "users" + __table_args__ = {"schema": "schema"} + ID: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(20)) + engine = connection.engine with Session(engine) as session: number = Number( @@ -156,3 +174,35 @@ class User(Base): users = session.scalars(statement).all() eq_(1, len(users)) is_true(users[0].ID > 0) + + with Session(engine) as session: + user = SchemaUser(name="SchemaTest") + session.add(user) + session.commit() + + users = session.scalars( + select(SchemaUser).where(SchemaUser.name == "SchemaTest") + ).all() + eq_(1, len(users)) + is_true(users[0].ID > 0) + + session.execute( + update(SchemaUser) + .where(SchemaUser.name == "SchemaTest") + .values(name="NewName") + ) + session.commit() + + users = session.scalars( + select(SchemaUser).where(SchemaUser.name == "NewName") + ).all() + eq_(1, len(users)) + is_true(users[0].ID > 0) + + session.execute(delete(SchemaUser).where(SchemaUser.name == "NewName")) + session.commit() + + users = session.scalars( + select(SchemaUser).where(SchemaUser.name == "NewName") + ).all() + eq_(0, len(users)) From 868838d932040d88baa5cd74246896ce11314397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Sat, 3 May 2025 07:07:48 +0200 Subject: [PATCH 449/582] chore: ignore tx warnings in pdml test (#653) --- .../sqlalchemy-spanner/test/mockserver_tests/test_basics.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index e14458299b4a..cffbda0dac8b 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -218,7 +218,11 @@ def test_partitioned_dml(self): add_update_count(sql, 100, AutocommitDmlMode.PARTITIONED_NON_ATOMIC) engine = create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, + connect_args={ + "client": self.client, + "pool": PingingPool(size=10), + "ignore_transaction_warnings": True, + }, ) # TODO: Support autocommit_dml_mode as a connection variable in execution # options. From 1d61fa4804bdf289573db628e04ae858d8a07fc1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 5 May 2025 07:52:10 +0200 Subject: [PATCH 450/582] chore(deps): update dependency charset-normalizer to v3.4.2 (#650) --- packages/sqlalchemy-spanner/requirements.txt | 186 +++++++++---------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 5283838aefcf..584e98f361ed 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -22,99 +22,99 @@ certifi==2025.4.26 \ --hash=sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6 \ --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3 # via requests -charset-normalizer==3.4.1 \ - --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \ - --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \ - --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \ - --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \ - --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \ - --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ - --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ - --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ - --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \ - --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ - --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \ - --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ - --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ - --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ - --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ - --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ - --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ - --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \ - --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ - --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ - --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \ - --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \ - --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \ - --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \ - --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \ - --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ - --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \ - --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ - --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ - --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ - --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \ - --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \ - --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ - --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ - --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ - --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \ - --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \ - --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ - --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ - --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ - --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \ - --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \ - --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \ - --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \ - --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \ - --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \ - --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \ - --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ - --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \ - --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ - --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ - --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ - --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \ - --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ - --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \ - --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ - --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ - --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \ - --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ - --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ - --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ - --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \ - --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ - --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ - --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \ - --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \ - --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ - --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ - --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ - --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ - --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ - --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ - --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ - --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ - --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ - --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ - --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ - --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \ - --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \ - --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ - --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ - --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \ - --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ - --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ - --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \ - --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ - --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ - --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \ - --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ - --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ - --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ - --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 +charset-normalizer==3.4.2 \ + --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ + --hash=sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45 \ + --hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \ + --hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \ + --hash=sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7 \ + --hash=sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d \ + --hash=sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d \ + --hash=sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0 \ + --hash=sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184 \ + --hash=sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db \ + --hash=sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b \ + --hash=sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64 \ + --hash=sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b \ + --hash=sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8 \ + --hash=sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff \ + --hash=sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344 \ + --hash=sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58 \ + --hash=sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e \ + --hash=sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471 \ + --hash=sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148 \ + --hash=sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a \ + --hash=sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836 \ + --hash=sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e \ + --hash=sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63 \ + --hash=sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c \ + --hash=sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1 \ + --hash=sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01 \ + --hash=sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366 \ + --hash=sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58 \ + --hash=sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5 \ + --hash=sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c \ + --hash=sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2 \ + --hash=sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a \ + --hash=sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597 \ + --hash=sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b \ + --hash=sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5 \ + --hash=sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb \ + --hash=sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f \ + --hash=sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0 \ + --hash=sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941 \ + --hash=sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0 \ + --hash=sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86 \ + --hash=sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7 \ + --hash=sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7 \ + --hash=sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455 \ + --hash=sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6 \ + --hash=sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4 \ + --hash=sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0 \ + --hash=sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3 \ + --hash=sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1 \ + --hash=sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6 \ + --hash=sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981 \ + --hash=sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c \ + --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980 \ + --hash=sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645 \ + --hash=sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7 \ + --hash=sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12 \ + --hash=sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa \ + --hash=sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd \ + --hash=sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef \ + --hash=sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f \ + --hash=sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2 \ + --hash=sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d \ + --hash=sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5 \ + --hash=sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02 \ + --hash=sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3 \ + --hash=sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd \ + --hash=sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e \ + --hash=sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214 \ + --hash=sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd \ + --hash=sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a \ + --hash=sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c \ + --hash=sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681 \ + --hash=sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba \ + --hash=sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f \ + --hash=sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a \ + --hash=sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28 \ + --hash=sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691 \ + --hash=sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82 \ + --hash=sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a \ + --hash=sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027 \ + --hash=sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7 \ + --hash=sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518 \ + --hash=sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf \ + --hash=sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b \ + --hash=sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9 \ + --hash=sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544 \ + --hash=sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da \ + --hash=sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509 \ + --hash=sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f \ + --hash=sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a \ + --hash=sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f # via requests click==8.1.8 \ --hash=sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2 \ From c62cf6f255e41a1a4f1ee2ae69a3729ad2b23775 Mon Sep 17 00:00:00 2001 From: twoodwark <40759527+twoodwark@users.noreply.github.com> Date: Mon, 5 May 2025 06:52:38 +0100 Subject: [PATCH 451/582] fix: column order in get_multi_pk_constraint (#640) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: column order in get_multi_pk_constraint * chore: order by catalog and schema name --------- Co-authored-by: Toby Woodwark Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 6 ++++-- .../sqlalchemy-spanner/test/test_suite_13.py | 16 ---------------- .../sqlalchemy-spanner/test/test_suite_14.py | 16 ---------------- .../sqlalchemy-spanner/test/test_suite_20.py | 16 ---------------- 4 files changed, 4 insertions(+), 50 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e5559c65718f..172a428bc32d 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1304,9 +1304,9 @@ def get_multi_pk_constraint( table_type_query = self._get_table_type_query(kind, True) sql = """ - SELECT tc.table_schema, tc.table_name, ccu.COLUMN_NAME + SELECT tc.table_schema, tc.table_name, kcu.column_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc - JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu + JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu USING (TABLE_CATALOG, TABLE_SCHEMA, CONSTRAINT_NAME) JOIN information_schema.tables AS t ON tc.TABLE_CATALOG = t.TABLE_CATALOG @@ -1314,6 +1314,8 @@ def get_multi_pk_constraint( AND tc.TABLE_NAME = t.TABLE_NAME WHERE {table_filter_query} {table_type_query} {schema_filter_query} tc.CONSTRAINT_TYPE = "PRIMARY KEY" + ORDER BY tc.table_catalog ASC, tc.table_schema ASC, + tc.table_name ASC, kcu.ordinal_position ASC """.format( table_filter_query=table_filter_query, table_type_query=table_type_query, diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 97f5754e066f..9a0c05452088 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -1014,22 +1014,6 @@ def test_fk_column_order(self): eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) - @testing.requires.primary_key_constraint_reflection - def test_pk_column_order(self, connection): - """ - SPANNER OVERRIDE: - Emultor doesn't support returning pk sorted by ordinal value - of columns. - """ - insp = inspect(connection) - primary_key = insp.get_pk_constraint(self.tables.tb1.name) - exp = ( - ["id", "name", "attr"] - if bool(os.environ.get("SPANNER_EMULATOR_HOST")) - else ["name", "id", "attr"] - ) - eq_(primary_key.get("constrained_columns"), exp) - class RowFetchTest(_RowFetchTest): def test_row_w_scalar_select(self): diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index 5730515792e7..e12267fafb78 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -858,22 +858,6 @@ def test_fk_column_order(self): eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) - @testing.requires.primary_key_constraint_reflection - def test_pk_column_order(self, connection): - """ - SPANNER OVERRIDE: - Emultor doesn't support returning pk sorted by ordinal value - of columns. - """ - insp = inspect(connection) - primary_key = insp.get_pk_constraint(self.tables.tb1.name) - exp = ( - ["id", "name", "attr"] - if bool(os.environ.get("SPANNER_EMULATOR_HOST")) - else ["name", "id", "attr"] - ) - eq_(primary_key.get("constrained_columns"), exp) - @pytest.mark.skip("Spanner doesn't support quotes in table names.") class QuotedNameArgumentTest(_QuotedNameArgumentTest): diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 4b6849e45a69..2b40d762715a 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -1539,22 +1539,6 @@ def test_fk_column_order(self, connection): eq_(set(fkey1.get("referred_columns")), {"name", "id", "attr"}) eq_(set(fkey1.get("constrained_columns")), {"pname", "pid", "pattr"}) - @testing.requires.primary_key_constraint_reflection - def test_pk_column_order(self, connection): - """ - SPANNER OVERRIDE: - Emultor doesn't support returning pk sorted by ordinal value - of columns. - """ - insp = inspect(connection) - primary_key = insp.get_pk_constraint(self.tables.tb1.name) - exp = ( - ["id", "name", "attr"] - if bool(os.environ.get("SPANNER_EMULATOR_HOST")) - else ["name", "id", "attr"] - ) - eq_(primary_key.get("constrained_columns"), exp) - @pytest.mark.skip("Spanner doesn't support quotes in table names.") class QuotedNameArgumentTest(_QuotedNameArgumentTest): From 18cd80fb2e20dfe1d6ed26701648b98c5be57949 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 6 May 2025 09:44:55 +0200 Subject: [PATCH 452/582] chore(deps): update dependency google-auth to v2.40.0 (#656) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 584e98f361ed..1f2dad5f8dfb 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.24.2 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.39.0 \ - --hash=sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2 \ - --hash=sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7 +google-auth==2.40.0 \ + --hash=sha256:c277cf39f7c192d8540eb6331c08b5a0796e8041af8343ae73dd6b269732ca6c \ + --hash=sha256:dc3a5078acb1043c3e43685c22d628afe40af8559cf561de388e0c939280fcc8 # via # google-api-core # google-cloud-core From c84dd375c712d48e01996bc6084ad2e6955a3267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 7 May 2025 10:39:32 +0200 Subject: [PATCH 453/582] feat: add SpannerPickleType (#655) Adds a SpannerPickleType that can be used as the implementation for the standard SQLAlchemy PickleType. The SpannerPickleType ensures that the binary values are encoded/decoded to/from base64 strings, which is how Spanner stores binary values. Fixes #654 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 32 +++- packages/sqlalchemy-spanner/samples/model.py | 5 + .../samples/pickle_type_sample.py | 55 ++++++ .../mockserver_tests/pickle_type_model.py | 31 +++ .../test/mockserver_tests/test_pickle_type.py | 181 ++++++++++++++++++ 5 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/samples/pickle_type_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/pickle_type_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 172a428bc32d..0ef9c86573fa 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import base64 import pkg_resources import re @@ -27,7 +28,7 @@ from google.cloud.spanner_v1 import Client from sqlalchemy.exc import NoSuchTableError from sqlalchemy.sql import elements -from sqlalchemy import ForeignKeyConstraint, types +from sqlalchemy import ForeignKeyConstraint, types, TypeDecorator, PickleType from sqlalchemy.engine.base import Engine from sqlalchemy.engine.default import DefaultDialect, DefaultExecutionContext from sqlalchemy.event import listens_for @@ -78,6 +79,35 @@ def reset_connection(dbapi_conn, connection_record, reset_state=None): OPERATORS[json_getitem_op] = operator_lookup["json_getitem_op"] +# PickleType that can be used with Spanner. +# Binary values are automatically encoded/decoded to/from base64. +# Usage: +# class User(Base): +# __tablename__ = 'users' +# +# user_id = Column(Integer, primary_key=True) +# username = Column(String(50), nullable=False) +# preferences = Column(PickleType(impl=SpannerPickleType)) +class SpannerPickleType(TypeDecorator): + impl = PickleType + + def bind_processor(self, dialect): + def process(value): + if value is None: + return None + return base64.standard_b64encode(value) + + return process + + def result_processor(self, dialect, coltype): + def process(value): + if value is None: + return None + return base64.standard_b64decode(value) + + return process + + # Spanner-to-SQLAlchemy types map _type_map = { "BOOL": types.Boolean, diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index 65fc4a41f219..2b231ca6230f 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -32,8 +32,10 @@ Sequence, TextClause, Index, + PickleType, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship +from google.cloud.sqlalchemy_spanner.sqlalchemy_spanner import SpannerPickleType class Base(DeclarativeBase): @@ -64,6 +66,9 @@ class Singer(Base): ) birthdate: Mapped[Optional[datetime.date]] = mapped_column(Date, nullable=True) picture: Mapped[Optional[bytes]] = mapped_column(LargeBinary, nullable=True) + preferences: Mapped[Optional[object]] = mapped_column( + PickleType(impl=SpannerPickleType), nullable=True + ) albums: Mapped[List["Album"]] = relationship( back_populates="singer", cascade="all, delete-orphan" ) diff --git a/packages/sqlalchemy-spanner/samples/pickle_type_sample.py b/packages/sqlalchemy-spanner/samples/pickle_type_sample.py new file mode 100644 index 000000000000..581599960788 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/pickle_type_sample.py @@ -0,0 +1,55 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer + +# Shows how to use PickleType with Spanner. +def pickle_type(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + singer = Singer( + id=str(uuid.uuid4()), + first_name="John", + last_name="Smith", + # Preferences are stored as an opaque BYTES column + # in the database. + preferences={ + "wakeup_call": "yes", + "vegetarian": "no", + }, + ) + session.add(singer) + session.commit() + + # Use AUTOCOMMIT for sessions that only read. This is more + # efficient than using a read/write transaction to only read. + session.connection(execution_options={"isolation_level": "AUTOCOMMIT"}) + print( + f"Inserted singer {singer.full_name} has these preferences: {singer.preferences}" + ) + + +if __name__ == "__main__": + run_sample(pickle_type) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/pickle_type_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/pickle_type_model.py new file mode 100644 index 000000000000..b3bb47c4bf3c --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/pickle_type_model.py @@ -0,0 +1,31 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import Column, Integer, String, PickleType +from sqlalchemy.orm import DeclarativeBase + +from google.cloud.sqlalchemy_spanner.sqlalchemy_spanner import SpannerPickleType + + +class Base(DeclarativeBase): + pass + + +class UserPreferences(Base): + __tablename__ = "user_preferences" + + user_id = Column(Integer, primary_key=True) + username = Column(String(50), nullable=False) + preferences = Column(PickleType(impl=SpannerPickleType), nullable=True) + created_at = Column(String(30), nullable=False) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py new file mode 100644 index 000000000000..b4c2e76c333b --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py @@ -0,0 +1,181 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + CommitRequest, + BeginTransactionRequest, + TypeCode, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, + add_update_count, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestPickleType(MockServerTestBase): + def test_create_table(self): + from test.mockserver_tests.pickle_type_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="user_preferences" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE user_preferences (\n" + "\tuser_id INT64 NOT NULL GENERATED BY DEFAULT" + " AS IDENTITY (BIT_REVERSED_POSITIVE), \n" + "\tusername STRING(50) NOT NULL, \n" + "\tpreferences BYTES(MAX), \n" + "\tcreated_at STRING(30) NOT NULL\n" + ") PRIMARY KEY (user_id)", + requests[0].statements[0], + ) + + def test_insert_and_query(self): + from test.mockserver_tests.pickle_type_model import UserPreferences + + add_update_count( + "INSERT INTO user_preferences (user_id, username, preferences, created_at) " + "VALUES (@a0, @a1, @a2, @a3)", + 1, + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + preferences = {"setting": "true"} + preferences_base64 = "gAWVFQAAAAAAAAB9lIwHc2V0dGluZ5SMBHRydWWUcy4=" + with Session(engine) as session: + new_user = UserPreferences( + user_id=1, + username="test_user", + preferences=preferences, + created_at="2025-05-04T00:00:00.000000", + ) + + session.add(new_user) + session.commit() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) + request: ExecuteSqlRequest = requests[2] + eq_(4, len(request.params)) + eq_("1", request.params["a0"]) + eq_("test_user", request.params["a1"]) + eq_(preferences_base64, request.params["a2"]) + eq_(TypeCode.INT64, request.param_types["a0"].code) + eq_(TypeCode.STRING, request.param_types["a1"].code) + eq_(TypeCode.BYTES, request.param_types["a2"].code) + + add_user_preferences_result( + "SELECT user_preferences.user_id AS user_preferences_user_id, " + "user_preferences.username AS user_preferences_username, " + "user_preferences.preferences AS user_preferences_preferences, " + "user_preferences.created_at AS user_preferences_created_at\n" + "FROM user_preferences\n" + "WHERE user_preferences.user_id = @a0\n" + " LIMIT @a1", + preferences_base64, + ) + user = session.query(UserPreferences).filter_by(user_id=1).first() + eq_(preferences, user.preferences) + + +def add_user_preferences_result(sql: str, preferences_base64: object): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="user_id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="user_name", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="preferences", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.BYTES) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="created_at", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.TIMESTAMP) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "Test", + preferences_base64, + "2025-05-05T00:00:00.000000Z", + ), + ] + ) + add_result(sql, result) From 03cb9f6edee052b30bc7918546f1fc6cd48899a4 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 7 May 2025 10:43:23 +0200 Subject: [PATCH 454/582] chore(deps): update dependency google-auth to v2.40.1 (#657) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1f2dad5f8dfb..e7fd31f6201b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.24.2 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.40.0 \ - --hash=sha256:c277cf39f7c192d8540eb6331c08b5a0796e8041af8343ae73dd6b269732ca6c \ - --hash=sha256:dc3a5078acb1043c3e43685c22d628afe40af8559cf561de388e0c939280fcc8 +google-auth==2.40.1 \ + --hash=sha256:58f0e8416a9814c1d86c9b7f6acf6816b51aba167b2c76821965271bac275540 \ + --hash=sha256:ed4cae4f5c46b41bae1d19c036e06f6c371926e97b19e816fc854eff811974ee # via # google-api-core # google-cloud-core From 9bd80da16ea62c74e14778033271ef5030de6156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 7 May 2025 12:21:47 +0200 Subject: [PATCH 455/582] feat: add isolation level support and sample (#652) * feat: add isolation level support and sample Add support for specifying the transaction isolation level. Spanner currently supports two isolation levels: - SERIALIZABLE (default) - REPEATABLE READ * fix: convert unspecified to serializable * test: only use repeatable read on the emulator --- .../cloud/sqlalchemy_spanner/requirements.py | 5 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 56 ++++- .../samples/isolation_level_sample.py | 47 ++++ .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../mockserver_tests/isolation_level_model.py | 28 +++ .../mockserver_tests/test_isolation_level.py | 208 ++++++++++++++++++ .../test/system/test_basics.py | 7 +- 7 files changed, 345 insertions(+), 11 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/isolation_level_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/isolation_level_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py index a6e6dc009788..04d21dc8d095 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/requirements.py @@ -102,7 +102,10 @@ def get_isolation_levels(self, _): Returns: dict: isolation levels description. """ - return {"default": "SERIALIZABLE", "supported": ["SERIALIZABLE", "AUTOCOMMIT"]} + return { + "default": "SERIALIZABLE", + "supported": ["SERIALIZABLE", "REPEATABLE READ", "AUTOCOMMIT"], + } @property def precision_numerics_enotation_large(self): diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 0ef9c86573fa..f2add3a15a7e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -25,7 +25,7 @@ ) from google.api_core.client_options import ClientOptions from google.auth.credentials import AnonymousCredentials -from google.cloud.spanner_v1 import Client +from google.cloud.spanner_v1 import Client, TransactionOptions from sqlalchemy.exc import NoSuchTableError from sqlalchemy.sql import elements from sqlalchemy import ForeignKeyConstraint, types, TypeDecorator, PickleType @@ -218,6 +218,16 @@ def pre_exec(self): if request_tag: self.cursor.request_tag = request_tag + ignore_transaction_warnings = self.execution_options.get( + "ignore_transaction_warnings" + ) + if ignore_transaction_warnings is not None: + conn = self._dbapi_connection.connection + if conn is not None and hasattr(conn, "_connection_variables"): + conn._connection_variables[ + "ignore_transaction_warnings" + ] = ignore_transaction_warnings + def fire_sequence(self, seq, type_): """Builds a statement for fetching next value of the sequence.""" return self._execute_scalar( @@ -777,6 +787,7 @@ class SpannerDialect(DefaultDialect): encoding = "utf-8" max_identifier_length = 256 _legacy_binary_type_literal_encoding = "utf-8" + _default_isolation_level = "SERIALIZABLE" execute_sequence_format = list @@ -828,12 +839,11 @@ def default_isolation_level(self): Returns: str: default isolation level. """ - return "SERIALIZABLE" + return self._default_isolation_level @default_isolation_level.setter def default_isolation_level(self, value): - """Default isolation level should not be changed.""" - pass + self._default_isolation_level = value def _check_unicode_returns(self, connection, additional_tests=None): """Ensure requests are returning Unicode responses.""" @@ -1682,7 +1692,7 @@ def set_isolation_level(self, conn_proxy, level): spanner_dbapi.connection.Connection, ] ): - Database connection proxy object or the connection iself. + Database connection proxy object or the connection itself. level (string): Isolation level. """ if isinstance(conn_proxy, spanner_dbapi.Connection): @@ -1690,7 +1700,13 @@ def set_isolation_level(self, conn_proxy, level): else: conn = conn_proxy.connection - conn.autocommit = level == "AUTOCOMMIT" + if level == "AUTOCOMMIT": + conn.autocommit = True + else: + if isinstance(level, str): + level = self._string_to_isolation_level(level) + conn.isolation_level = level + conn.autocommit = False def get_isolation_level(self, conn_proxy): """Get the connection isolation level. @@ -1702,7 +1718,7 @@ def get_isolation_level(self, conn_proxy): spanner_dbapi.connection.Connection, ] ): - Database connection proxy object or the connection iself. + Database connection proxy object or the connection itself. Returns: str: the connection isolation level. @@ -1712,7 +1728,31 @@ def get_isolation_level(self, conn_proxy): else: conn = conn_proxy.connection - return "AUTOCOMMIT" if conn.autocommit else "SERIALIZABLE" + if conn.autocommit: + return "AUTOCOMMIT" + + level = conn.isolation_level + if level == TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED: + level = TransactionOptions.IsolationLevel.SERIALIZABLE + if isinstance(level, TransactionOptions.IsolationLevel): + level = self._isolation_level_to_string(level) + + return level + + def _string_to_isolation_level(self, name): + try: + # SQLAlchemy guarantees that the isolation level string will: + # 1. Be all upper case. + # 2. Contain spaces instead of underscores. + # We change the spaces into underscores to get the enum value. + return TransactionOptions.IsolationLevel[name.replace(" ", "_")] + except KeyError: + raise ValueError("Invalid isolation level name '%s'" % name) + + def _isolation_level_to_string(self, level): + # SQLAlchemy expects isolation level names to contain spaces, + # and not underscores, so we remove those before returning. + return level.name.replace("_", " ") def do_rollback(self, dbapi_connection): """ diff --git a/packages/sqlalchemy-spanner/samples/isolation_level_sample.py b/packages/sqlalchemy-spanner/samples/isolation_level_sample.py new file mode 100644 index 000000000000..ceb5664375be --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/isolation_level_sample.py @@ -0,0 +1,47 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer + + +# Shows how to set the isolation level for a read/write transaction. +# Spanner supports the following isolation levels: +# - SERIALIZABLE (default) +# - REPEATABLE READ +def isolation_level_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + # You can set a default isolation level for an engine. + isolation_level="REPEATABLE READ", + echo=True, + ) + # You can override the default isolation level of the connection + # by setting it in the execution_options. + with Session(engine.execution_options(isolation_level="SERIALIZABLE")) as session: + singer_id = str(uuid.uuid4()) + singer = Singer(id=singer_id, first_name="John", last_name="Doe") + session.add(singer) + session.commit() + + +if __name__ == "__main__": + run_sample(isolation_level_sample) diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 67c3fae58c1b..82019f5b21fd 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -62,6 +62,11 @@ def transaction(session): _sample(session) +@nox.session() +def isolation_level(session): + _sample(session) + + @nox.session() def stale_read(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/isolation_level_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/isolation_level_model.py new file mode 100644 index 000000000000..9965dbf03dfa --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/isolation_level_model.py @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import String, BigInteger +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + name: Mapped[str] = mapped_column(String) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py new file mode 100644 index 000000000000..f6545298f2ea --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py @@ -0,0 +1,208 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + BatchCreateSessionsRequest, + ExecuteSqlRequest, + CommitRequest, + BeginTransactionRequest, + TransactionOptions, +) + +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + +ISOLATION_LEVEL_UNSPECIFIED = ( + TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED +) + + +class TestIsolationLevel(MockServerTestBase): + def test_default_isolation_level(self): + from test.mockserver_tests.isolation_level_model import Singer + + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session(engine) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + self.verify_isolation_level( + TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED + ) + + def test_engine_isolation_level(self): + from test.mockserver_tests.isolation_level_model import Singer + + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + isolation_level="REPEATABLE READ", + ) + + with Session(engine) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + self.verify_isolation_level(TransactionOptions.IsolationLevel.REPEATABLE_READ) + + def test_execution_options_isolation_level(self): + from test.mockserver_tests.isolation_level_model import Singer + + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + + with Session( + engine.execution_options(isolation_level="repeatable read") + ) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + self.verify_isolation_level(TransactionOptions.IsolationLevel.REPEATABLE_READ) + + def test_override_engine_isolation_level(self): + from test.mockserver_tests.isolation_level_model import Singer + + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + isolation_level="REPEATABLE READ", + ) + + with Session( + engine.execution_options(isolation_level="SERIALIZABLE") + ) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + self.verify_isolation_level(TransactionOptions.IsolationLevel.SERIALIZABLE) + + def test_auto_commit(self): + from test.mockserver_tests.isolation_level_model import Singer + + self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={ + "client": self.client, + "pool": FixedSizePool(size=10), + "ignore_transaction_warnings": True, + }, + ) + + with Session( + engine.execution_options( + isolation_level="AUTOCOMMIT", ignore_transaction_warnings=True + ) + ) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(3, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + is_instance_of(requests[2], CommitRequest) + execute_request: ExecuteSqlRequest = requests[1] + eq_( + TransactionOptions( + dict( + isolation_level=ISOLATION_LEVEL_UNSPECIFIED, + read_write=TransactionOptions.ReadWrite(), + ) + ), + execute_request.transaction.begin, + ) + + def test_invalid_isolation_level(self): + from test.mockserver_tests.isolation_level_model import Singer + + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + with pytest.raises(ValueError): + with Session(engine.execution_options(isolation_level="foo")) as session: + singer = Singer(name="Test") + session.add(singer) + session.commit() + + def verify_isolation_level(self, level): + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], BeginTransactionRequest) + is_instance_of(requests[2], ExecuteSqlRequest) + is_instance_of(requests[3], CommitRequest) + begin_request: BeginTransactionRequest = requests[1] + eq_( + TransactionOptions( + dict( + isolation_level=level, + read_write=TransactionOptions.ReadWrite(), + ) + ), + begin_request.options, + ) + + def add_insert_result(self, sql): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ) + ] + ) + ) + ) + ), + stats=result_set.ResultSetStats( + dict( + row_count_exact=1, + ) + ), + ) + ) + result.rows.extend([("987654321",)]) + add_result(sql, result) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 3001052db5e4..693617b1f233 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import os from typing import Optional from sqlalchemy import ( text, @@ -165,7 +165,10 @@ class SchemaUser(Base): session.add(number) session.commit() - with Session(engine) as session: + level = "serializable" + if os.environ.get("SPANNER_EMULATOR_HOST", ""): + level = "REPEATABLE READ" + with Session(engine.execution_options(isolation_level=level)) as session: user = User(name="Test") session.add(user) session.commit() From ca19988ffcfb25d00aac11e411735bbb79855260 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 12:35:53 +0200 Subject: [PATCH 456/582] chore(main): release 1.11.0 (#651) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 15 +++++++++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 3fa83c271a8d..fa708562d0e1 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.11.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.10.0...v1.11.0) (2025-05-07) + + +### Features + +* Add isolation level support and sample ([#652](https://github.com/googleapis/python-spanner-sqlalchemy/issues/652)) ([0aba318](https://github.com/googleapis/python-spanner-sqlalchemy/commit/0aba31835bc581a0a05e29b5878ba0a665686414)) +* Add SpannerPickleType ([#655](https://github.com/googleapis/python-spanner-sqlalchemy/issues/655)) ([0837542](https://github.com/googleapis/python-spanner-sqlalchemy/commit/0837542e5606ab9ea7a8765bf54524ebf9b0dd71)), closes [#654](https://github.com/googleapis/python-spanner-sqlalchemy/issues/654) +* Support schemas in queries and dml statements ([#639](https://github.com/googleapis/python-spanner-sqlalchemy/issues/639)) ([81c154a](https://github.com/googleapis/python-spanner-sqlalchemy/commit/81c154a37b82315a8bb57319ba11272626addad3)) + + +### Bug Fixes + +* Column order in get_multi_pk_constraint ([#640](https://github.com/googleapis/python-spanner-sqlalchemy/issues/640)) ([16c87e4](https://github.com/googleapis/python-spanner-sqlalchemy/commit/16c87e4fbf1b9d5dbac0e3279cce078a2d09e4b4)) +* Include schema when creating indices ([#637](https://github.com/googleapis/python-spanner-sqlalchemy/issues/637)) ([41905e2](https://github.com/googleapis/python-spanner-sqlalchemy/commit/41905e21b5b6473d5dbf75d40db765ebf48235dc)) + ## [1.10.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.9.0...v1.10.0) (2025-03-17) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index c11faefc8070..3e8796d47b15 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.10.0" +__version__ = "1.11.0" From adbe3b40b09b5341a76b0e553c9cc3b36a923b1a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 13:47:47 +0200 Subject: [PATCH 457/582] chore(deps): update opentelemetry-python monorepo to v1.33.1 (#658) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e7fd31f6201b..fe2ce7a10bd5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -300,9 +300,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.32.1 \ - --hash=sha256:a5be71591694a4d9195caf6776b055aa702e964d961051a0715d05f8632c32fb \ - --hash=sha256:bbd19f14ab9f15f0e85e43e6a958aa4cb1f36870ee62b7fd205783a112012724 +opentelemetry-api==1.33.1 \ + --hash=sha256:1c6055fc0a2d3f23a50c7e17e16ef75ad489345fd3df1f8b8af7c0bbf8a109e8 \ + --hash=sha256:4db83ebcf7ea93e64637ec6ee6fabee45c5cbe4abd9cf3da95c43828ddb50b83 # via # -r requirements.in # opentelemetry-instrumentation @@ -312,9 +312,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.32.1 \ - --hash=sha256:8ef373d490961848f525255a42b193430a0637e064dd132fd2a014d94792a092 \ - --hash=sha256:bba37b70a08038613247bc42beee5a81b0ddca422c7d7f1b097b32bf1c7e2f17 +opentelemetry-sdk==1.33.1 \ + --hash=sha256:19ea73d9a01be29cacaa5d6c8ce0adc0b7f7b4d58cc52f923e4413609f670112 \ + --hash=sha256:85b9fcf7c3d23506fbc9692fd210b8b025a1920535feec50bd54ce203d57a531 # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From 34ba5bae9053b326d915268e06ff8f87e4da80fd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 13:51:26 +0200 Subject: [PATCH 458/582] chore(deps): update dependency click to v8.2.1 (#660) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index fe2ce7a10bd5..148ed92e9d4f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -116,9 +116,9 @@ charset-normalizer==3.4.2 \ --hash=sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a \ --hash=sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f # via requests -click==8.1.8 \ - --hash=sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2 \ - --hash=sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a +click==8.2.1 \ + --hash=sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202 \ + --hash=sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b # via # -r requirements.in # pip-tools From ce073854db00347221b7ea811a0c926beec160db Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 14:06:16 +0200 Subject: [PATCH 459/582] chore(deps): update dependency sqlalchemy to v2.0.41 (#661) --- packages/sqlalchemy-spanner/requirements.txt | 116 +++++++++---------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 148ed92e9d4f..d4d50857e8df 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -387,64 +387,64 @@ rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth -SQLAlchemy==2.0.40 \ - --hash=sha256:00a494ea6f42a44c326477b5bee4e0fc75f6a80c01570a32b57e89cf0fbef85a \ - --hash=sha256:0bb933a650323e476a2e4fbef8997a10d0003d4da996aad3fd7873e962fdde4d \ - --hash=sha256:110179728e442dae85dd39591beb74072ae4ad55a44eda2acc6ec98ead80d5f2 \ - --hash=sha256:15d08d5ef1b779af6a0909b97be6c1fd4298057504eb6461be88bd1696cb438e \ - --hash=sha256:16d325ea898f74b26ffcd1cf8c593b0beed8714f0317df2bed0d8d1de05a8f26 \ - --hash=sha256:1abb387710283fc5983d8a1209d9696a4eae9db8d7ac94b402981fe2fe2e39ad \ - --hash=sha256:1ffdf9c91428e59744f8e6f98190516f8e1d05eec90e936eb08b257332c5e870 \ - --hash=sha256:2be94d75ee06548d2fc591a3513422b873490efb124048f50556369a834853b0 \ - --hash=sha256:2cbafc8d39ff1abdfdda96435f38fab141892dc759a2165947d1a8fffa7ef596 \ - --hash=sha256:2ee5f9999a5b0e9689bed96e60ee53c3384f1a05c2dd8068cc2e8361b0df5b7a \ - --hash=sha256:32587e2e1e359276957e6fe5dad089758bc042a971a8a09ae8ecf7a8fe23d07a \ - --hash=sha256:35904d63412db21088739510216e9349e335f142ce4a04b69e2528020ee19ed4 \ - --hash=sha256:37a5c21ab099a83d669ebb251fddf8f5cee4d75ea40a5a1653d9c43d60e20867 \ - --hash=sha256:37f7a0f506cf78c80450ed1e816978643d3969f99c4ac6b01104a6fe95c5490a \ - --hash=sha256:46628ebcec4f23a1584fb52f2abe12ddb00f3bb3b7b337618b80fc1b51177aff \ - --hash=sha256:4a4c5a2905a9ccdc67a8963e24abd2f7afcd4348829412483695c59e0af9a705 \ - --hash=sha256:4aeb939bcac234b88e2d25d5381655e8353fe06b4e50b1c55ecffe56951d18c2 \ - --hash=sha256:50f5885bbed261fc97e2e66c5156244f9704083a674b8d17f24c72217d29baf5 \ - --hash=sha256:519624685a51525ddaa7d8ba8265a1540442a2ec71476f0e75241eb8263d6f51 \ - --hash=sha256:5434223b795be5c5ef8244e5ac98056e290d3a99bdcc539b916e282b160dda00 \ - --hash=sha256:55028d7a3ebdf7ace492fab9895cbc5270153f75442a0472d8516e03159ab364 \ - --hash=sha256:5654d1ac34e922b6c5711631f2da497d3a7bffd6f9f87ac23b35feea56098011 \ - --hash=sha256:574aea2c54d8f1dd1699449f332c7d9b71c339e04ae50163a3eb5ce4c4325ee4 \ - --hash=sha256:5cfa124eda500ba4b0d3afc3e91ea27ed4754e727c7f025f293a22f512bcd4c9 \ - --hash=sha256:5ea9181284754d37db15156eb7be09c86e16e50fbe77610e9e7bee09291771a1 \ - --hash=sha256:641ee2e0834812d657862f3a7de95e0048bdcb6c55496f39c6fa3d435f6ac6ad \ - --hash=sha256:650490653b110905c10adac69408380688cefc1f536a137d0d69aca1069dc1d1 \ - --hash=sha256:6959738971b4745eea16f818a2cd086fb35081383b078272c35ece2b07012716 \ - --hash=sha256:6cfedff6878b0e0d1d0a50666a817ecd85051d12d56b43d9d425455e608b5ba0 \ - --hash=sha256:7e0505719939e52a7b0c65d20e84a6044eb3712bb6f239c6b1db77ba8e173a37 \ - --hash=sha256:8b6b28d303b9d57c17a5164eb1fd2d5119bb6ff4413d5894e74873280483eeb5 \ - --hash=sha256:8bb131ffd2165fae48162c7bbd0d97c84ab961deea9b8bab16366543deeab625 \ - --hash=sha256:915866fd50dd868fdcc18d61d8258db1bf9ed7fbd6dfec960ba43365952f3b01 \ - --hash=sha256:9408fd453d5f8990405cc9def9af46bfbe3183e6110401b407c2d073c3388f47 \ - --hash=sha256:957f8d85d5e834397ef78a6109550aeb0d27a53b5032f7a57f2451e1adc37e98 \ - --hash=sha256:9c7a80ed86d6aaacb8160a1caef6680d4ddd03c944d985aecee940d168c411d1 \ - --hash=sha256:9d3b31d0a1c44b74d3ae27a3de422dfccd2b8f0b75e51ecb2faa2bf65ab1ba0d \ - --hash=sha256:a669cbe5be3c63f75bcbee0b266779706f1a54bcb1000f302685b87d1b8c1500 \ - --hash=sha256:a8aae085ea549a1eddbc9298b113cffb75e514eadbb542133dd2b99b5fb3b6af \ - --hash=sha256:ae9597cab738e7cc823f04a704fb754a9249f0b6695a6aeb63b74055cd417a96 \ - --hash=sha256:afe63b208153f3a7a2d1a5b9df452b0673082588933e54e7c8aac457cf35e758 \ - --hash=sha256:b5a5bbe29c10c5bfd63893747a1bf6f8049df607638c786252cb9243b86b6706 \ - --hash=sha256:baf7cee56bd552385c1ee39af360772fbfc2f43be005c78d1140204ad6148438 \ - --hash=sha256:bb19e30fdae77d357ce92192a3504579abe48a66877f476880238a962e5b96db \ - --hash=sha256:bece9527f5a98466d67fb5d34dc560c4da964240d8b09024bb21c1246545e04e \ - --hash=sha256:c0cae71e20e3c02c52f6b9e9722bca70e4a90a466d59477822739dc31ac18b4b \ - --hash=sha256:c268b5100cfeaa222c40f55e169d484efa1384b44bf9ca415eae6d556f02cb08 \ - --hash=sha256:c7b927155112ac858357ccf9d255dd8c044fd9ad2dc6ce4c4149527c901fa4c3 \ - --hash=sha256:c884de19528e0fcd9dc34ee94c810581dd6e74aef75437ff17e696c2bfefae3e \ - --hash=sha256:cd2f75598ae70bcfca9117d9e51a3b06fe29edd972fdd7fd57cc97b4dbf3b08a \ - --hash=sha256:cf0e99cdb600eabcd1d65cdba0d3c91418fee21c4aa1d28db47d095b1064a7d8 \ - --hash=sha256:d827099289c64589418ebbcaead0145cd19f4e3e8a93919a0100247af245fa00 \ - --hash=sha256:e8040680eaacdce4d635f12c55c714f3d4c7f57da2bc47a01229d115bd319191 \ - --hash=sha256:f0fda83e113bb0fb27dc003685f32a5dcb99c9c4f41f4fa0838ac35265c23b5c \ - --hash=sha256:f1ea21bef99c703f44444ad29c2c1b6bd55d202750b6de8e06a955380f4725d7 \ - --hash=sha256:f6bacab7514de6146a1976bc56e1545bee247242fab030b89e5f70336fc0003e \ - --hash=sha256:fe147fcd85aaed53ce90645c91ed5fca0cc88a797314c70dfd9d35925bd5d106 +SQLAlchemy==2.0.41 \ + --hash=sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5 \ + --hash=sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582 \ + --hash=sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b \ + --hash=sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b \ + --hash=sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348 \ + --hash=sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda \ + --hash=sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5 \ + --hash=sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2 \ + --hash=sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29 \ + --hash=sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8 \ + --hash=sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f \ + --hash=sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826 \ + --hash=sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504 \ + --hash=sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae \ + --hash=sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45 \ + --hash=sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443 \ + --hash=sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23 \ + --hash=sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576 \ + --hash=sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1 \ + --hash=sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0 \ + --hash=sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71 \ + --hash=sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11 \ + --hash=sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e \ + --hash=sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f \ + --hash=sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8 \ + --hash=sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd \ + --hash=sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814 \ + --hash=sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08 \ + --hash=sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea \ + --hash=sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30 \ + --hash=sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda \ + --hash=sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9 \ + --hash=sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923 \ + --hash=sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df \ + --hash=sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036 \ + --hash=sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3 \ + --hash=sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f \ + --hash=sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6 \ + --hash=sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04 \ + --hash=sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2 \ + --hash=sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560 \ + --hash=sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70 \ + --hash=sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769 \ + --hash=sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1 \ + --hash=sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6 \ + --hash=sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b \ + --hash=sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747 \ + --hash=sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078 \ + --hash=sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440 \ + --hash=sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f \ + --hash=sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2 \ + --hash=sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d \ + --hash=sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc \ + --hash=sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a \ + --hash=sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd \ + --hash=sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9 \ + --hash=sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6 # via # -r requirements.in # alembic From a1b21957dc4f86b2c71050beac5b5296ce4c7e61 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Tue, 27 May 2025 08:08:01 -0400 Subject: [PATCH 460/582] bug: update google-cloud-spanner dependency (#662) The library now depends on google-cloud-spanner-3.54.0 for transaction isolation level support. fixes #659 --- packages/sqlalchemy-spanner/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index d3d0f8c409ba..763df27052c5 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -25,7 +25,7 @@ description = "SQLAlchemy dialect integrated into Cloud Spanner database" dependencies = [ "sqlalchemy>=1.1.13", - "google-cloud-spanner>=3.12.0", + "google-cloud-spanner>=3.54.0", "alembic", ] extras = { From 8fabead3227415f726ddc86f40c1e6c9d32049ec Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 14:11:50 +0200 Subject: [PATCH 461/582] chore(deps): update dependency google-auth to v2.40.2 (#663) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index d4d50857e8df..03e9b79dca50 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.24.2 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.40.1 \ - --hash=sha256:58f0e8416a9814c1d86c9b7f6acf6816b51aba167b2c76821965271bac275540 \ - --hash=sha256:ed4cae4f5c46b41bae1d19c036e06f6c371926e97b19e816fc854eff811974ee +google-auth==2.40.2 \ + --hash=sha256:a33cde547a2134273226fa4b853883559947ebe9207521f7afc707efbf690f58 \ + --hash=sha256:f7e568d42eedfded58734f6a60c58321896a621f7c116c411550a4b4a13da90b # via # google-api-core # google-cloud-core From 2908f28a4ed662d5fdbde479747b5376606d5a9e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 14:13:57 +0200 Subject: [PATCH 462/582] chore(deps): update dependency alembic to v1.16.1 (#664) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 03e9b79dca50..38613c67512d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.15.2 \ - --hash=sha256:1c72391bbdeffccfe317eefba686cb9a3c078005478885413b95c3b26c57a8a7 \ - --hash=sha256:2e76bd916d547f6900ec4bb5a90aeac1485d2c92536923d0b138c02b126edc53 +alembic==1.16.1 \ + --hash=sha256:0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67 \ + --hash=sha256:43d37ba24b3d17bc1eb1024fe0f51cd1dc95aeb5464594a02c6bb9ca9864bfa4 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From 3e46faca6a03359209902432526114c7722d1e0d Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 14:16:57 +0200 Subject: [PATCH 463/582] chore(deps): update dependency cachetools to v6 (#665) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 38613c67512d..36ef70ddab9e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==5.5.2 \ - --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ - --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a +cachetools==6.0.0 \ + --hash=sha256:82e73ba88f7b30228b5507dce1a1f878498fc669d972aef2dde4f3a3c24f103e \ + --hash=sha256:f225782b84438f828328fc2ad74346522f27e5b1440f4e9fd18b20ebfd1aa2cf # via google-auth certifi==2025.4.26 \ --hash=sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6 \ From cd30544e3dbbcb806ffee7169e79c4edee8f0b57 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 27 May 2025 14:18:42 +0200 Subject: [PATCH 464/582] chore(deps): update dependency zipp to v3.22.0 (#666) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 36ef70ddab9e..ffdde8a8ea54 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -584,9 +584,9 @@ wrapt==1.17.2 \ # via # deprecated # opentelemetry-instrumentation -zipp==3.21.0 \ - --hash=sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4 \ - --hash=sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931 +zipp==3.22.0 \ + --hash=sha256:dd2f28c3ce4bc67507bfd3781d21b7bb2be31103b51a4553ad7d90b84e57ace5 \ + --hash=sha256:fe208f65f2aca48b81f9e6fd8cf7b8b32c26375266b009b413d45306b6148343 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be From 303d6e27f86251c244c732b56d9ce8a36cc15652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 27 May 2025 15:17:11 +0200 Subject: [PATCH 465/582] fix: update README to include isolation level repeatable read (#668) The README file did not include any information about REPEATABLE READ. --- packages/sqlalchemy-spanner/README.rst | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 2a195455c895..3e08970f99ec 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -89,7 +89,8 @@ To pass your custom client object directly to be be used, create engine as follo engine = create_engine( "spanner+spanner:///projects/project-id/instances/instance-id/databases/database-id", - connect_args={'client': spanner.Client(project="project-id")} + connect_args={'client': spanner.Client(project="project-id")}, + isolation_level="SERIALIZABLE" ) Create a table @@ -264,8 +265,9 @@ Create a UNIQUE index: Autocommit mode ~~~~~~~~~~~~~~~ -Spanner dialect supports both ``SERIALIZABLE`` and ``AUTOCOMMIT`` -isolation levels. ``SERIALIZABLE`` is the default isolation level. +Spanner dialect supports ``SERIALIZABLE``, ``REPEATABLE_READ``, and +``AUTOCOMMIT`` isolation levels. ``SERIALIZABLE`` is the default +isolation level. ``AUTOCOMMIT`` mode corresponds to automatically committing each insert/update/delete statement right after is has been executed. @@ -287,11 +289,17 @@ Isolation level change example: Automatic transaction retry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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. +In ``SERIALIZABLE`` isolation mode, transactions may fail with an ``Aborted`` exception. +This happens if there are conflicts between different transactions, for example if one +transaction tries to read data that another transaction has modified. Aborted transactions +should be retried by the client. The Spanner SQLAlchemy provider automatically retries +aborted transactions. -This, however, may require to manually repeat a long list of operations, executed in the failed transaction. To simplify it, Spanner Connection API tracks all the operations, executed inside current transaction, and their result checksums. If the transaction failed with ``Aborted`` exception, the Connection API will automatically start a new transaction and will re-run all the tracked operations, checking if their results are the same as they were in the original transaction. In case data changed, and results differ, the transaction is dropped, as there is no way to automatically retry it. +Isolation level ``SERIALIZABLE`` takes lock for both **reads and writes**. -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. +Use isolation level ``REPEATABLE READ`` to reduce the amount of locks that +are taken by read/write transactions. ``REPEATABLE READ`` only takes locks +for **writes** and for queries that use a ``FOR UPDATE`` clause. Auto-increment primary keys ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -340,8 +348,8 @@ Usage example: query = query.filter(User.name.in_(["val1", "val2"])) query.statement.compile(session.bind) -ReadOnly transactions -~~~~~~~~~~~~~~~~~~~~~ +Read-only transactions +~~~~~~~~~~~~~~~~~~~~~~ By default, transactions produced by a Spanner connection are in ReadWrite mode. However, workloads that only read data perform better From a7190d25a07867cada34e1b17111343a084e3518 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 27 May 2025 15:24:09 +0200 Subject: [PATCH 466/582] chore(main): release 1.11.1 (#669) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index fa708562d0e1..b857594bf374 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.11.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.11.0...v1.11.1) (2025-05-27) + + +### Bug Fixes + +* Update README to include isolation level repeatable read ([#668](https://github.com/googleapis/python-spanner-sqlalchemy/issues/668)) ([d84daf6](https://github.com/googleapis/python-spanner-sqlalchemy/commit/d84daf65a496bdff6f5d9e835490785c69533238)) + ## [1.11.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.10.0...v1.11.0) (2025-05-07) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 3e8796d47b15..7f878bcb02dc 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.11.0" +__version__ = "1.11.1" From d8b1679900649af8f4ad46f916259799cfa3ab90 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 30 May 2025 08:48:03 -0400 Subject: [PATCH 467/582] feat: support multi-row inserts (#671) Support multi-row inserts like ```sql INSERT INTO tbl VALUES ('a'), ('b') ``` fixes: #670 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 1 + .../test/system/test_basics.py | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index f2add3a15a7e..9db46b6508b5 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -807,6 +807,7 @@ class SpannerDialect(DefaultDialect): insert_returning = True update_returning = True delete_returning = True + supports_multivalues_insert = True ddl_compiler = SpannerDDLCompiler preparer = SpannerIdentifierPreparer diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 693617b1f233..c2b2f6da896e 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -209,3 +209,32 @@ class SchemaUser(Base): select(SchemaUser).where(SchemaUser.name == "NewName") ).all() eq_(0, len(users)) + + def test_multi_row_insert(self, connection): + """Ensures we can perform multi-row inserts.""" + + class Base(DeclarativeBase): + pass + + class User(Base): + __tablename__ = "users" + ID: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String(20)) + + with connection.engine.begin() as conn: + inserted_rows = list( + conn.execute( + User.__table__.insert() + .values([{"name": "a"}, {"name": "b"}]) + .returning(User.__table__.c.ID, User.__table__.c.name) + ) + ) + + eq_(2, len(inserted_rows)) + eq_({"a", "b"}, {row.name for row in inserted_rows}) + + with connection.engine.connect() as conn: + selected_rows = list(conn.execute(User.__table__.select())) + + eq_(len(inserted_rows), len(selected_rows)) + eq_(set(inserted_rows), set(selected_rows)) From 6c5294667a241e8673582ba7554d6e3904b57028 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 30 May 2025 17:35:33 +0200 Subject: [PATCH 468/582] chore(deps): update dependency protobuf to v5.29.5 (#674) --- packages/sqlalchemy-spanner/requirements.txt | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ffdde8a8ea54..bcfca60d6907 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -340,18 +340,18 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.4 \ - --hash=sha256:13eb236f8eb9ec34e63fc8b1d6efd2777d062fa6aaa68268fb67cf77f6839ad7 \ - --hash=sha256:1832f0515b62d12d8e6ffc078d7e9eb06969aa6dc13c13e1036e39d73bebc2de \ - --hash=sha256:307ecba1d852ec237e9ba668e087326a67564ef83e45a0189a772ede9e854dd0 \ - --hash=sha256:3fde11b505e1597f71b875ef2fc52062b6a9740e5f7c8997ce878b6009145862 \ - --hash=sha256:476cb7b14914c780605a8cf62e38c2a85f8caff2e28a6a0bad827ec7d6c85d68 \ - --hash=sha256:4f1dfcd7997b31ef8f53ec82781ff434a28bf71d9102ddde14d076adcfc78c99 \ - --hash=sha256:678974e1e3a9b975b8bc2447fca458db5f93a2fb6b0c8db46b6675b5b5346812 \ - --hash=sha256:aec4962f9ea93c431d5714ed1be1c93f13e1a8618e70035ba2b0564d9e633f2e \ - --hash=sha256:bcefcdf3976233f8a502d265eb65ea740c989bacc6c30a58290ed0e519eb4b8d \ - --hash=sha256:d7d3f7d1d5a66ed4942d4fefb12ac4b14a29028b209d4bfb25c68ae172059922 \ - --hash=sha256:fd32223020cb25a2cc100366f1dedc904e2d71d9322403224cdde5fdced0dabe +protobuf==5.29.5 \ + --hash=sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079 \ + --hash=sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc \ + --hash=sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353 \ + --hash=sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61 \ + --hash=sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5 \ + --hash=sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736 \ + --hash=sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e \ + --hash=sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84 \ + --hash=sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671 \ + --hash=sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238 \ + --hash=sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015 # via # google-api-core # google-cloud-spanner From 47c9d57bc48a4a09ac443adbb34a016fde88b2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 2 Jun 2025 09:47:15 +0200 Subject: [PATCH 469/582] feat: support database role in connect arguments (#667) * feat: support database role in connect arguments * chore: update minimum Spanner version + add sample to nox --- .../samples/database_role_sample.py | 42 +++++++++++++++++++ .../sqlalchemy-spanner/samples/noxfile.py | 5 +++ packages/sqlalchemy-spanner/setup.py | 2 +- .../test/mockserver_tests/test_basics.py | 19 +++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/samples/database_role_sample.py diff --git a/packages/sqlalchemy-spanner/samples/database_role_sample.py b/packages/sqlalchemy-spanner/samples/database_role_sample.py new file mode 100644 index 000000000000..6edd8040ad75 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/database_role_sample.py @@ -0,0 +1,42 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer + + +# Shows how to set the database role for a connection. +def database_role_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + # You can set the database role in the connect arguments. + connect_args={"database_role": "my_role"}, + echo=True, + ) + with Session(engine) as session: + singer_id = str(uuid.uuid4()) + singer = Singer(id=singer_id, first_name="John", last_name="Doe") + session.add(singer) + session.commit() + + +if __name__ == "__main__": + run_sample(database_role_sample) diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 82019f5b21fd..2ea2c37adf41 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -77,6 +77,11 @@ def read_only_transaction(session): _sample(session) +@nox.session() +def database_role(session): + _sample(session) + + @nox.session() def _all_samples(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 763df27052c5..74ad421431c9 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -25,7 +25,7 @@ description = "SQLAlchemy dialect integrated into Cloud Spanner database" dependencies = [ "sqlalchemy>=1.1.13", - "google-cloud-spanner>=3.54.0", + "google-cloud-spanner>=3.55.0", "alembic", ] extras = { diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index cffbda0dac8b..3e422885b2ed 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -267,6 +267,25 @@ class Singer(Base): session.add(singer) session.commit() + def test_database_role(self): + add_select1_result() + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={ + "client": self.client, + "pool": FixedSizePool(size=10), + "database_role": "my_role", + }, + ) + with Session(engine.execution_options(isolation_level="autocommit")) as session: + session.execute(select(1)) + requests = self.spanner_service.requests + eq_(2, len(requests)) + is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[1], ExecuteSqlRequest) + request: BatchCreateSessionsRequest = requests[0] + eq_("my_role", request.session_template.creator_role) + def test_select_table_in_named_schema(self): class Base(DeclarativeBase): pass From 74a5a109e314a4038a908632521b61322ad8c5be Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 2 Jun 2025 09:52:29 +0200 Subject: [PATCH 470/582] chore(deps): update dependency google-cloud-spanner to v3.55.0 (#675) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index bcfca60d6907..db96d0715198 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.54.0 \ - --hash=sha256:81987b3fc7d9930e03f51bcb6c6567db62838b00bdfa82aeb708584f0536fc0c \ - --hash=sha256:eef44f1207d6fae52819099cadfb225a19596e6551216831de6cbc245725efe4 +google-cloud-spanner==3.55.0 \ + --hash=sha256:bec170c6619f667cc657e977f87391d76975559be70b155d90a2902613662b3c \ + --hash=sha256:fc9f717b612924f5e9bfae9514aa0d5cd30e6b40e8d472d030f84b16de2c18fe # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ From 5659290529b8dde18a0c0751e4e76ae51cf8f6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 2 Jun 2025 11:02:36 +0200 Subject: [PATCH 471/582] feat: document the use of statement and transaction tags (#676) Add a sample that shows how to use statement and transaction tags with SQLAlchemy. --- .../sqlalchemy-spanner/samples/noxfile.py | 5 ++ .../sqlalchemy-spanner/samples/tags_sample.py | 58 +++++++++++++++++++ .../test/mockserver_tests/test_tags.py | 38 ++++++++++-- 3 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/tags_sample.py diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 2ea2c37adf41..8c95f052c07b 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -62,6 +62,11 @@ def transaction(session): _sample(session) +@nox.session() +def tags(session): + _sample(session) + + @nox.session() def isolation_level(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/samples/tags_sample.py b/packages/sqlalchemy-spanner/samples/tags_sample.py new file mode 100644 index 000000000000..a75bddd53eb4 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/tags_sample.py @@ -0,0 +1,58 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer + + +# Shows how to transaction tags and statement tags with Spanner and SQLAlchemy. +def tags_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # Set a transaction_tag in the execution options for the session to set + # a transaction tag. + with Session( + engine.execution_options(transaction_tag="my_transaction_tag") + ) as session: + # The transaction that is automatically started by SQLAlchemy will use the + # transaction tag that is specified in the execution options. + + # Execute a query with a request tag. + singer_id = str(uuid.uuid4()) + singer = session.get( + Singer, singer_id, execution_options={"request_tag": "my_tag_1"} + ) + + # Add the singer if it was not found. + if singer is None: + # The session.Add(..) function does not support execution_options, but we can + # set the execution_options on the connection of this session. This will be + # propagated to the next statement that is executed on the connection. + session.connection().execution_options(request_tag="insert_singer") + singer = Singer(id=singer_id, first_name="John", last_name="Doe") + session.add(singer) + session.commit() + + +if __name__ == "__main__": + run_sample(tags_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py index c422bc5edd19..8c157154a7fb 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py @@ -65,6 +65,11 @@ def test_transaction_tag(self): from test.mockserver_tests.tags_model import Singer add_singer_query_result("SELECT singers.id, singers.name\n" + "FROM singers") + add_single_singer_query_result( + "SELECT singers.id AS singers_id, singers.name AS singers_name\n" + "FROM singers\n" + "WHERE singers.id = @a0" + ) add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) engine = create_engine( "spanner:///projects/p/instances/i/databases/d", @@ -75,26 +80,32 @@ def test_transaction_tag(self): engine.execution_options(transaction_tag="my-transaction-tag") ) as session: # Execute a query and an insert statement in a read/write transaction. + session.get(Singer, 1, execution_options={"request_tag": "my-tag-1"}) session.scalars( - select(Singer).execution_options(request_tag="my-tag-1") + select(Singer).execution_options(request_tag="my-tag-2") ).all() + session.connection().execution_options(request_tag="insert-singer") session.add(Singer(id=1, name="Some Singer")) session.commit() # Verify the requests that we got. requests = self.spanner_service.requests - eq_(5, len(requests)) + eq_(6, len(requests)) is_instance_of(requests[0], BatchCreateSessionsRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) - is_instance_of(requests[4], CommitRequest) + is_instance_of(requests[4], ExecuteSqlRequest) + is_instance_of(requests[5], CommitRequest) for request in requests[2:]: 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) -def add_singer_query_result(sql: str): - result = result_set.ResultSet( +def empty_singer_result_set(): + return result_set.ResultSet( dict( metadata=result_set.ResultSetMetadata( dict( @@ -124,6 +135,10 @@ def add_singer_query_result(sql: str): ), ) ) + + +def add_singer_query_result(sql: str): + result = empty_singer_result_set() result.rows.extend( [ ( @@ -137,3 +152,16 @@ def add_singer_query_result(sql: str): ] ) add_result(sql, result) + + +def add_single_singer_query_result(sql: str): + result = empty_singer_result_set() + result.rows.extend( + [ + ( + "1", + "Jane Doe", + ), + ] + ) + add_result(sql, result) From 6d7eb5e25ef0bf7c8e16a9babf2293fb87fcc34a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:10:10 +0200 Subject: [PATCH 472/582] chore(main): release 1.12.0 (#673) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 9 +++++++++ packages/sqlalchemy-spanner/version.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index b857594bf374..0bfb4ae33d6d 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [1.12.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.11.1...v1.12.0) (2025-06-02) + + +### Features + +* Document the use of statement and transaction tags ([#676](https://github.com/googleapis/python-spanner-sqlalchemy/issues/676)) ([c78ad04](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c78ad04dc7a3e1c773bde21ef927d5250f47992d)) +* Support database role in connect arguments ([#667](https://github.com/googleapis/python-spanner-sqlalchemy/issues/667)) ([47aa27c](https://github.com/googleapis/python-spanner-sqlalchemy/commit/47aa27c489cb7051cb55468ab4d6b79f8c0ce1f3)) +* Support multi-row inserts ([#671](https://github.com/googleapis/python-spanner-sqlalchemy/issues/671)) ([f5d94cd](https://github.com/googleapis/python-spanner-sqlalchemy/commit/f5d94cd15cba43684fc584072018ab3bc826f457)), closes [#670](https://github.com/googleapis/python-spanner-sqlalchemy/issues/670) + ## [1.11.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.11.0...v1.11.1) (2025-05-27) diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/version.py index 7f878bcb02dc..ecbccc606856 100644 --- a/packages/sqlalchemy-spanner/version.py +++ b/packages/sqlalchemy-spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.11.1" +__version__ = "1.12.0" From 6dca7b07549c2ecf3fc53b8066e765e469a82d64 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 5 Jun 2025 07:03:52 -0400 Subject: [PATCH 473/582] feat: Introduce compatibility with native namespace packages (#375) * feat: Introduce compatibility with native namespace packages * lint * lint * lint --- .../sqlalchemy-spanner/google/__init__.py | 22 -------- .../google/cloud/__init__.py | 22 -------- .../cloud/sqlalchemy_spanner/__init__.py | 5 +- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 6 +-- .../cloud/sqlalchemy_spanner}/version.py | 0 packages/sqlalchemy-spanner/setup.py | 51 ++++++++----------- .../sqlalchemy-spanner/test/test_suite_13.py | 8 ++- .../sqlalchemy-spanner/test/test_suite_14.py | 9 ++-- .../sqlalchemy-spanner/test/test_suite_20.py | 11 ++-- .../test/unit/test_packaging.py | 37 ++++++++++++++ 10 files changed, 76 insertions(+), 95 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/google/__init__.py delete mode 100644 packages/sqlalchemy-spanner/google/cloud/__init__.py rename packages/sqlalchemy-spanner/{ => google/cloud/sqlalchemy_spanner}/version.py (100%) create mode 100644 packages/sqlalchemy-spanner/test/unit/test_packaging.py diff --git a/packages/sqlalchemy-spanner/google/__init__.py b/packages/sqlalchemy-spanner/google/__init__.py deleted file mode 100644 index e0bdef06ac5f..000000000000 --- a/packages/sqlalchemy-spanner/google/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2021 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -try: - import pkg_resources - - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - - __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/sqlalchemy-spanner/google/cloud/__init__.py b/packages/sqlalchemy-spanner/google/cloud/__init__.py deleted file mode 100644 index e0bdef06ac5f..000000000000 --- a/packages/sqlalchemy-spanner/google/cloud/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2021 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -try: - import pkg_resources - - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - - __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py index 6cfd02bb7288..a5a387d1271f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/__init__.py @@ -14,4 +14,7 @@ from .sqlalchemy_spanner import SpannerDialect -__all__ = (SpannerDialect,) +from .version import __version__ + + +__all__ = (SpannerDialect, __version__) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 9db46b6508b5..8e935fb24d41 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -13,7 +13,6 @@ # limitations under the License. import base64 -import pkg_resources import re from alembic.ddl.base import ( @@ -50,6 +49,7 @@ from google.cloud.spanner_v1.data_types import JsonObject from google.cloud import spanner_dbapi from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call +from google.cloud.sqlalchemy_spanner import version as sqlalchemy_spanner_version import sqlalchemy USING_SQLACLCHEMY_20 = False @@ -928,8 +928,8 @@ def create_connect_args(self, url): ), url.database, ) - dist = pkg_resources.get_distribution("sqlalchemy-spanner") - options = {"user_agent": f"gl-{dist.project_name}/{dist.version}"} + dist_version = sqlalchemy_spanner_version.__version__ + options = {"user_agent": f"gl-sqlalchemy-spanner/{dist_version}"} connect_opts = url.translate_connect_args() if ( "host" in connect_opts diff --git a/packages/sqlalchemy-spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py similarity index 100% rename from packages/sqlalchemy-spanner/version.py rename to packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 74ad421431c9..2c039fe76278 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -14,7 +14,6 @@ import io import os -import warnings import setuptools @@ -37,7 +36,7 @@ } BASE_DIR = os.path.dirname(__file__) -VERSION_FILENAME = os.path.join(BASE_DIR, "version.py") +VERSION_FILENAME = os.path.join(BASE_DIR, "google/cloud/sqlalchemy_spanner/version.py") PACKAGE_INFO = {} with open(VERSION_FILENAME) as f: exec(f.read(), PACKAGE_INFO) @@ -56,31 +55,23 @@ if package.startswith("google") ] -# Determine which namespaces are needed. -namespaces = ["google"] -if "google.cloud" in packages: - namespaces.append("google.cloud") - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - setuptools.setup( - author="Google LLC", - author_email="cloud-spanner-developers@googlegroups.com", - classifiers=["Intended Audience :: Developers"], - description=description, - long_description=readme, - entry_points={ - "sqlalchemy.dialects": [ - "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" - ] - }, - install_requires=dependencies, - extras_require=extras, - name=name, - namespace_packages=namespaces, - packages=packages, - url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", - version=version, - include_package_data=True, - zip_safe=False, - ) +setuptools.setup( + author="Google LLC", + author_email="googleapis-packages@google.com", + classifiers=["Intended Audience :: Developers"], + description=description, + long_description=readme, + entry_points={ + "sqlalchemy.dialects": [ + "spanner.spanner = google.cloud.sqlalchemy_spanner:SpannerDialect" + ] + }, + install_requires=dependencies, + extras_require=extras, + name=name, + packages=packages, + url="https://github.com/cloudspannerecosystem/python-spanner-sqlalchemy", + version=version, + include_package_data=True, + zip_safe=False, +) diff --git a/packages/sqlalchemy-spanner/test/test_suite_13.py b/packages/sqlalchemy-spanner/test/test_suite_13.py index 9a0c05452088..be8b1f782cb0 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_13.py +++ b/packages/sqlalchemy-spanner/test/test_suite_13.py @@ -18,7 +18,6 @@ import decimal import operator import os -import pkg_resources import pytest import random import time @@ -126,6 +125,8 @@ ) from test._helpers import get_db_url, get_project +from google.cloud.sqlalchemy_spanner import version as sqlalchemy_spanner_version + config.test_schema = "" @@ -1632,12 +1633,10 @@ class UserAgentTest(SpannerSpecificTestBase): """Check that SQLAlchemy dialect uses correct user agent.""" def test_user_agent(self): - dist = pkg_resources.get_distribution("sqlalchemy-spanner") - with self._engine.connect() as connection: assert ( connection.connection.instance._client._client_info.user_agent - == f"gl-{dist.project_name}/{dist.version}" + == f"gl-sqlalchemy-spanner/{sqlalchemy_spanner_version.__version__}" ) @@ -1689,7 +1688,6 @@ def setUp(self): def test_offset_only(self): for offset in [1, 7, 10, 100, 1000, 10000]: - with self._engine.connect().execution_options(read_only=True) as connection: list(connection.execute(self._table.select().offset(offset)).fetchall()) diff --git a/packages/sqlalchemy-spanner/test/test_suite_14.py b/packages/sqlalchemy-spanner/test/test_suite_14.py index e12267fafb78..5a083ce26b6f 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_14.py +++ b/packages/sqlalchemy-spanner/test/test_suite_14.py @@ -18,7 +18,6 @@ import decimal import operator import os -import pkg_resources import pytest import random import time @@ -143,6 +142,9 @@ ) from test._helpers import get_db_url, get_project +from google.cloud.sqlalchemy_spanner import version as sqlalchemy_spanner_version + + config.test_schema = "" @@ -557,7 +559,6 @@ def test_get_foreign_keys(self, connection, use_schema): def test_get_table_names( self, connection, order_by, include_plain, include_views, use_schema ): - if use_schema: schema = config.test_schema else: @@ -1905,12 +1906,10 @@ def setUp(self): self._metadata = MetaData(bind=self._engine) def test_user_agent(self): - dist = pkg_resources.get_distribution("sqlalchemy-spanner") - with self._engine.connect() as connection: assert ( connection.connection.instance._client._client_info.user_agent - == "gl-" + dist.project_name + "/" + dist.version + == f"gl-sqlalchemy-spanner/{sqlalchemy_spanner_version.__version__}" ) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 2b40d762715a..3cb252d2dee3 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -18,7 +18,6 @@ import decimal import operator import os -import pkg_resources import pytest import random import time @@ -157,6 +156,9 @@ get_project, ) +from google.cloud.sqlalchemy_spanner import version as sqlalchemy_spanner_version + + config.test_schema = "" @@ -884,7 +886,6 @@ def test_get_multi_foreign_keys( scope=ObjectScope.DEFAULT, kind=ObjectKind.TABLE, ): - """ SPANNER OVERRIDE: @@ -1106,7 +1107,6 @@ def test_get_foreign_keys(self, connection, use_schema): (True, testing.requires.schemas), False, argnames="use_schema" ) def test_get_table_names(self, connection, order_by, use_schema): - schema = None _ignore_tables = [ @@ -1981,7 +1981,6 @@ def _round_trip(self, datatype, data): assert isinstance(row[0], (long, int)) # noqa def _huge_ints(): - return testing.combinations( 2147483649, # 32 bits 2147483648, # 32 bits @@ -2721,12 +2720,10 @@ def setUp(self): self._metadata = MetaData() def test_user_agent(self): - dist = pkg_resources.get_distribution("sqlalchemy-spanner") - with self._engine.connect() as connection: assert ( connection.connection.instance._client._client_info.user_agent - == "gl-" + dist.project_name + "/" + dist.version + == f"gl-sqlalchemy-spanner/{sqlalchemy_spanner_version.__version__}" ) diff --git a/packages/sqlalchemy-spanner/test/unit/test_packaging.py b/packages/sqlalchemy-spanner/test/unit/test_packaging.py new file mode 100644 index 000000000000..c05f60426361 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/unit/test_packaging.py @@ -0,0 +1,37 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess +import sys + + +def test_namespace_package_compat(tmp_path): + # The ``google`` namespace package should not be masked + # by the presence of ``sqlalchemy-spanner``. + google = tmp_path / "google" + google.mkdir() + google.joinpath("othermod.py").write_text("") + env = dict(os.environ, PYTHONPATH=str(tmp_path)) + cmd = [sys.executable, "-m", "google.othermod"] + subprocess.check_call(cmd, env=env) + + # The ``google.cloud`` namespace package should not be masked + # by the presence of ``sqlalchemy-spanner``. + google_cloud = tmp_path / "google" / "cloud" + google_cloud.mkdir() + google_cloud.joinpath("othermod.py").write_text("") + env = dict(os.environ, PYTHONPATH=str(tmp_path)) + cmd = [sys.executable, "-m", "google.cloud.othermod"] + subprocess.check_call(cmd, env=env) From 35b849f3ff1004b8d3fda97bb0c5893f4b3cc5c6 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:18:58 +0200 Subject: [PATCH 474/582] chore(main): release 1.13.0 (#688) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 0bfb4ae33d6d..b56111be1485 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.12.0...v1.13.0) (2025-06-05) + + +### Features + +* Introduce compatibility with native namespace packages ([#375](https://github.com/googleapis/python-spanner-sqlalchemy/issues/375)) ([052e699](https://github.com/googleapis/python-spanner-sqlalchemy/commit/052e699f82a795def518f4f0a32039e1c68174a0)) + ## [1.12.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.11.1...v1.12.0) (2025-06-02) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index ecbccc606856..bde8e01493a7 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.12.0" +__version__ = "1.13.0" From 114ea4e2cf9bf03798f6671fff09d50ea5e24736 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 19 Jun 2025 14:36:32 +0200 Subject: [PATCH 475/582] chore(deps): update dependency grpcio-status to v1.73.0 (#678) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index db96d0715198..f18884eb4b28 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -221,9 +221,9 @@ grpcio==1.71.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.71.0 \ - --hash=sha256:11405fed67b68f406b3f3c7c5ae5104a79d2d309666d10d61b152e91d28fb968 \ - --hash=sha256:843934ef8c09e3e858952887467f8256aac3910c55f077a359a65b2b3cde3e68 +grpcio-status==1.73.0 \ + --hash=sha256:a2b7f430568217f884fe52a5a0133b6f4c9338beae33fb5370134a8eaf58f974 \ + --hash=sha256:a3f3a9994b44c364f014e806114ba44cc52e50c426779f958c8b22f14ff0d892 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 65b79b0b2d16188ca602654199e2fd4e8839aa70 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 19 Jun 2025 14:42:53 +0200 Subject: [PATCH 476/582] chore(deps): update dependency grpcio to v1.73.0 (#677) --- packages/sqlalchemy-spanner/requirements.txt | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f18884eb4b28..8eb8dea35a57 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -163,58 +163,58 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.71.0 \ - --hash=sha256:0ab8b2864396663a5b0b0d6d79495657ae85fa37dcb6498a2669d067c65c11ea \ - --hash=sha256:0fa05ee31a20456b13ae49ad2e5d585265f71dd19fbd9ef983c28f926d45d0a7 \ - --hash=sha256:0ff35c8d807c1c7531d3002be03221ff9ae15712b53ab46e2a0b4bb271f38537 \ - --hash=sha256:1be857615e26a86d7363e8a163fade914595c81fec962b3d514a4b1e8760467b \ - --hash=sha256:20e8f653abd5ec606be69540f57289274c9ca503ed38388481e98fa396ed0b41 \ - --hash=sha256:22c3bc8d488c039a199f7a003a38cb7635db6656fa96437a8accde8322ce2366 \ - --hash=sha256:24e867651fc67717b6f896d5f0cac0ec863a8b5fb7d6441c2ab428f52c651c6b \ - --hash=sha256:2b85f7820475ad3edec209d3d89a7909ada16caab05d3f2e08a7e8ae3200a55c \ - --hash=sha256:39983a9245d37394fd59de71e88c4b295eb510a3555e0a847d9965088cdbd033 \ - --hash=sha256:3d081e859fb1ebe176de33fc3adb26c7d46b8812f906042705346b314bde32c3 \ - --hash=sha256:469f42a0b410883185eab4689060a20488a1a0a00f8bbb3cbc1061197b4c5a79 \ - --hash=sha256:47be9584729534660416f6d2a3108aaeac1122f6b5bdbf9fd823e11fe6fbaa29 \ - --hash=sha256:4be74ddeeb92cc87190e0e376dbc8fc7736dbb6d3d454f2fa1f5be1dee26b9d7 \ - --hash=sha256:4dd0dfbe4d5eb1fcfec9490ca13f82b089a309dc3678e2edabc144051270a66e \ - --hash=sha256:5b08d03ace7aca7b2fadd4baf291139b4a5f058805a8327bfe9aece7253b6d67 \ - --hash=sha256:63e41b91032f298b3e973b3fa4093cbbc620c875e2da7b93e249d4728b54559a \ - --hash=sha256:652350609332de6dac4ece254e5d7e1ff834e203d6afb769601f286886f6f3a8 \ - --hash=sha256:693bc706c031aeb848849b9d1c6b63ae6bcc64057984bb91a542332b75aa4c3d \ - --hash=sha256:74258dce215cb1995083daa17b379a1a5a87d275387b7ffe137f1d5131e2cfbb \ - --hash=sha256:789d5e2a3a15419374b7b45cd680b1e83bbc1e52b9086e49308e2c0b5bbae6e3 \ - --hash=sha256:7c9c80ac6091c916db81131d50926a93ab162a7e97e4428ffc186b6e80d6dda4 \ - --hash=sha256:7d6ac9481d9d0d129224f6d5934d5832c4b1cddb96b59e7eba8416868909786a \ - --hash=sha256:85da336e3649a3d2171e82f696b5cad2c6231fdd5bad52616476235681bee5b3 \ - --hash=sha256:8700a2a57771cc43ea295296330daaddc0d93c088f0a35cc969292b6db959bf3 \ - --hash=sha256:8997d6785e93308f277884ee6899ba63baafa0dfb4729748200fcc537858a509 \ - --hash=sha256:9182e0063112e55e74ee7584769ec5a0b4f18252c35787f48738627e23a62b97 \ - --hash=sha256:9b91879d6da1605811ebc60d21ab6a7e4bae6c35f6b63a061d61eb818c8168f6 \ - --hash=sha256:a2242d6950dc892afdf9e951ed7ff89473aaf744b7d5727ad56bdaace363722b \ - --hash=sha256:a371e6b6a5379d3692cc4ea1cb92754d2a47bdddeee755d3203d1f84ae08e03e \ - --hash=sha256:a76d39b5fafd79ed604c4be0a869ec3581a172a707e2a8d7a4858cb05a5a7637 \ - --hash=sha256:ad9f30838550695b5eb302add33f21f7301b882937460dd24f24b3cc5a95067a \ - --hash=sha256:b2266862c5ad664a380fbbcdbdb8289d71464c42a8c29053820ee78ba0119e5d \ - --hash=sha256:b78a99cd1ece4be92ab7c07765a0b038194ded2e0a26fd654591ee136088d8d7 \ - --hash=sha256:c200cb6f2393468142eb50ab19613229dcc7829b5ccee8b658a36005f6669fdd \ - --hash=sha256:c30f393f9d5ff00a71bb56de4aa75b8fe91b161aeb61d39528db6b768d7eac69 \ - --hash=sha256:c6a0a28450c16809f94e0b5bfe52cabff63e7e4b97b44123ebf77f448534d07d \ - --hash=sha256:cebc1b34ba40a312ab480ccdb396ff3c529377a2fce72c45a741f7215bfe8379 \ - --hash=sha256:d2c170247315f2d7e5798a22358e982ad6eeb68fa20cf7a820bb74c11f0736e7 \ - --hash=sha256:d35a95f05a8a2cbe8e02be137740138b3b2ea5f80bd004444e4f9a1ffc511e32 \ - --hash=sha256:d5170929109450a2c031cfe87d6716f2fae39695ad5335d9106ae88cc32dc84c \ - --hash=sha256:d6aa986318c36508dc1d5001a3ff169a15b99b9f96ef5e98e13522c506b37eef \ - --hash=sha256:d6de81c9c00c8a23047136b11794b3584cdc1460ed7cbc10eada50614baa1444 \ - --hash=sha256:dc1a1231ed23caac1de9f943d031f1bc38d0f69d2a3b243ea0d664fc1fbd7fec \ - --hash=sha256:e6beeea5566092c5e3c4896c6d1d307fb46b1d4bdf3e70c8340b190a69198594 \ - --hash=sha256:e6d8de076528f7c43a2f576bc311799f89d795aa6c9b637377cc2b1616473804 \ - --hash=sha256:e6f83a583ed0a5b08c5bc7a3fe860bb3c2eac1f03f1f63e0bc2091325605d2b7 \ - --hash=sha256:f250ff44843d9a0615e350c77f890082102a0318d66a99540f54769c8766ab73 \ - --hash=sha256:f71574afdf944e6652203cd1badcda195b2a27d9c83e6d88dc1ce3cfb73b31a5 \ - --hash=sha256:f903017db76bf9cc2b2d8bdd37bf04b505bbccad6be8a81e1542206875d0e9db \ - --hash=sha256:f9a412f55bb6e8f3bb000e020dbc1e709627dcb3a56f6431fa7076b4c1aab0db \ - --hash=sha256:f9c30c464cb2ddfbc2ddf9400287701270fdc0f14be5f08a1e3939f1e749b455 +grpcio==1.73.0 \ + --hash=sha256:068ecc415f79408d57a7f146f54cdf9f0acb4b301a52a9e563973dc981e82f3d \ + --hash=sha256:072d8154b8f74300ed362c01d54af8b93200c1a9077aeaea79828d48598514f1 \ + --hash=sha256:07ad7c57233c2109e4ac999cb9c2710c3b8e3f491a73b058b0ce431f31ed8145 \ + --hash=sha256:085ebe876373ca095e24ced95c8f440495ed0b574c491f7f4f714ff794bbcd10 \ + --hash=sha256:0e092a4b28eefb63eec00d09ef33291cd4c3a0875cde29aec4d11d74434d222c \ + --hash=sha256:0eb5df4f41ea10bda99a802b2a292d85be28958ede2a50f2beb8c7fc9a738419 \ + --hash=sha256:10e8edc035724aba0346a432060fd192b42bd03675d083c01553cab071a28da5 \ + --hash=sha256:12787c791c3993d0ea1cc8bf90393647e9a586066b3b322949365d2772ba965b \ + --hash=sha256:1284850607901cfe1475852d808e5a102133461ec9380bc3fc9ebc0686ee8e32 \ + --hash=sha256:128ba2ebdac41e41554d492b82c34586a90ebd0766f8ebd72160c0e3a57b9155 \ + --hash=sha256:1dd7fa7276dcf061e2d5f9316604499eea06b1b23e34a9380572d74fe59915a8 \ + --hash=sha256:275e23d4c428c26b51857bbd95fcb8e528783597207ec592571e4372b300a29f \ + --hash=sha256:2a9c957dc65e5d474378d7bcc557e9184576605d4b4539e8ead6e351d7ccce20 \ + --hash=sha256:2c17771e884fddf152f2a0df12478e8d02853e5b602a10a9a9f1f52fa02b1d32 \ + --hash=sha256:2d1510c4ea473110cb46a010555f2c1a279d1c256edb276e17fa571ba1e8927c \ + --hash=sha256:33577fe7febffe8ebad458744cfee8914e0c10b09f0ff073a6b149a84df8ab8f \ + --hash=sha256:36bf93f6a657f37c131d9dd2c391b867abf1426a86727c3575393e9e11dadb0d \ + --hash=sha256:38cf518cc54cd0c47c9539cefa8888549fcc067db0b0c66a46535ca8032020c4 \ + --hash=sha256:3902b71407d021163ea93c70c8531551f71ae742db15b66826cf8825707d2908 \ + --hash=sha256:3af4c30918a7f0d39de500d11255f8d9da4f30e94a2033e70fe2a720e184bd8e \ + --hash=sha256:483c507c2328ed0e01bc1adb13d1eada05cc737ec301d8e5a8f4a90f387f1790 \ + --hash=sha256:4dd8d8d092efede7d6f48d695ba2592046acd04ccf421436dd7ed52677a9ad29 \ + --hash=sha256:51036f641f171eebe5fa7aaca5abbd6150f0c338dab3a58f9111354240fe36ec \ + --hash=sha256:60813d8a16420d01fa0da1fc7ebfaaa49a7e5051b0337cd48f4f950eb249a08e \ + --hash=sha256:6228f7eb6d9f785f38b589d49957fca5df3d5b5349e77d2d89b14e390165344c \ + --hash=sha256:6ddc1cfb2240f84d35d559ade18f69dcd4257dbaa5ba0de1a565d903aaab2968 \ + --hash=sha256:70176093d0a95b44d24baa9c034bb67bfe2b6b5f7ebc2836f4093c97010e17fd \ + --hash=sha256:859f70c8e435e8e1fa060e04297c6818ffc81ca9ebd4940e180490958229a45a \ + --hash=sha256:965a16b71a8eeef91fc4df1dc40dc39c344887249174053814f8a8e18449c4c3 \ + --hash=sha256:9ffc972b530bf73ef0f948f799482a1bf12d9b6f33406a8e6387c0ca2098a833 \ + --hash=sha256:a73c72922dfd30b396a5f25bb3a4590195ee45ecde7ee068acb0892d2900cf07 \ + --hash=sha256:b71a7b4483d1f753bbc11089ff0f6fa63b49c97a9cc20552cded3fcad466d23b \ + --hash=sha256:bbf45d59d090bf69f1e4e1594832aaf40aa84b31659af3c5e2c3f6a35202791a \ + --hash=sha256:c0811331b469e3f15dda5f90ab71bcd9681189a83944fd6dc908e2c9249041ef \ + --hash=sha256:c201a34aa960c962d0ce23fe5f423f97e9d4b518ad605eae6d0a82171809caaa \ + --hash=sha256:c98ba1d928a178ce33f3425ff823318040a2b7ef875d30a0073565e5ceb058d9 \ + --hash=sha256:ce953d9d2100e1078a76a9dc2b7338d5415924dc59c69a15bf6e734db8a0f1ca \ + --hash=sha256:cfc556c1d6aef02c727ec7d0016827a73bfe67193e47c546f7cadd3ee6bf1a60 \ + --hash=sha256:d050197eeed50f858ef6c51ab09514856f957dba7b1f7812698260fc9cc417f6 \ + --hash=sha256:d0a1517b2005ba1235a1190b98509264bf72e231215dfeef8db9a5a92868789e \ + --hash=sha256:d12bbb88381ea00bdd92c55aff3da3391fd85bc902c41275c8447b86f036ce0f \ + --hash=sha256:d84000367508ade791d90c2bafbd905574b5ced8056397027a77a215d601ba15 \ + --hash=sha256:da1d677018ef423202aca6d73a8d3b2cb245699eb7f50eb5f74cae15a8e1f724 \ + --hash=sha256:e0084d4559ee3dbdcce9395e1bc90fdd0262529b32c417a39ecbc18da8074ac7 \ + --hash=sha256:e2459a27c6886e7e687e4e407778425f3c6a971fa17a16420227bda39574d64b \ + --hash=sha256:e53007f70d9783f53b41b4cf38ed39a8e348011437e4c287eee7dd1d39d54b2f \ + --hash=sha256:ebb8d5f4b0200916fb292a964a4d41210de92aba9007e33d8551d85800ea16cb \ + --hash=sha256:ebd8d269df64aff092b2cec5e015d8ae09c7e90888b5c35c24fdca719a2c9f35 \ + --hash=sha256:ef5fff73d5f724755693a464d444ee0a448c6cdfd3c1616a9223f736c622617d \ + --hash=sha256:f5cdc332b503c33b1643b12ea933582c7b081957c8bc2ea4cc4bc58054a09288 \ + --hash=sha256:fb9d7c27089d9ba3746f18d2109eb530ef2a37452d2ff50f5a6696cd39167d3b # via # google-api-core # googleapis-common-protos From 0ee1609e04e3ecf77b31901edcc47943fe112376 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 19 Jun 2025 19:33:43 +0200 Subject: [PATCH 477/582] chore(deps): update dependency google-api-core to v2.25.1 (#679) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8eb8dea35a57..02a966a982c7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -128,9 +128,9 @@ Deprecated==1.2.18 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.24.2 \ - --hash=sha256:810a63ac95f3c441b7c0e43d344e372887f62ce9071ba972eacf32672e072de9 \ - --hash=sha256:81718493daf06d96d6bc76a91c23874dbf2fac0adbbf542831b805ee6e974696 +google-api-core[grpc]==2.25.1 \ + --hash=sha256:8a2a56c1fef82987a524371f99f3bd0143702fecc670c72e600c1cda6bf8dbb7 \ + --hash=sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8 # via # google-cloud-core # google-cloud-spanner From f1c8cc30cce8bc2ae614b8979fdf841ec4de33d5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:03:24 +0200 Subject: [PATCH 478/582] chore(deps): update dependency typing-extensions to v4.14.0 (#680) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 02a966a982c7..da0b7afb5cda 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -486,9 +486,9 @@ tomli==2.2.1 \ --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in -typing-extensions==4.13.2 \ - --hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c \ - --hash=sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef +typing-extensions==4.14.0 \ + --hash=sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4 \ + --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af # via # alembic # opentelemetry-sdk From d1afbae420c211923c9b8ec7420ecbdc41542f84 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:10:11 +0200 Subject: [PATCH 479/582] chore(deps): update opentelemetry-python monorepo to v1.34.1 (#683) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index da0b7afb5cda..4e3092b00dc2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -300,9 +300,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.33.1 \ - --hash=sha256:1c6055fc0a2d3f23a50c7e17e16ef75ad489345fd3df1f8b8af7c0bbf8a109e8 \ - --hash=sha256:4db83ebcf7ea93e64637ec6ee6fabee45c5cbe4abd9cf3da95c43828ddb50b83 +opentelemetry-api==1.34.1 \ + --hash=sha256:64f0bd06d42824843731d05beea88d4d4b6ae59f9fe347ff7dfa2cc14233bbb3 \ + --hash=sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c # via # -r requirements.in # opentelemetry-instrumentation @@ -312,9 +312,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.33.1 \ - --hash=sha256:19ea73d9a01be29cacaa5d6c8ce0adc0b7f7b4d58cc52f923e4413609f670112 \ - --hash=sha256:85b9fcf7c3d23506fbc9692fd210b8b025a1920535feec50bd54ce203d57a531 +opentelemetry-sdk==1.34.1 \ + --hash=sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e \ + --hash=sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d # via -r requirements.in opentelemetry-semantic-conventions==0.48b0 \ --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ From a651592a9fac38b397edf095456e4fe484c837b5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:13:05 +0200 Subject: [PATCH 480/582] chore(deps): update dependency google-auth to v2.40.3 (#687) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4e3092b00dc2..f3e70edfa055 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -134,9 +134,9 @@ google-api-core[grpc]==2.25.1 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.40.2 \ - --hash=sha256:a33cde547a2134273226fa4b853883559947ebe9207521f7afc707efbf690f58 \ - --hash=sha256:f7e568d42eedfded58734f6a60c58321896a621f7c116c411550a4b4a13da90b +google-auth==2.40.3 \ + --hash=sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca \ + --hash=sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77 # via # google-api-core # google-cloud-core From 67493ee7aab3b1e9a6490413b243a58455beb7d1 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 20 Jun 2025 02:13:25 -0400 Subject: [PATCH 481/582] bug: Support Retrieval of Cross-Schema Foreign Keys (#681) Allow `get_multi_foreign_keys` to retrieve foreign keys between tables in different schemas. The current SQL used to retrieve them has a mistake in the JOINs used to retrieve them, confusing the `table_schema` column and the `constraint_schema` column. This goes unnoticed as long as everything is in the same schema. Include schemas names in ALTER TABLE schema.table DROP CONSTRAINT DDL and quote the table name. fixes: #638 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 17 ++++- .../test/system/test_basics.py | 64 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 8e935fb24d41..aa6ee2b5ad24 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -607,8 +607,17 @@ def visit_drop_table(self, drop_table, **kw): constrs = "" for cons in drop_table.element.constraints: if isinstance(cons, ForeignKeyConstraint) and cons.name: + effective_schema = self.preparer.schema_for_object(drop_table.element) + if effective_schema: + table = ( + f"{self.preparer.quote_schema(effective_schema)}" + "." + f"{self.preparer.quote(drop_table.element.name)}" + ) + else: + table = self.preparer.quote(drop_table.element.name) constrs += "ALTER TABLE {table} DROP CONSTRAINT {constr};".format( - table=drop_table.element.name, + table=table, constr=self.preparer.quote(cons.name), ) @@ -1472,10 +1481,12 @@ def get_multi_foreign_keys( ) FROM information_schema.table_constraints AS tc JOIN information_schema.constraint_column_usage AS ccu - USING (table_catalog, table_schema, constraint_name) + ON ccu.table_catalog = tc.table_catalog + and ccu.constraint_schema = tc.table_schema + and ccu.constraint_name = tc.constraint_name JOIN information_schema.constraint_table_usage AS ctu ON ctu.table_catalog = tc.table_catalog - and ctu.table_schema = tc.table_schema + and ctu.constraint_schema = tc.table_schema and ctu.constraint_name = tc.constraint_name JOIN information_schema.key_column_usage AS kcu ON kcu.table_catalog = tc.table_catalog diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index c2b2f6da896e..bb2ae9a80eb5 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -18,12 +18,14 @@ Table, Column, Integer, + ForeignKey, PrimaryKeyConstraint, String, Index, MetaData, Boolean, BIGINT, + inspect, select, update, delete, @@ -59,6 +61,16 @@ def define_tables(cls, metadata): Column("ID", Integer, primary_key=True), Column("name", String(20)), ) + # Add a foreign key example. + Table( + "number_colors", + metadata, + Column("ID", Integer, primary_key=True), + Column( + "number_id", Integer, ForeignKey("numbers.number", name="number_fk") + ), + Column("color", String(20)), + ) with cls.bind.begin() as conn: conn.execute(text("CREATE SCHEMA IF NOT EXISTS schema")) @@ -69,6 +81,19 @@ def define_tables(cls, metadata): Column("name", String(20)), schema="schema", ) + # Add a foreign key example which crosses schema. + Table( + "number_colors", + metadata, + Column("ID", Integer, primary_key=True), + Column( + "number_id", + Integer, + ForeignKey("numbers.number", name="cross_schema_number_fk"), + ), + Column("color", String(20)), + schema="schema", + ) def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) @@ -88,7 +113,7 @@ def test_reflect(self, connection): engine = connection.engine meta: MetaData = MetaData() meta.reflect(bind=engine) - eq_(2, len(meta.tables)) + eq_(3, len(meta.tables)) table = meta.tables["numbers"] eq_(5, len(table.columns)) eq_("number", table.columns[0].name) @@ -238,3 +263,40 @@ class User(Base): eq_(len(inserted_rows), len(selected_rows)) eq_(set(inserted_rows), set(selected_rows)) + + def test_cross_schema_fk_lookups(self, connection): + """Ensures we introspect FKs within & across schema.""" + + engine = connection.engine + + insp = inspect(engine) + eq_( + { + (None, "number_colors"): [ + { + "name": "number_fk", + "referred_table": "numbers", + "referred_schema": None, + "referred_columns": ["number"], + "constrained_columns": ["number_id"], + } + ] + }, + insp.get_multi_foreign_keys(filter_names=["number_colors"]), + ) + eq_( + { + ("schema", "number_colors"): [ + { + "name": "cross_schema_number_fk", + "referred_table": "numbers", + "referred_schema": None, + "referred_columns": ["number"], + "constrained_columns": ["number_id"], + } + ] + }, + insp.get_multi_foreign_keys( + filter_names=["number_colors"], schema="schema" + ), + ) From 8d34fb645745bbe94159b7923f7ed575be2e5830 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:19:03 +0200 Subject: [PATCH 482/582] chore(deps): update dependency zipp to v3.23.0 (#690) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f3e70edfa055..a79d92b24ef7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -584,9 +584,9 @@ wrapt==1.17.2 \ # via # deprecated # opentelemetry-instrumentation -zipp==3.22.0 \ - --hash=sha256:dd2f28c3ce4bc67507bfd3781d21b7bb2be31103b51a4553ad7d90b84e57ace5 \ - --hash=sha256:fe208f65f2aca48b81f9e6fd8cf7b8b32c26375266b009b413d45306b6148343 +zipp==3.23.0 \ + --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \ + --hash=sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166 # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be From 8520d26456f613e981a75e9e504963354d7bde5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 08:19:31 +0200 Subject: [PATCH 483/582] build(deps): bump requests from 2.32.3 to 2.32.4 (#692) Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/requirements.txt | 86 ++++++++++++++++---- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a79d92b24ef7..c39cbbbef249 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==6.0.0 \ - --hash=sha256:82e73ba88f7b30228b5507dce1a1f878498fc669d972aef2dde4f3a3c24f103e \ - --hash=sha256:f225782b84438f828328fc2ad74346522f27e5b1440f4e9fd18b20ebfd1aa2cf +cachetools==5.5.2 \ + --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ + --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth certifi==2025.4.26 \ --hash=sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6 \ @@ -122,7 +122,7 @@ click==8.2.1 \ # via # -r requirements.in # pip-tools -Deprecated==1.2.18 \ +deprecated==1.2.18 \ --hash=sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d \ --hash=sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec # via @@ -155,6 +155,62 @@ googleapis-common-protos[grpc]==1.70.0 \ # google-api-core # grpc-google-iam-v1 # grpcio-status +greenlet==3.2.3 \ + --hash=sha256:003c930e0e074db83559edc8705f3a2d066d4aa8c2f198aff1e454946efd0f26 \ + --hash=sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36 \ + --hash=sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892 \ + --hash=sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83 \ + --hash=sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688 \ + --hash=sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be \ + --hash=sha256:22eb5ba839c4b2156f18f76768233fe44b23a31decd9cc0d4cc8141c211fd1b4 \ + --hash=sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d \ + --hash=sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5 \ + --hash=sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b \ + --hash=sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb \ + --hash=sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86 \ + --hash=sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c \ + --hash=sha256:42efc522c0bd75ffa11a71e09cd8a399d83fafe36db250a87cf1dacfaa15dc64 \ + --hash=sha256:4532f0d25df67f896d137431b13f4cdce89f7e3d4a96387a41290910df4d3a57 \ + --hash=sha256:49c8cfb18fb419b3d08e011228ef8a25882397f3a859b9fe1436946140b6756b \ + --hash=sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad \ + --hash=sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95 \ + --hash=sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3 \ + --hash=sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147 \ + --hash=sha256:68671180e3849b963649254a882cd544a3c75bfcd2c527346ad8bb53494444db \ + --hash=sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb \ + --hash=sha256:72e77ed69312bab0434d7292316d5afd6896192ac4327d44f3d613ecb85b037c \ + --hash=sha256:731e154aba8e757aedd0781d4b240f1225b075b4409f1bb83b05ff410582cf00 \ + --hash=sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849 \ + --hash=sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba \ + --hash=sha256:761917cac215c61e9dc7324b2606107b3b292a8349bdebb31503ab4de3f559ac \ + --hash=sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822 \ + --hash=sha256:7e70ea4384b81ef9e84192e8a77fb87573138aa5d4feee541d8014e452b434da \ + --hash=sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97 \ + --hash=sha256:8324319cbd7b35b97990090808fdc99c27fe5338f87db50514959f8059999805 \ + --hash=sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34 \ + --hash=sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141 \ + --hash=sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3 \ + --hash=sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0 \ + --hash=sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b \ + --hash=sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365 \ + --hash=sha256:8c37ef5b3787567d322331d5250e44e42b58c8c713859b8a04c6065f27efbf72 \ + --hash=sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a \ + --hash=sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc \ + --hash=sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163 \ + --hash=sha256:96c20252c2f792defe9a115d3287e14811036d51e78b3aaddbee23b69b216302 \ + --hash=sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef \ + --hash=sha256:a433dbc54e4a37e4fff90ef34f25a8c00aed99b06856f0119dcf09fbafa16392 \ + --hash=sha256:aaa7aae1e7f75eaa3ae400ad98f8644bb81e1dc6ba47ce8a93d3f17274e08322 \ + --hash=sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d \ + --hash=sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264 \ + --hash=sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b \ + --hash=sha256:ce539fb52fb774d0802175d37fcff5c723e2c7d249c65916257f0a940cee8904 \ + --hash=sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf \ + --hash=sha256:d760f9bdfe79bff803bad32b4d8ffb2c1d2ce906313fc10a83976ffb73d64ca7 \ + --hash=sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a \ + --hash=sha256:efc6dc8a792243c31f2f5674b670b3a95d46fa1c6a912b8e310d6f542e7b0712 \ + --hash=sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728 + # via sqlalchemy grpc-google-iam-v1==0.14.2 \ --hash=sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351 \ --hash=sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20 @@ -229,11 +285,11 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.7.0 \ - --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ - --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd +importlib-metadata==8.6.1 \ + --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ + --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 # via opentelemetry-api -Mako==1.3.10 \ +mako==1.3.10 \ --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ --hash=sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59 # via alembic @@ -316,9 +372,9 @@ opentelemetry-sdk==1.34.1 \ --hash=sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e \ --hash=sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d # via -r requirements.in -opentelemetry-semantic-conventions==0.48b0 \ - --hash=sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a \ - --hash=sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f +opentelemetry-semantic-conventions==0.54b1 \ + --hash=sha256:29dab644a7e435b58d3a3918b58c333c92686236b30f7891d5e51f02933ca60d \ + --hash=sha256:d1cecedae15d19bdaafca1e56b29a66aa286f50b5d08f036a145c7f3e9ef9cee # via opentelemetry-sdk packaging==25.0 \ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ @@ -379,15 +435,15 @@ pyproject-hooks==1.2.0 \ # via # build # pip-tools -requests==2.32.3 \ - --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ - --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 +requests==2.32.4 \ + --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ + --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 # via google-api-core rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth -SQLAlchemy==2.0.41 \ +sqlalchemy==2.0.41 \ --hash=sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5 \ --hash=sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582 \ --hash=sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b \ From 0f0c1ac7a4e128603d807d951509c5c92f1ec562 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:23:33 +0200 Subject: [PATCH 484/582] chore(deps): update dependency certifi to v2025.6.15 (#696) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c39cbbbef249..b1bcd753ea0c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.5.2 \ --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth -certifi==2025.4.26 \ - --hash=sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6 \ - --hash=sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3 +certifi==2025.6.15 \ + --hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \ + --hash=sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b # via requests charset-normalizer==3.4.2 \ --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ From 8228fa10910671f4b8cadd199c8b3d6898f3496a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:29:32 +0200 Subject: [PATCH 485/582] chore(deps): update dependency urllib3 to v2.5.0 [security] (#700) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index b1bcd753ea0c..79a679a8cec7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -549,9 +549,9 @@ typing-extensions==4.14.0 \ # alembic # opentelemetry-sdk # sqlalchemy -urllib3==2.4.0 \ - --hash=sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466 \ - --hash=sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813 +urllib3==2.5.0 \ + --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ + --hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc # via requests wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ From 85f5004f15a947a66c95ebf64dc3fc2aa414829e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 08:29:50 +0200 Subject: [PATCH 486/582] chore(deps): update dependency alembic to v1.16.2 (#701) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 79a679a8cec7..6b13caad7a75 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.16.1 \ - --hash=sha256:0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67 \ - --hash=sha256:43d37ba24b3d17bc1eb1024fe0f51cd1dc95aeb5464594a02c6bb9ca9864bfa4 +alembic==1.16.2 \ + --hash=sha256:5f42e9bd0afdbd1d5e3ad856c01754530367debdebf21ed6894e34af52b3bb03 \ + --hash=sha256:e53c38ff88dadb92eb22f8b150708367db731d58ad7e9d417c9168ab516cbed8 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From 2ca75ff6575f39005d34f7eb0d8bb0b9114a0858 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 09:29:55 +0200 Subject: [PATCH 487/582] chore(deps): update dependency importlib-metadata to v8.7.0 (#704) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6b13caad7a75..f2570f81444e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -285,9 +285,9 @@ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # via requests -importlib-metadata==8.6.1 \ - --hash=sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e \ - --hash=sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580 +importlib-metadata==8.7.0 \ + --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ + --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd # via opentelemetry-api mako==1.3.10 \ --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ From c9d38dce00cc001efe6953b8bf01aef2e646053e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 20 Jun 2025 10:40:42 +0200 Subject: [PATCH 488/582] chore(deps): update dependency cachetools to v6 (#702) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f2570f81444e..287e4926ce3e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==5.5.2 \ - --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ - --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a +cachetools==6.1.0 \ + --hash=sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e \ + --hash=sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587 # via google-auth certifi==2025.6.15 \ --hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \ From 6fe973553ee6e7fb0f6ad3c20480fb93b76f476a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:50:23 +0200 Subject: [PATCH 489/582] chore(main): release 1.13.1 (#705) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index b56111be1485..44e1517b98d8 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.13.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.13.0...v1.13.1) (2025-06-20) + + +### Bug Fixes + +* Support retrieval of cross-schema foreign keys ([ef07a1f](https://github.com/googleapis/python-spanner-sqlalchemy/commit/ef07a1f55736eae9751f85fef66599fdfa21bcd4)), closes [#638](https://github.com/googleapis/python-spanner-sqlalchemy/issues/638) + ## [1.13.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.12.0...v1.13.0) (2025-06-05) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index bde8e01493a7..7628b0ec9c9b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.13.0" +__version__ = "1.13.1" From cba2b49dfcf4e9830be7b338acafaef52cefe45a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 27 Jun 2025 12:16:08 +0200 Subject: [PATCH 490/582] chore(deps): update dependency grpcio to v1.73.1 (#707) --- packages/sqlalchemy-spanner/requirements.txt | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 287e4926ce3e..8818a8df3e18 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -219,58 +219,58 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.73.0 \ - --hash=sha256:068ecc415f79408d57a7f146f54cdf9f0acb4b301a52a9e563973dc981e82f3d \ - --hash=sha256:072d8154b8f74300ed362c01d54af8b93200c1a9077aeaea79828d48598514f1 \ - --hash=sha256:07ad7c57233c2109e4ac999cb9c2710c3b8e3f491a73b058b0ce431f31ed8145 \ - --hash=sha256:085ebe876373ca095e24ced95c8f440495ed0b574c491f7f4f714ff794bbcd10 \ - --hash=sha256:0e092a4b28eefb63eec00d09ef33291cd4c3a0875cde29aec4d11d74434d222c \ - --hash=sha256:0eb5df4f41ea10bda99a802b2a292d85be28958ede2a50f2beb8c7fc9a738419 \ - --hash=sha256:10e8edc035724aba0346a432060fd192b42bd03675d083c01553cab071a28da5 \ - --hash=sha256:12787c791c3993d0ea1cc8bf90393647e9a586066b3b322949365d2772ba965b \ - --hash=sha256:1284850607901cfe1475852d808e5a102133461ec9380bc3fc9ebc0686ee8e32 \ - --hash=sha256:128ba2ebdac41e41554d492b82c34586a90ebd0766f8ebd72160c0e3a57b9155 \ - --hash=sha256:1dd7fa7276dcf061e2d5f9316604499eea06b1b23e34a9380572d74fe59915a8 \ - --hash=sha256:275e23d4c428c26b51857bbd95fcb8e528783597207ec592571e4372b300a29f \ - --hash=sha256:2a9c957dc65e5d474378d7bcc557e9184576605d4b4539e8ead6e351d7ccce20 \ - --hash=sha256:2c17771e884fddf152f2a0df12478e8d02853e5b602a10a9a9f1f52fa02b1d32 \ - --hash=sha256:2d1510c4ea473110cb46a010555f2c1a279d1c256edb276e17fa571ba1e8927c \ - --hash=sha256:33577fe7febffe8ebad458744cfee8914e0c10b09f0ff073a6b149a84df8ab8f \ - --hash=sha256:36bf93f6a657f37c131d9dd2c391b867abf1426a86727c3575393e9e11dadb0d \ - --hash=sha256:38cf518cc54cd0c47c9539cefa8888549fcc067db0b0c66a46535ca8032020c4 \ - --hash=sha256:3902b71407d021163ea93c70c8531551f71ae742db15b66826cf8825707d2908 \ - --hash=sha256:3af4c30918a7f0d39de500d11255f8d9da4f30e94a2033e70fe2a720e184bd8e \ - --hash=sha256:483c507c2328ed0e01bc1adb13d1eada05cc737ec301d8e5a8f4a90f387f1790 \ - --hash=sha256:4dd8d8d092efede7d6f48d695ba2592046acd04ccf421436dd7ed52677a9ad29 \ - --hash=sha256:51036f641f171eebe5fa7aaca5abbd6150f0c338dab3a58f9111354240fe36ec \ - --hash=sha256:60813d8a16420d01fa0da1fc7ebfaaa49a7e5051b0337cd48f4f950eb249a08e \ - --hash=sha256:6228f7eb6d9f785f38b589d49957fca5df3d5b5349e77d2d89b14e390165344c \ - --hash=sha256:6ddc1cfb2240f84d35d559ade18f69dcd4257dbaa5ba0de1a565d903aaab2968 \ - --hash=sha256:70176093d0a95b44d24baa9c034bb67bfe2b6b5f7ebc2836f4093c97010e17fd \ - --hash=sha256:859f70c8e435e8e1fa060e04297c6818ffc81ca9ebd4940e180490958229a45a \ - --hash=sha256:965a16b71a8eeef91fc4df1dc40dc39c344887249174053814f8a8e18449c4c3 \ - --hash=sha256:9ffc972b530bf73ef0f948f799482a1bf12d9b6f33406a8e6387c0ca2098a833 \ - --hash=sha256:a73c72922dfd30b396a5f25bb3a4590195ee45ecde7ee068acb0892d2900cf07 \ - --hash=sha256:b71a7b4483d1f753bbc11089ff0f6fa63b49c97a9cc20552cded3fcad466d23b \ - --hash=sha256:bbf45d59d090bf69f1e4e1594832aaf40aa84b31659af3c5e2c3f6a35202791a \ - --hash=sha256:c0811331b469e3f15dda5f90ab71bcd9681189a83944fd6dc908e2c9249041ef \ - --hash=sha256:c201a34aa960c962d0ce23fe5f423f97e9d4b518ad605eae6d0a82171809caaa \ - --hash=sha256:c98ba1d928a178ce33f3425ff823318040a2b7ef875d30a0073565e5ceb058d9 \ - --hash=sha256:ce953d9d2100e1078a76a9dc2b7338d5415924dc59c69a15bf6e734db8a0f1ca \ - --hash=sha256:cfc556c1d6aef02c727ec7d0016827a73bfe67193e47c546f7cadd3ee6bf1a60 \ - --hash=sha256:d050197eeed50f858ef6c51ab09514856f957dba7b1f7812698260fc9cc417f6 \ - --hash=sha256:d0a1517b2005ba1235a1190b98509264bf72e231215dfeef8db9a5a92868789e \ - --hash=sha256:d12bbb88381ea00bdd92c55aff3da3391fd85bc902c41275c8447b86f036ce0f \ - --hash=sha256:d84000367508ade791d90c2bafbd905574b5ced8056397027a77a215d601ba15 \ - --hash=sha256:da1d677018ef423202aca6d73a8d3b2cb245699eb7f50eb5f74cae15a8e1f724 \ - --hash=sha256:e0084d4559ee3dbdcce9395e1bc90fdd0262529b32c417a39ecbc18da8074ac7 \ - --hash=sha256:e2459a27c6886e7e687e4e407778425f3c6a971fa17a16420227bda39574d64b \ - --hash=sha256:e53007f70d9783f53b41b4cf38ed39a8e348011437e4c287eee7dd1d39d54b2f \ - --hash=sha256:ebb8d5f4b0200916fb292a964a4d41210de92aba9007e33d8551d85800ea16cb \ - --hash=sha256:ebd8d269df64aff092b2cec5e015d8ae09c7e90888b5c35c24fdca719a2c9f35 \ - --hash=sha256:ef5fff73d5f724755693a464d444ee0a448c6cdfd3c1616a9223f736c622617d \ - --hash=sha256:f5cdc332b503c33b1643b12ea933582c7b081957c8bc2ea4cc4bc58054a09288 \ - --hash=sha256:fb9d7c27089d9ba3746f18d2109eb530ef2a37452d2ff50f5a6696cd39167d3b +grpcio==1.73.1 \ + --hash=sha256:052e28fe9c41357da42250a91926a3e2f74c046575c070b69659467ca5aa976b \ + --hash=sha256:07f08705a5505c9b5b0cbcbabafb96462b5a15b7236bbf6bbcc6b0b91e1cbd7e \ + --hash=sha256:0a9f3ea8dce9eae9d7cb36827200133a72b37a63896e0e61a9d5ec7d61a59ab1 \ + --hash=sha256:0ab860d5bfa788c5a021fba264802e2593688cd965d1374d31d2b1a34cacd854 \ + --hash=sha256:105492124828911f85127e4825d1c1234b032cb9d238567876b5515d01151379 \ + --hash=sha256:10af9f2ab98a39f5b6c1896c6fc2036744b5b41d12739d48bed4c3e15b6cf900 \ + --hash=sha256:1c0bf15f629b1497436596b1cbddddfa3234273490229ca29561209778ebe182 \ + --hash=sha256:1c502c2e950fc7e8bf05c047e8a14522ef7babac59abbfde6dbf46b7a0d9c71e \ + --hash=sha256:24e06a5319e33041e322d32c62b1e728f18ab8c9dbc91729a3d9f9e3ed336642 \ + --hash=sha256:277b426a0ed341e8447fbf6c1d6b68c952adddf585ea4685aa563de0f03df887 \ + --hash=sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55 \ + --hash=sha256:303c8135d8ab176f8038c14cc10d698ae1db9c480f2b2823f7a987aa2a4c5646 \ + --hash=sha256:3841a8a5a66830261ab6a3c2a3dc539ed84e4ab019165f77b3eeb9f0ba621f26 \ + --hash=sha256:42f0660bce31b745eb9d23f094a332d31f210dcadd0fc8e5be7e4c62a87ce86b \ + --hash=sha256:45cf17dcce5ebdb7b4fe9e86cb338fa99d7d1bb71defc78228e1ddf8d0de8cbb \ + --hash=sha256:4a68f8c9966b94dff693670a5cf2b54888a48a5011c5d9ce2295a1a1465ee84f \ + --hash=sha256:5b9b1805a7d61c9e90541cbe8dfe0a593dfc8c5c3a43fe623701b6a01b01d710 \ + --hash=sha256:610e19b04f452ba6f402ac9aa94eb3d21fbc94553368008af634812c4a85a99e \ + --hash=sha256:628c30f8e77e0258ab788750ec92059fc3d6628590fb4b7cea8c102503623ed7 \ + --hash=sha256:65b0458a10b100d815a8426b1442bd17001fdb77ea13665b2f7dc9e8587fdc6b \ + --hash=sha256:67a0468256c9db6d5ecb1fde4bf409d016f42cef649323f0a08a72f352d1358b \ + --hash=sha256:686231cdd03a8a8055f798b2b54b19428cdf18fa1549bee92249b43607c42668 \ + --hash=sha256:68b84d65bbdebd5926eb5c53b0b9ec3b3f83408a30e4c20c373c5337b4219ec5 \ + --hash=sha256:6957025a4608bb0a5ff42abd75bfbb2ed99eda29d5992ef31d691ab54b753643 \ + --hash=sha256:6a2b372e65fad38842050943f42ce8fee00c6f2e8ea4f7754ba7478d26a356ee \ + --hash=sha256:6a6037891cd2b1dd1406b388660522e1565ed340b1fea2955b0234bdd941a862 \ + --hash=sha256:6abfc0f9153dc4924536f40336f88bd4fe7bd7494f028675e2e04291b8c2c62a \ + --hash=sha256:75fc8e543962ece2f7ecd32ada2d44c0c8570ae73ec92869f9af8b944863116d \ + --hash=sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87 \ + --hash=sha256:83a6c2cce218e28f5040429835fa34a29319071079e3169f9543c3fbeff166d2 \ + --hash=sha256:89018866a096e2ce21e05eabed1567479713ebe57b1db7cbb0f1e3b896793ba4 \ + --hash=sha256:8f5a6df3fba31a3485096ac85b2e34b9666ffb0590df0cd044f58694e6a1f6b5 \ + --hash=sha256:921b25618b084e75d424a9f8e6403bfeb7abef074bb6c3174701e0f2542debcf \ + --hash=sha256:96c112333309493c10e118d92f04594f9055774757f5d101b39f8150f8c25582 \ + --hash=sha256:ad1d958c31cc91ab050bd8a91355480b8e0683e21176522bacea225ce51163f2 \ + --hash=sha256:ad5c958cc3d98bb9d71714dc69f1c13aaf2f4b53e29d4cc3f1501ef2e4d129b2 \ + --hash=sha256:b310824ab5092cf74750ebd8a8a8981c1810cb2b363210e70d06ef37ad80d4f9 \ + --hash=sha256:b3215f69a0670a8cfa2ab53236d9e8026bfb7ead5d4baabe7d7dc11d30fda967 \ + --hash=sha256:b4adc97d2d7f5c660a5498bda978ebb866066ad10097265a5da0511323ae9f50 \ + --hash=sha256:ba2cea9f7ae4bc21f42015f0ec98f69ae4179848ad744b210e7685112fa507a1 \ + --hash=sha256:bc5eccfd9577a5dc7d5612b2ba90cca4ad14c6d949216c68585fdec9848befb1 \ + --hash=sha256:c45a28a0cfb6ddcc7dc50a29de44ecac53d115c3388b2782404218db51cb2df3 \ + --hash=sha256:c54796ca22b8349cc594d18b01099e39f2b7ffb586ad83217655781a350ce4da \ + --hash=sha256:cce7265b9617168c2d08ae570fcc2af4eaf72e84f8c710ca657cc546115263af \ + --hash=sha256:d60588ab6ba0ac753761ee0e5b30a29398306401bfbceffe7d68ebb21193f9d4 \ + --hash=sha256:d74c3f4f37b79e746271aa6cdb3a1d7e4432aea38735542b23adcabaaee0c097 \ + --hash=sha256:dc7d7fd520614fce2e6455ba89791458020a39716951c7c07694f9dbae28e9c0 \ + --hash=sha256:de18769aea47f18e782bf6819a37c1c528914bfd5683b8782b9da356506190c8 \ + --hash=sha256:ed451a0e39c8e51eb1612b78686839efd1a920666d1666c1adfdb4fd51680c0f \ + --hash=sha256:f43ffb3bd415c57224c7427bfb9e6c46a0b6e998754bfa0d00f408e1873dcbb5 \ + --hash=sha256:f48e862aed925ae987eb7084409a80985de75243389dc9d9c271dd711e589918 # via # google-api-core # googleapis-common-protos From fe7f312a8404c7ec3f28110ec2c7e28f380ea424 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 27 Jun 2025 12:32:20 +0200 Subject: [PATCH 491/582] chore(deps): update dependency grpcio-status to v1.73.1 (#708) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8818a8df3e18..a4f6d24f210e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -277,9 +277,9 @@ grpcio==1.73.1 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.73.0 \ - --hash=sha256:a2b7f430568217f884fe52a5a0133b6f4c9338beae33fb5370134a8eaf58f974 \ - --hash=sha256:a3f3a9994b44c364f014e806114ba44cc52e50c426779f958c8b22f14ff0d892 +grpcio-status==1.73.1 \ + --hash=sha256:538595c32a6c819c32b46a621a51e9ae4ffcd7e7e1bce35f728ef3447e9809b6 \ + --hash=sha256:928f49ccf9688db5f20cd9e45c4578a1d01ccca29aeaabf066f2ac76aa886668 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From e55408e9810d6fe1eb90551e4a78f5582194c39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 27 Jun 2025 12:49:33 +0200 Subject: [PATCH 492/582] chore: make the fk query joins consistent (#703) --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index aa6ee2b5ad24..3c6038243a9f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1481,11 +1481,11 @@ def get_multi_foreign_keys( ) FROM information_schema.table_constraints AS tc JOIN information_schema.constraint_column_usage AS ccu - ON ccu.table_catalog = tc.table_catalog + ON ccu.constraint_catalog = tc.table_catalog and ccu.constraint_schema = tc.table_schema and ccu.constraint_name = tc.constraint_name JOIN information_schema.constraint_table_usage AS ctu - ON ctu.table_catalog = tc.table_catalog + ON ctu.constraint_catalog = tc.table_catalog and ctu.constraint_schema = tc.table_schema and ctu.constraint_name = tc.constraint_name JOIN information_schema.key_column_usage AS kcu From bff3d7381cce242051f6671efdabe53400f4d58c Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 27 Jun 2025 08:35:31 -0400 Subject: [PATCH 493/582] feat: Support Server-Side Checks for Enums (#694) Spanner uses protos for enums. Creating a column like Column("an_enum", Enum("A", "B", "C")) will result in a String column. Setting supports_native_enum to False allows SQLAlchemy to generate check constraints to enforce the enum values if the create_constraint=True flag is passed to the Enum constructor. Fixes: #686 --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 7 ++++++- .../test/mockserver_tests/test_basics.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 3c6038243a9f..e59f26d8790a 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -807,10 +807,15 @@ class SpannerDialect(DefaultDialect): supports_sequences = True sequences_optional = False supports_identity_columns = True - supports_native_enum = True supports_native_boolean = True supports_native_decimal = True supports_statement_cache = True + # Spanner uses protos for enums. Creating a column like + # Column("an_enum", Enum("A", "B", "C")) will result in a String + # column. Setting supports_native_enum to False allows SQLAlchemy + # to generate check constraints to enforce the enum values if the + # create_constraint=True flag is passed to the Enum constructor. + supports_native_enum = False postfetch_lastrowid = False insert_returning = True diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 3e422885b2ed..7d40e874ab90 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -27,6 +27,7 @@ func, text, BigInteger, + Enum, ) from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.testing import eq_, is_instance_of @@ -120,6 +121,7 @@ def test_create_table(self): metadata, Column("user_id", Integer, primary_key=True), Column("user_name", String(16), nullable=False), + Column("status", Enum("a", "b", "cee", create_constraint=True)), ) metadata.create_all(engine) requests = self.database_admin_service.requests @@ -130,7 +132,9 @@ def test_create_table(self): "CREATE TABLE users (\n" "\tuser_id INT64 NOT NULL " "GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE), \n" - "\tuser_name STRING(16) NOT NULL\n" + "\tuser_name STRING(16) NOT NULL, \n" + "\tstatus STRING(3), \n" + "\tCHECK (status IN ('a', 'b', 'cee'))\n" ") PRIMARY KEY (user_id)", requests[0].statements[0], ) From 0f55b6df32c06e77584b96c01f456d89fd3f337e Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 27 Jun 2025 08:35:42 -0400 Subject: [PATCH 494/582] feat: support commit timestamp option (#697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support commit timestamp option Add support for columns with commit timestamps: https://cloud.google.com/spanner/docs/commit-timestamp Fixes: #695 * chore: use Singer in sample --------- Co-authored-by: Knut Olav LΓΈite --- packages/sqlalchemy-spanner/README.rst | 16 +++++ .../sqlalchemy_spanner/sqlalchemy_spanner.py | 5 ++ packages/sqlalchemy-spanner/samples/model.py | 17 +++++ .../commit_timestamp_model.py | 32 ++++++++++ .../mockserver_tests/test_commit_timestamp.py | 64 +++++++++++++++++++ .../test/system/test_basics.py | 58 ++++++++++++++++- 6 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/commit_timestamp_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py diff --git a/packages/sqlalchemy-spanner/README.rst b/packages/sqlalchemy-spanner/README.rst index 3e08970f99ec..ae8a3109ffcd 100644 --- a/packages/sqlalchemy-spanner/README.rst +++ b/packages/sqlalchemy-spanner/README.rst @@ -234,6 +234,22 @@ tables with this feature, make sure to call ``add_is_dependent_on()`` on the child table to request SQLAlchemy to create the parent table before the child table. +Commit timestamps +~~~~~~~~~~~~~~~~~~ + +The dialect offers the ``spanner_allow_commit_timestamp`` option to +column constructors for creating commit timestamp columns. + +.. code:: python + + Table( + "table", + metadata, + Column("last_update_time", DateTime, spanner_allow_commit_timestamp=True), + ) + +`See this documentation page for more details `__. + Unique constraints ~~~~~~~~~~~~~~~~~~ diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e59f26d8790a..c34ec0b02cf1 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -578,6 +578,11 @@ def get_column_specification(self, column, **kwargs): elif hasattr(column, "computed") and column.computed is not None: colspec += " " + self.process(column.computed) + if column.dialect_options.get("spanner", {}).get( + "allow_commit_timestamp", False + ): + colspec += " OPTIONS (allow_commit_timestamp=true)" + return colspec def visit_computed_column(self, generated, **kw): diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index 2b231ca6230f..c7c683011e8b 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -33,6 +33,8 @@ TextClause, Index, PickleType, + text, + event, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from google.cloud.sqlalchemy_spanner.sqlalchemy_spanner import SpannerPickleType @@ -177,3 +179,18 @@ class TicketSale(Base): DateTime, nullable=False ) singer_id: Mapped[str] = mapped_column(String(36), ForeignKey("singers.id")) + # Create a commit timestamp column and set a client-side default of + # PENDING_COMMIT_TIMESTAMP() An event handler below is responsible for + # setting PENDING_COMMIT_TIMESTAMP() on updates. If using SQLAlchemy + # core rather than the ORM, callers will need to supply their own + # PENDING_COMMIT_TIMESTAMP() values in their inserts & updates. + last_update_time: Mapped[datetime.datetime] = mapped_column( + spanner_allow_commit_timestamp=True, + default=text("PENDING_COMMIT_TIMESTAMP()"), + ) + + +@event.listens_for(TicketSale, "before_update") +def ticket_sale_before_update(mapper, connection, target): + """Updates the commit timestamp when the row is updated.""" + target.last_update_time = text("PENDING_COMMIT_TIMESTAMP()") diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/commit_timestamp_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/commit_timestamp_model.py new file mode 100644 index 000000000000..28c58b8668d3 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/commit_timestamp_model.py @@ -0,0 +1,32 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime + +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[str] = mapped_column(primary_key=True) + name: Mapped[str] + updated_at: Mapped[datetime.datetime] = mapped_column( + spanner_allow_commit_timestamp=True + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py new file mode 100644 index 000000000000..3872bde1d3c0 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py @@ -0,0 +1,64 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest + + +class TestCommitTimestamp(MockServerTestBase): + def test_create_table(self): + from test.mockserver_tests.commit_timestamp_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true + FROM INFORMATION_SCHEMA.SEQUENCES + WHERE NAME="singer_id" + AND SCHEMA="" + LIMIT 1""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid STRING(MAX) NOT NULL, \n" + "\tname STRING(MAX) NOT NULL, \n" + "\tupdated_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index bb2ae9a80eb5..7ea6fa2bda5d 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import datetime import os from typing import Optional from sqlalchemy import ( @@ -29,10 +30,11 @@ select, update, delete, + event, ) from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.types import REAL -from sqlalchemy.testing import eq_, is_true +from sqlalchemy.testing import eq_, is_true, is_not_none from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -300,3 +302,57 @@ def test_cross_schema_fk_lookups(self, connection): filter_names=["number_colors"], schema="schema" ), ) + + def test_commit_timestamp(self, connection): + """Ensures commit timestamps are set.""" + + class Base(DeclarativeBase): + pass + + class TimestampUser(Base): + __tablename__ = "timestamp_users" + ID: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] + updated_at: Mapped[datetime.datetime] = mapped_column( + spanner_allow_commit_timestamp=True, + default=text("PENDING_COMMIT_TIMESTAMP()"), + ) + + @event.listens_for(TimestampUser, "before_update") + def before_update(mapper, connection, target): + target.updated_at = text("PENDING_COMMIT_TIMESTAMP()") + + engine = connection.engine + Base.metadata.create_all(engine) + try: + with Session(engine) as session: + session.add(TimestampUser(name="name")) + session.commit() + + with Session(engine) as session: + users = list( + session.scalars( + select(TimestampUser).where(TimestampUser.name == "name") + ) + ) + user = users[0] + + is_not_none(user.updated_at) + created_at = user.updated_at + + user.name = "new-name" + session.commit() + + with Session(engine) as session: + users = list( + session.scalars( + select(TimestampUser).where(TimestampUser.name == "new-name") + ) + ) + user = users[0] + + is_not_none(user.updated_at) + is_true(user.updated_at > created_at) + + finally: + Base.metadata.drop_all(engine) From 9530ad4ba6cf4f9ce88969059d8093c9ff67cbea Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Fri, 27 Jun 2025 08:35:53 -0400 Subject: [PATCH 495/582] bug: don't rollback non-spanner connections on reset (#709) This is the simplest way to address bug #706 and address the `AttributeError: 'Connection' object has no attribute 'rollback'` I'm seeing when connections from BigQuery engines get caught by this event handler. I think we should be able to rely on SQLAlchemy's [reset on return](https://docs.sqlalchemy.org/en/20/core/pooling.html#reset-on-return) behaviour to rollback transactions when they're reset rather than call rollback ourselves. That behaviour is also something end users can configure, so it'd be good to respect their settings if they disable the behaviour. Fixes: #706 --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index c34ec0b02cf1..d868daf94079 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -71,8 +71,6 @@ def reset_connection(dbapi_conn, connection_record, reset_state=None): dbapi_conn.staleness = None dbapi_conn.read_only = False - else: - dbapi_conn.rollback() # register a method to get a single value of a JSON object From e3ac8e7c5808b6a1689402636ce37dd44776265b Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:37:15 +0200 Subject: [PATCH 496/582] chore(main): release 1.14.0 (#710) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 44e1517b98d8..fc7918b08214 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.14.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.13.1...v1.14.0) (2025-06-27) + + +### Features + +* Support commit timestamp option ([#697](https://github.com/googleapis/python-spanner-sqlalchemy/issues/697)) ([82bb8ed](https://github.com/googleapis/python-spanner-sqlalchemy/commit/82bb8ed583a5fd91c8a10fb73c85a6a5f45269f6)) + ## [1.13.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.13.0...v1.13.1) (2025-06-20) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index 7628b0ec9c9b..af1f26ba58a4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.13.1" +__version__ = "1.14.0" From 006289e5f55f3cf58b0533a8939a75d8bbefadce Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Fri, 15 Aug 2025 11:01:12 +0200 Subject: [PATCH 497/582] chore(deps): update dependency google-cloud-spanner to v3.56.0 (#722) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update dependency google-cloud-spanner to v3.56.0 * chore: update tests for mux session usage --------- Co-authored-by: Knut Olav LΓΈite --- .../.github/workflows/test_suite.yml | 6 +-- packages/sqlalchemy-spanner/.gitignore | 4 +- packages/sqlalchemy-spanner/requirements.txt | 46 ++++++++-------- .../samples/sample_helper.py | 2 +- .../mockserver_tests/mock_server_test_base.py | 16 +++--- .../mockserver_tests/test_auto_increment.py | 31 +++-------- .../test/mockserver_tests/test_basics.py | 52 ++++++------------- .../test_bit_reversed_sequence.py | 16 ++---- .../mockserver_tests/test_commit_timestamp.py | 11 +--- .../test/mockserver_tests/test_float32.py | 4 +- .../mockserver_tests/test_isolation_level.py | 28 ++++------ .../test/mockserver_tests/test_json.py | 22 +++----- .../test/mockserver_tests/test_pickle_type.py | 16 ++---- .../test/mockserver_tests/test_quickstart.py | 4 +- .../test_read_only_transaction.py | 13 ++--- .../test/mockserver_tests/test_stale_reads.py | 21 +++----- .../test/mockserver_tests/test_tags.py | 19 +++---- .../sqlalchemy-spanner/test/test_suite_20.py | 11 ++++ 18 files changed, 117 insertions(+), 205 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 23f28e197e37..6ffc17d25806 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -74,7 +74,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 @@ -98,7 +98,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 @@ -123,7 +123,7 @@ jobs: services: emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest + image: gcr.io/cloud-spanner-emulator/emulator ports: - 9010:9010 diff --git a/packages/sqlalchemy-spanner/.gitignore b/packages/sqlalchemy-spanner/.gitignore index 6cb13eed1d7e..e62c347963fa 100644 --- a/packages/sqlalchemy-spanner/.gitignore +++ b/packages/sqlalchemy-spanner/.gitignore @@ -48,6 +48,7 @@ docs/_build docs.metadata # Virtual environment +.venv/ env/ coverage.xml sponge_log.xml @@ -59,4 +60,5 @@ system_tests/local_test_setup pylintrc pylintrc.test -test.cfg \ No newline at end of file +test.cfg +database diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a4f6d24f210e..0894601a78ba 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.2.2.post1 \ # via # -r requirements.in # pip-tools -cachetools==6.1.0 \ - --hash=sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e \ - --hash=sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587 +cachetools==5.5.2 \ + --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ + --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth certifi==2025.6.15 \ --hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \ @@ -144,9 +144,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.55.0 \ - --hash=sha256:bec170c6619f667cc657e977f87391d76975559be70b155d90a2902613662b3c \ - --hash=sha256:fc9f717b612924f5e9bfae9514aa0d5cd30e6b40e8d472d030f84b16de2c18fe +google-cloud-spanner==3.57.0 \ + --hash=sha256:5b10b40bc646091f1b4cbb2e7e2e82ec66bcce52c7105f86b65070d34d6df86f \ + --hash=sha256:73f52f58617449fcff7073274a7f7a798f4f7b2788eda26de3b7f98ad857ab99 # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ @@ -372,9 +372,9 @@ opentelemetry-sdk==1.34.1 \ --hash=sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e \ --hash=sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d # via -r requirements.in -opentelemetry-semantic-conventions==0.54b1 \ - --hash=sha256:29dab644a7e435b58d3a3918b58c333c92686236b30f7891d5e51f02933ca60d \ - --hash=sha256:d1cecedae15d19bdaafca1e56b29a66aa286f50b5d08f036a145c7f3e9ef9cee +opentelemetry-semantic-conventions==0.55b1 \ + --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ + --hash=sha256:ef95b1f009159c28d7a7849f5cbc71c4c34c845bb514d66adfdf1b3fff3598b3 # via opentelemetry-sdk packaging==25.0 \ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ @@ -396,18 +396,16 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==5.29.5 \ - --hash=sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079 \ - --hash=sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc \ - --hash=sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353 \ - --hash=sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61 \ - --hash=sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5 \ - --hash=sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736 \ - --hash=sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e \ - --hash=sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84 \ - --hash=sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671 \ - --hash=sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238 \ - --hash=sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015 +protobuf==6.32.0 \ + --hash=sha256:15eba1b86f193a407607112ceb9ea0ba9569aed24f93333fe9a497cf2fda37d3 \ + --hash=sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1 \ + --hash=sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c \ + --hash=sha256:7db8ed09024f115ac877a1427557b838705359f047b2ff2f2b2364892d19dacb \ + --hash=sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741 \ + --hash=sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2 \ + --hash=sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e \ + --hash=sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783 \ + --hash=sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0 # via # google-api-core # google-cloud-spanner @@ -547,7 +545,9 @@ typing-extensions==4.14.0 \ --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af # via # alembic + # opentelemetry-api # opentelemetry-sdk + # opentelemetry-semantic-conventions # sqlalchemy urllib3==2.5.0 \ --hash=sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760 \ @@ -637,9 +637,7 @@ wrapt==1.17.2 \ --hash=sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119 \ --hash=sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b \ --hash=sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58 - # via - # deprecated - # opentelemetry-instrumentation + # via opentelemetry-instrumentation zipp==3.23.0 \ --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \ --hash=sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166 diff --git a/packages/sqlalchemy-spanner/samples/sample_helper.py b/packages/sqlalchemy-spanner/samples/sample_helper.py index 862d535d3bae..b1c068f8cf7c 100644 --- a/packages/sqlalchemy-spanner/samples/sample_helper.py +++ b/packages/sqlalchemy-spanner/samples/sample_helper.py @@ -49,7 +49,7 @@ def start_emulator() -> (DockerContainer, str): ).with_exposed_ports(9010) emulator.start() wait_for_logs(emulator, "gRPC server listening at 0.0.0.0:9010") - port = emulator.get_exposed_port(9010) + port = str(emulator.get_exposed_port(9010)) _create_instance_and_database(port) return emulator, port diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py index a8fea8192438..6cdf97337e58 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/mock_server_test_base.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import logging from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import Engine, create_engine @@ -22,7 +23,6 @@ from google.cloud.spanner_v1 import ( Client, ResultSet, - PingingPool, TypeCode, ) from google.cloud.spanner_v1.database import Database @@ -131,9 +131,12 @@ class MockServerTestBase(fixtures.TestBase): spanner_service: SpannerServicer = None database_admin_service: DatabaseAdminServicer = None port: int = None + logger: logging.Logger = None @classmethod def setup_class(cls): + MockServerTestBase.logger = logging.getLogger("level warning") + MockServerTestBase.logger.setLevel(logging.WARN) ( MockServerTestBase.server, MockServerTestBase.spanner_service, @@ -151,6 +154,7 @@ def setup_method(self): self._client = None self._instance = None self._database = None + _ = self.database def teardown_method(self): MockServerTestBase.spanner_service.clear_requests() @@ -159,7 +163,7 @@ def teardown_method(self): def create_engine(self) -> Engine: return create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, ) @property @@ -177,13 +181,13 @@ def client(self) -> Client: @property def instance(self) -> Instance: if self._instance is None: - self._instance = self.client.instance("test-instance") + self._instance = self.client.instance("i") return self._instance @property def database(self) -> Database: + logger = logging.getLogger("level warning") + logger.setLevel(logging.WARN) if self._database is None: - self._database = self.instance.database( - "test-database", pool=PingingPool(size=10) - ) + self._database = self.instance.database("d", logger=logger) return self._database diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py index 7fa245e822c3..9e8051dbde7c 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_auto_increment.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -45,10 +43,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -74,10 +69,7 @@ def test_create_auto_increment_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() engine.dialect.use_auto_increment = True Base.metadata.create_all(engine) requests = self.database_admin_service.requests @@ -103,10 +95,7 @@ def test_create_table_with_specific_sequence_kind(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() engine.dialect.default_sequence_kind = "non_existing_kind" Base.metadata.create_all(engine) requests = self.database_admin_service.requests @@ -126,10 +115,7 @@ def test_insert_row(self): from test.mockserver_tests.auto_increment_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -141,7 +127,7 @@ def test_insert_row(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) @@ -152,10 +138,7 @@ def test_insert_row_with_pk_value(self): # SQLAlchemy should not use a THEN RETURN clause when a value for the # primary key has been set on the model. add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: # Manually specify a value for the primary key. diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py index 7d40e874ab90..3e6c2fe02737 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_basics.py @@ -13,6 +13,7 @@ # limitations under the License. import datetime + from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest from google.cloud.spanner_dbapi.parsed_statement import AutocommitDmlMode from sqlalchemy import ( @@ -32,11 +33,9 @@ from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, ResultSet, - PingingPool, TypeCode, ) from test.mockserver_tests.mock_server_test_base import ( @@ -58,7 +57,7 @@ def verify_select1(self, results): eq_(1, len(result_list)) requests = self.spanner_service.requests eq_(2, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) def test_select1(self): @@ -69,10 +68,7 @@ def test_select1(self): def test_sqlalchemy_select1(self): add_select1_result() - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, - ) + engine = self.create_engine() with engine.connect().execution_options( isolation_level="AUTOCOMMIT" ) as connection: @@ -92,10 +88,7 @@ def test_sqlalchemy_select_now(self): TypeCode.TIMESTAMP, [(iso_now,)], ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": PingingPool(size=10)}, - ) + engine = self.create_engine() with engine.connect().execution_options( isolation_level="AUTOCOMMIT" ) as connection: @@ -111,10 +104,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() Table( "users", @@ -148,10 +138,7 @@ def test_create_table_in_schema(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() Table( "users", @@ -190,10 +177,7 @@ def test_create_multiple_tables(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() metadata = MetaData() for i in range(2): Table( @@ -224,7 +208,7 @@ def test_partitioned_dml(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": PingingPool(size=10), + "logger": MockServerTestBase.logger, "ignore_transaction_warnings": True, }, ) @@ -258,10 +242,7 @@ class Singer(Base): update = "UPDATE singers SET name=@a0 WHERE singers.id = @a1" add_update_count(update, 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = ( @@ -277,7 +258,7 @@ def test_database_role(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": FixedSizePool(size=10), + "logger": MockServerTestBase.logger, "database_role": "my_role", }, ) @@ -285,10 +266,10 @@ def test_database_role(self): session.execute(select(1)) requests = self.spanner_service.requests eq_(2, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) - request: BatchCreateSessionsRequest = requests[0] - eq_("my_role", request.session_template.creator_role) + request: CreateSessionRequest = requests[0] + eq_("my_role", request.session.creator_role) def test_select_table_in_named_schema(self): class Base(DeclarativeBase): @@ -309,10 +290,7 @@ class Singer(Base): " LIMIT @a1" ) add_singer_query_result(query) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() insert = "INSERT INTO my_schema.singers (name) VALUES (@a0) THEN RETURN id" add_single_result(insert, "id", TypeCode.INT64, [("1",)]) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py index 9e7a81a8e510..b54bb367bda7 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_bit_reversed_sequence.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -52,10 +50,7 @@ def test_create_table(self): LIMIT 1""", ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -113,10 +108,7 @@ def test_insert_row(self): "THEN RETURN id", result, ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -128,7 +120,7 @@ def test_insert_row(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py index 3872bde1d3c0..f70fcec66b35 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_commit_timestamp.py @@ -12,12 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.testing import eq_, is_instance_of -from google.cloud.spanner_v1 import ( - FixedSizePool, - ResultSet, -) +from google.cloud.spanner_v1 import ResultSet from test.mockserver_tests.mock_server_test_base import ( MockServerTestBase, add_result, @@ -45,10 +41,7 @@ def test_create_table(self): LIMIT 1""", ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py index 801a57c238dd..50cd6a861701 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_float32.py @@ -19,7 +19,7 @@ is_false, ) from google.cloud.spanner_v1 import ( - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, ResultSet, ResultSetStats, @@ -59,7 +59,7 @@ def test_insert_data(self): requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py index f6545298f2ea..21dca30579fe 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_isolation_level.py @@ -16,8 +16,7 @@ from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -41,10 +40,7 @@ def test_default_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: singer = Singer(name="Test") @@ -60,7 +56,7 @@ def test_engine_isolation_level(self): self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, isolation_level="REPEATABLE READ", ) @@ -74,10 +70,7 @@ def test_execution_options_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options(isolation_level="repeatable read") @@ -93,7 +86,7 @@ def test_override_engine_isolation_level(self): self.add_insert_result("INSERT INTO singers (name) VALUES (@a0) THEN RETURN id") engine = create_engine( "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + connect_args={"client": self.client, "logger": MockServerTestBase.logger}, isolation_level="REPEATABLE READ", ) @@ -113,7 +106,7 @@ def test_auto_commit(self): "spanner:///projects/p/instances/i/databases/d", connect_args={ "client": self.client, - "pool": FixedSizePool(size=10), + "logger": MockServerTestBase.logger, "ignore_transaction_warnings": True, }, ) @@ -130,7 +123,7 @@ def test_auto_commit(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(3, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], CommitRequest) execute_request: ExecuteSqlRequest = requests[1] @@ -147,10 +140,7 @@ def test_auto_commit(self): def test_invalid_isolation_level(self): from test.mockserver_tests.isolation_level_model import Singer - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with pytest.raises(ValueError): with Session(engine.execution_options(isolation_level="foo")) as session: singer = Singer(name="Test") @@ -161,7 +151,7 @@ def verify_isolation_level(self, level): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py index 6395fe3a3b25..2d37a3350a3b 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py @@ -12,13 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -47,10 +46,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -83,10 +79,7 @@ def _test_insert_json(self, description, expected): add_update_count( "INSERT INTO venues (id, name, description) VALUES (@a0, @a1, @a2)", 1 ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine) as session: venue = Venue(id=1, name="Test", description=description) @@ -96,7 +89,7 @@ def _test_insert_json(self, description, expected): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) @@ -126,10 +119,7 @@ def _test_select_json(self, description, expected): sql = "SELECT venues.id, venues.name, venues.description \n" "FROM venues" add_venue_query_result(sql, description) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine.execution_options(read_only=True)) as session: venue = session.execute(select(Venue)).first()[0] diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py index b4c2e76c333b..b2f1a2abee3c 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_pickle_type.py @@ -12,13 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, ResultSet, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, CommitRequest, BeginTransactionRequest, @@ -46,10 +44,7 @@ def test_create_table(self): """, ResultSet(), ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() Base.metadata.create_all(engine) requests = self.database_admin_service.requests eq_(1, len(requests)) @@ -74,10 +69,7 @@ def test_insert_and_query(self): "VALUES (@a0, @a1, @a2, @a3)", 1, ) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() preferences = {"setting": "true"} preferences_base64 = "gAWVFQAAAAAAAAB9lIwHc2V0dGluZ5SMBHRydWWUcy4=" with Session(engine) as session: @@ -94,7 +86,7 @@ def test_insert_and_query(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], CommitRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py index c7db636e2883..d62f03594699 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_quickstart.py @@ -16,7 +16,7 @@ from google.cloud.spanner_v1 import ( ResultSet, ResultSetStats, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteBatchDmlRequest, CommitRequest, BeginTransactionRequest, @@ -116,7 +116,7 @@ def test_insert_data(self): requests = self.spanner_service.requests eq_(5, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteBatchDmlRequest) is_instance_of(requests[3], ExecuteBatchDmlRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py index 013c0401b194..0dffbb888e00 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_read_only_transaction.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, TransactionOptions, @@ -33,11 +32,7 @@ def test_read_only_transaction(self): from test.mockserver_tests.read_only_model import Singer add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() for i in range(2): with Session(engine.execution_options(read_only=True)) as session: @@ -48,7 +43,7 @@ def test_read_only_transaction(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(7, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py index d3ac91e8fdb1..0dcf8b38c680 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_stale_reads.py @@ -13,12 +13,11 @@ # limitations under the License. import datetime -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, TransactionOptions, @@ -34,11 +33,7 @@ def test_stale_read_multi_use(self): from test.mockserver_tests.stale_read_model import Singer add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() timestamp = datetime.datetime.fromtimestamp(1733328910) for i in range(2): @@ -55,7 +50,7 @@ def test_stale_read_multi_use(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(7, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) @@ -83,11 +78,7 @@ def test_stale_read_single_use(self): from test.mockserver_tests.stale_read_model import Singer add_singer_query_result("SELECT singers.id, singers.name \nFROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - echo=True, - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options( @@ -102,7 +93,7 @@ def test_stale_read_single_use(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(3, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], ExecuteSqlRequest) is_instance_of(requests[2], ExecuteSqlRequest) # Verify that the requests use a stale read. diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py index 8c157154a7fb..0a4d6337f03c 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_tags.py @@ -12,12 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import create_engine, select +from sqlalchemy import select from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( - FixedSizePool, - BatchCreateSessionsRequest, + CreateSessionRequest, ExecuteSqlRequest, BeginTransactionRequest, CommitRequest, @@ -36,10 +35,7 @@ def test_request_tag(self): from test.mockserver_tests.tags_model import Singer add_singer_query_result("SELECT singers.id, singers.name \n" + "FROM singers") - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session(engine.execution_options(read_only=True)) as session: # Execute two queries in a read-only transaction. @@ -53,7 +49,7 @@ def test_request_tag(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(4, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) @@ -71,10 +67,7 @@ def test_transaction_tag(self): "WHERE singers.id = @a0" ) add_update_count("INSERT INTO singers (id, name) VALUES (@a0, @a1)", 1) - engine = create_engine( - "spanner:///projects/p/instances/i/databases/d", - connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, - ) + engine = self.create_engine() with Session( engine.execution_options(transaction_tag="my-transaction-tag") @@ -91,7 +84,7 @@ def test_transaction_tag(self): # Verify the requests that we got. requests = self.spanner_service.requests eq_(6, len(requests)) - is_instance_of(requests[0], BatchCreateSessionsRequest) + is_instance_of(requests[0], CreateSessionRequest) is_instance_of(requests[1], BeginTransactionRequest) is_instance_of(requests[2], ExecuteSqlRequest) is_instance_of(requests[3], ExecuteSqlRequest) diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 3cb252d2dee3..27143de9d3e4 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -256,6 +256,11 @@ def test_binary_reflection(self, connection, metadata): assert isinstance(typ, LargeBinary) eq_(typ.length, 20) + @testing.requires.table_reflection + def test_string_length_reflection(self, connection, metadata): + typ = self._type_round_trip(connection, metadata, types.String(52))[0] + assert isinstance(typ, types.String) + class ComputedReflectionFixtureTest(_ComputedReflectionFixtureTest): @classmethod @@ -2576,6 +2581,12 @@ class BizarroCharacterFKResolutionTest(fixtures.TestBase): pass +class BizarroCharacterTest(fixtures.TestBase): + @pytest.mark.skip("Bizarre characters in foreign key names are not supported") + def test_fk_ref(self, testing_engine): + pass + + class IsolationLevelTest(fixtures.TestBase): @pytest.mark.skip("Cloud Spanner does not support different isolation levels") def test_dialect_user_setting_is_restored(self, testing_engine): From 797f56b674c8966326875db0df7eef91d8a1d006 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 09:54:32 +0200 Subject: [PATCH 498/582] chore(deps): update dependency alembic to v1.16.4 (#713) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0894601a78ba..4ca8380175df 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.16.2 \ - --hash=sha256:5f42e9bd0afdbd1d5e3ad856c01754530367debdebf21ed6894e34af52b3bb03 \ - --hash=sha256:e53c38ff88dadb92eb22f8b150708367db731d58ad7e9d417c9168ab516cbed8 +alembic==1.16.4 \ + --hash=sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d \ + --hash=sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2 # via -r requirements.in build==1.2.2.post1 \ --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ From e76e152635e1dcaf3ecf2b81dfa8b6a1a24d8942 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:09:40 +0200 Subject: [PATCH 499/582] chore(deps): update dependency certifi to v2025.8.3 (#714) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4ca8380175df..7ecb842c1f37 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==5.5.2 \ --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a # via google-auth -certifi==2025.6.15 \ - --hash=sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057 \ - --hash=sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b +certifi==2025.8.3 \ + --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ + --hash=sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5 # via requests charset-normalizer==3.4.2 \ --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ From 375eb920c376add63c2a7626c903ad828d1d32e8 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:12:09 +0200 Subject: [PATCH 500/582] chore(deps): update opentelemetry-python monorepo to v1.36.0 (#716) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7ecb842c1f37..37880f8dbf92 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -356,9 +356,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.34.1 \ - --hash=sha256:64f0bd06d42824843731d05beea88d4d4b6ae59f9fe347ff7dfa2cc14233bbb3 \ - --hash=sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c +opentelemetry-api==1.36.0 \ + --hash=sha256:02f20bcacf666e1333b6b1f04e647dc1d5111f86b8e510238fcc56d7762cda8c \ + --hash=sha256:9a72572b9c416d004d492cbc6e61962c0501eaf945ece9b5a0f56597d8348aa0 # via # -r requirements.in # opentelemetry-instrumentation @@ -368,9 +368,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.34.1 \ - --hash=sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e \ - --hash=sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d +opentelemetry-sdk==1.36.0 \ + --hash=sha256:19c8c81599f51b71670661ff7495c905d8fdf6976e41622d5245b791b06fa581 \ + --hash=sha256:19fe048b42e98c5c1ffe85b569b7073576ad4ce0bcb6e9b4c6a39e890a6c45fb # via -r requirements.in opentelemetry-semantic-conventions==0.55b1 \ --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ From b65ec236c9e3e3c83933e1c4218f96f1cacc381a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:14:24 +0200 Subject: [PATCH 501/582] chore(deps): update dependency grpcio to v1.74.0 (#723) --- packages/sqlalchemy-spanner/requirements.txt | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 37880f8dbf92..96796671188b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -219,58 +219,58 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.73.1 \ - --hash=sha256:052e28fe9c41357da42250a91926a3e2f74c046575c070b69659467ca5aa976b \ - --hash=sha256:07f08705a5505c9b5b0cbcbabafb96462b5a15b7236bbf6bbcc6b0b91e1cbd7e \ - --hash=sha256:0a9f3ea8dce9eae9d7cb36827200133a72b37a63896e0e61a9d5ec7d61a59ab1 \ - --hash=sha256:0ab860d5bfa788c5a021fba264802e2593688cd965d1374d31d2b1a34cacd854 \ - --hash=sha256:105492124828911f85127e4825d1c1234b032cb9d238567876b5515d01151379 \ - --hash=sha256:10af9f2ab98a39f5b6c1896c6fc2036744b5b41d12739d48bed4c3e15b6cf900 \ - --hash=sha256:1c0bf15f629b1497436596b1cbddddfa3234273490229ca29561209778ebe182 \ - --hash=sha256:1c502c2e950fc7e8bf05c047e8a14522ef7babac59abbfde6dbf46b7a0d9c71e \ - --hash=sha256:24e06a5319e33041e322d32c62b1e728f18ab8c9dbc91729a3d9f9e3ed336642 \ - --hash=sha256:277b426a0ed341e8447fbf6c1d6b68c952adddf585ea4685aa563de0f03df887 \ - --hash=sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55 \ - --hash=sha256:303c8135d8ab176f8038c14cc10d698ae1db9c480f2b2823f7a987aa2a4c5646 \ - --hash=sha256:3841a8a5a66830261ab6a3c2a3dc539ed84e4ab019165f77b3eeb9f0ba621f26 \ - --hash=sha256:42f0660bce31b745eb9d23f094a332d31f210dcadd0fc8e5be7e4c62a87ce86b \ - --hash=sha256:45cf17dcce5ebdb7b4fe9e86cb338fa99d7d1bb71defc78228e1ddf8d0de8cbb \ - --hash=sha256:4a68f8c9966b94dff693670a5cf2b54888a48a5011c5d9ce2295a1a1465ee84f \ - --hash=sha256:5b9b1805a7d61c9e90541cbe8dfe0a593dfc8c5c3a43fe623701b6a01b01d710 \ - --hash=sha256:610e19b04f452ba6f402ac9aa94eb3d21fbc94553368008af634812c4a85a99e \ - --hash=sha256:628c30f8e77e0258ab788750ec92059fc3d6628590fb4b7cea8c102503623ed7 \ - --hash=sha256:65b0458a10b100d815a8426b1442bd17001fdb77ea13665b2f7dc9e8587fdc6b \ - --hash=sha256:67a0468256c9db6d5ecb1fde4bf409d016f42cef649323f0a08a72f352d1358b \ - --hash=sha256:686231cdd03a8a8055f798b2b54b19428cdf18fa1549bee92249b43607c42668 \ - --hash=sha256:68b84d65bbdebd5926eb5c53b0b9ec3b3f83408a30e4c20c373c5337b4219ec5 \ - --hash=sha256:6957025a4608bb0a5ff42abd75bfbb2ed99eda29d5992ef31d691ab54b753643 \ - --hash=sha256:6a2b372e65fad38842050943f42ce8fee00c6f2e8ea4f7754ba7478d26a356ee \ - --hash=sha256:6a6037891cd2b1dd1406b388660522e1565ed340b1fea2955b0234bdd941a862 \ - --hash=sha256:6abfc0f9153dc4924536f40336f88bd4fe7bd7494f028675e2e04291b8c2c62a \ - --hash=sha256:75fc8e543962ece2f7ecd32ada2d44c0c8570ae73ec92869f9af8b944863116d \ - --hash=sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87 \ - --hash=sha256:83a6c2cce218e28f5040429835fa34a29319071079e3169f9543c3fbeff166d2 \ - --hash=sha256:89018866a096e2ce21e05eabed1567479713ebe57b1db7cbb0f1e3b896793ba4 \ - --hash=sha256:8f5a6df3fba31a3485096ac85b2e34b9666ffb0590df0cd044f58694e6a1f6b5 \ - --hash=sha256:921b25618b084e75d424a9f8e6403bfeb7abef074bb6c3174701e0f2542debcf \ - --hash=sha256:96c112333309493c10e118d92f04594f9055774757f5d101b39f8150f8c25582 \ - --hash=sha256:ad1d958c31cc91ab050bd8a91355480b8e0683e21176522bacea225ce51163f2 \ - --hash=sha256:ad5c958cc3d98bb9d71714dc69f1c13aaf2f4b53e29d4cc3f1501ef2e4d129b2 \ - --hash=sha256:b310824ab5092cf74750ebd8a8a8981c1810cb2b363210e70d06ef37ad80d4f9 \ - --hash=sha256:b3215f69a0670a8cfa2ab53236d9e8026bfb7ead5d4baabe7d7dc11d30fda967 \ - --hash=sha256:b4adc97d2d7f5c660a5498bda978ebb866066ad10097265a5da0511323ae9f50 \ - --hash=sha256:ba2cea9f7ae4bc21f42015f0ec98f69ae4179848ad744b210e7685112fa507a1 \ - --hash=sha256:bc5eccfd9577a5dc7d5612b2ba90cca4ad14c6d949216c68585fdec9848befb1 \ - --hash=sha256:c45a28a0cfb6ddcc7dc50a29de44ecac53d115c3388b2782404218db51cb2df3 \ - --hash=sha256:c54796ca22b8349cc594d18b01099e39f2b7ffb586ad83217655781a350ce4da \ - --hash=sha256:cce7265b9617168c2d08ae570fcc2af4eaf72e84f8c710ca657cc546115263af \ - --hash=sha256:d60588ab6ba0ac753761ee0e5b30a29398306401bfbceffe7d68ebb21193f9d4 \ - --hash=sha256:d74c3f4f37b79e746271aa6cdb3a1d7e4432aea38735542b23adcabaaee0c097 \ - --hash=sha256:dc7d7fd520614fce2e6455ba89791458020a39716951c7c07694f9dbae28e9c0 \ - --hash=sha256:de18769aea47f18e782bf6819a37c1c528914bfd5683b8782b9da356506190c8 \ - --hash=sha256:ed451a0e39c8e51eb1612b78686839efd1a920666d1666c1adfdb4fd51680c0f \ - --hash=sha256:f43ffb3bd415c57224c7427bfb9e6c46a0b6e998754bfa0d00f408e1873dcbb5 \ - --hash=sha256:f48e862aed925ae987eb7084409a80985de75243389dc9d9c271dd711e589918 +grpcio==1.74.0 \ + --hash=sha256:0f87bddd6e27fc776aacf7ebfec367b6d49cad0455123951e4488ea99d9b9b8f \ + --hash=sha256:136b53c91ac1d02c8c24201bfdeb56f8b3ac3278668cbb8e0ba49c88069e1bdc \ + --hash=sha256:1733969040989f7acc3d94c22f55b4a9501a30f6aaacdbccfaba0a3ffb255ab7 \ + --hash=sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7 \ + --hash=sha256:1a2b06afe2e50ebfd46247ac3ba60cac523f54ec7792ae9ba6073c12daf26f0a \ + --hash=sha256:1bf949792cee20d2078323a9b02bacbbae002b9e3b9e2433f2741c15bdeba1c4 \ + --hash=sha256:22b834cef33429ca6cc28303c9c327ba9a3fafecbf62fae17e9a7b7163cc43ac \ + --hash=sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6 \ + --hash=sha256:2bc2d7d8d184e2362b53905cb1708c84cb16354771c04b490485fa07ce3a1d89 \ + --hash=sha256:2f609a39f62a6f6f05c7512746798282546358a37ea93c1fcbadf8b2fed162e3 \ + --hash=sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49 \ + --hash=sha256:3b03d8f2a07f0fea8c8f74deb59f8352b770e3900d143b3d1475effcb08eec20 \ + --hash=sha256:3d14e3c4d65e19d8430a4e28ceb71ace4728776fd6c3ce34016947474479683f \ + --hash=sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc \ + --hash=sha256:4bc5fca10aaf74779081e16c2bcc3d5ec643ffd528d9e7b1c9039000ead73bae \ + --hash=sha256:4e4181bfc24413d1e3a37a0b7889bea68d973d4b45dd2bc68bb766c140718f82 \ + --hash=sha256:55b453812fa7c7ce2f5c88be3018fb4a490519b6ce80788d5913f3f9d7da8c7b \ + --hash=sha256:566b9395b90cc3d0d0c6404bc8572c7c18786ede549cdb540ae27b58afe0fb91 \ + --hash=sha256:5f251c355167b2360537cf17bea2cf0197995e551ab9da6a0a59b3da5e8704f9 \ + --hash=sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5 \ + --hash=sha256:64229c1e9cea079420527fa8ac45d80fc1e8d3f94deaa35643c381fa8d98f362 \ + --hash=sha256:655726919b75ab3c34cdad39da5c530ac6fa32696fb23119e36b64adcfca174a \ + --hash=sha256:662456c4513e298db6d7bd9c3b8df6f75f8752f0ba01fb653e252ed4a59b5a5d \ + --hash=sha256:68c8ebcca945efff9d86d8d6d7bfb0841cf0071024417e2d7f45c5e46b5b08eb \ + --hash=sha256:69e1a8180868a2576f02356565f16635b99088da7df3d45aaa7e24e73a054e31 \ + --hash=sha256:6bab67d15ad617aff094c382c882e0177637da73cbc5532d52c07b4ee887a87b \ + --hash=sha256:7d95d71ff35291bab3f1c52f52f474c632db26ea12700c2ff0ea0532cb0b5854 \ + --hash=sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1 \ + --hash=sha256:834988b6c34515545b3edd13e902c1acdd9f2465d386ea5143fb558f153a7176 \ + --hash=sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8 \ + --hash=sha256:85bd5cdf4ed7b2d6438871adf6afff9af7096486fcf51818a81b77ef4dd30907 \ + --hash=sha256:86ad489db097141a907c559988c29718719aa3e13370d40e20506f11b4de0d11 \ + --hash=sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c \ + --hash=sha256:8efe72fde5500f47aca1ef59495cb59c885afe04ac89dd11d810f2de87d935d4 \ + --hash=sha256:8f7b5882fb50632ab1e48cb3122d6df55b9afabc265582808036b6e51b9fd6b7 \ + --hash=sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707 \ + --hash=sha256:9e912d3c993a29df6c627459af58975b2e5c897d93287939b9d5065f000249b5 \ + --hash=sha256:a8f0302f9ac4e9923f98d8e243939a6fb627cd048f5cd38595c97e38020dffce \ + --hash=sha256:b6a73b2ba83e663b2480a90b82fdae6a7aa6427f62bf43b29912c0cfd1aa2bfa \ + --hash=sha256:c14e803037e572c177ba54a3e090d6eb12efd795d49327c5ee2b3bddb836bf01 \ + --hash=sha256:c3d7bd6e3929fd2ea7fbc3f562e4987229ead70c9ae5f01501a46701e08f1ad9 \ + --hash=sha256:c98e0b7434a7fa4e3e63f250456eaef52499fba5ae661c58cc5b5477d11e7182 \ + --hash=sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b \ + --hash=sha256:e154d230dc1bbbd78ad2fdc3039fa50ad7ffcf438e4eb2fa30bce223a70c7486 \ + --hash=sha256:e1ea6176d7dfd5b941ea01c2ec34de9531ba494d541fe2057c904e601879f249 \ + --hash=sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3 \ + --hash=sha256:e8978003816c7b9eabe217f88c78bc26adc8f9304bf6a594b02e5a49b2ef9c11 \ + --hash=sha256:ecde9ab49f58433abe02f9ed076c7b5be839cf0153883a6d23995937a82392fa \ + --hash=sha256:f6ec94f0e50eb8fa1744a731088b966427575e40c2944a980049798b127a687e \ + --hash=sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24 \ + --hash=sha256:fe0f540750a13fd8e5da4b3eaba91a785eea8dca5ccd2bc2ffe978caa403090e # via # google-api-core # googleapis-common-protos From 3fe04272741c2f882f4bee46d53fbcf38c698b3f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:15:26 +0200 Subject: [PATCH 502/582] chore(deps): update dependency sqlalchemy to v2.0.43 (#725) --- packages/sqlalchemy-spanner/requirements.txt | 116 +++++++++---------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 96796671188b..f76df6a55459 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -441,64 +441,64 @@ rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth -sqlalchemy==2.0.41 \ - --hash=sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5 \ - --hash=sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582 \ - --hash=sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b \ - --hash=sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b \ - --hash=sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348 \ - --hash=sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda \ - --hash=sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5 \ - --hash=sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2 \ - --hash=sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29 \ - --hash=sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8 \ - --hash=sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f \ - --hash=sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826 \ - --hash=sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504 \ - --hash=sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae \ - --hash=sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45 \ - --hash=sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443 \ - --hash=sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23 \ - --hash=sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576 \ - --hash=sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1 \ - --hash=sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0 \ - --hash=sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71 \ - --hash=sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11 \ - --hash=sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e \ - --hash=sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f \ - --hash=sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8 \ - --hash=sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd \ - --hash=sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814 \ - --hash=sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08 \ - --hash=sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea \ - --hash=sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30 \ - --hash=sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda \ - --hash=sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9 \ - --hash=sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923 \ - --hash=sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df \ - --hash=sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036 \ - --hash=sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3 \ - --hash=sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f \ - --hash=sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6 \ - --hash=sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04 \ - --hash=sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2 \ - --hash=sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560 \ - --hash=sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70 \ - --hash=sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769 \ - --hash=sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1 \ - --hash=sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6 \ - --hash=sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b \ - --hash=sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747 \ - --hash=sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078 \ - --hash=sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440 \ - --hash=sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f \ - --hash=sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2 \ - --hash=sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d \ - --hash=sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc \ - --hash=sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a \ - --hash=sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd \ - --hash=sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9 \ - --hash=sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6 +SQLAlchemy==2.0.43 \ + --hash=sha256:022e436a1cb39b13756cf93b48ecce7aa95382b9cfacceb80a7d263129dfd019 \ + --hash=sha256:03d73ab2a37d9e40dec4984d1813d7878e01dbdc742448d44a7341b7a9f408c7 \ + --hash=sha256:07097c0a1886c150ef2adba2ff7437e84d40c0f7dcb44a2c2b9c905ccfc6361c \ + --hash=sha256:11b9503fa6f8721bef9b8567730f664c5a5153d25e247aadc69247c4bc605227 \ + --hash=sha256:11f43c39b4b2ec755573952bbcc58d976779d482f6f832d7f33a8d869ae891bf \ + --hash=sha256:13194276e69bb2af56198fef7909d48fd34820de01d9c92711a5fa45497cc7ed \ + --hash=sha256:136063a68644eca9339d02e6693932116f6a8591ac013b0014479a1de664e40a \ + --hash=sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa \ + --hash=sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc \ + --hash=sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48 \ + --hash=sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a \ + --hash=sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24 \ + --hash=sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9 \ + --hash=sha256:21ba7a08a4253c5825d1db389d4299f64a100ef9800e4624c8bf70d8f136e6ed \ + --hash=sha256:227119ce0a89e762ecd882dc661e0aa677a690c914e358f0dd8932a2e8b2765b \ + --hash=sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83 \ + --hash=sha256:334f41fa28de9f9be4b78445e68530da3c5fa054c907176460c81494f4ae1f5e \ + --hash=sha256:413391b2239db55be14fa4223034d7e13325a1812c8396ecd4f2c08696d5ccad \ + --hash=sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687 \ + --hash=sha256:44337823462291f17f994d64282a71c51d738fc9ef561bf265f1d0fd9116a782 \ + --hash=sha256:46293c39252f93ea0910aababa8752ad628bcce3a10d3f260648dd472256983f \ + --hash=sha256:4bf0edb24c128b7be0c61cd17eef432e4bef507013292415f3fb7023f02b7d4b \ + --hash=sha256:4d3d9b904ad4a6b175a2de0738248822f5ac410f52c2fd389ada0b5262d6a1e3 \ + --hash=sha256:4e6aeb2e0932f32950cf56a8b4813cb15ff792fc0c9b3752eaf067cfe298496a \ + --hash=sha256:4fb1a8c5438e0c5ea51afe9c6564f951525795cf432bed0c028c1cb081276685 \ + --hash=sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe \ + --hash=sha256:52d9b73b8fb3e9da34c2b31e6d99d60f5f99fd8c1225c9dad24aeb74a91e1d29 \ + --hash=sha256:5cda6b51faff2639296e276591808c1726c4a77929cfaa0f514f30a5f6156921 \ + --hash=sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738 \ + --hash=sha256:61f964a05356f4bca4112e6334ed7c208174511bd56e6b8fc86dad4d024d4185 \ + --hash=sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9 \ + --hash=sha256:6e2bf13d9256398d037fef09fd8bf9b0bf77876e22647d10761d35593b9ac547 \ + --hash=sha256:70322986c0c699dca241418fcf18e637a4369e0ec50540a2b907b184c8bca069 \ + --hash=sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417 \ + --hash=sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d \ + --hash=sha256:87accdbba88f33efa7b592dc2e8b2a9c2cdbca73db2f9d5c510790428c09c154 \ + --hash=sha256:8cee08f15d9e238ede42e9bbc1d6e7158d0ca4f176e4eab21f88ac819ae3bd7b \ + --hash=sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197 \ + --hash=sha256:9c2e02f06c68092b875d5cbe4824238ab93a7fa35d9c38052c033f7ca45daa18 \ + --hash=sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f \ + --hash=sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164 \ + --hash=sha256:b3edaec7e8b6dc5cd94523c6df4f294014df67097c8217a89929c99975811414 \ + --hash=sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d \ + --hash=sha256:bcf0724a62a5670e5718957e05c56ec2d6850267ea859f8ad2481838f889b42c \ + --hash=sha256:c00e7845d2f692ebfc7d5e4ec1a3fd87698e4337d09e58d6749a16aedfdf8612 \ + --hash=sha256:c379e37b08c6c527181a397212346be39319fb64323741d23e46abd97a400d34 \ + --hash=sha256:c5d1730b25d9a07727d20ad74bc1039bbbb0a6ca24e6769861c1aa5bf2c4c4a8 \ + --hash=sha256:c5e73ba0d76eefc82ec0219d2301cb33bfe5205ed7a2602523111e2e56ccbd20 \ + --hash=sha256:c697575d0e2b0a5f0433f679bda22f63873821d991e95a90e9e52aae517b2e32 \ + --hash=sha256:cdeff998cb294896a34e5b2f00e383e7c5c4ef3b4bfa375d9104723f15186443 \ + --hash=sha256:ceb5c832cc30663aeaf5e39657712f4c4241ad1f638d487ef7216258f6d41fe7 \ + --hash=sha256:d34c0f6dbefd2e816e8f341d0df7d4763d382e3f452423e752ffd1e213da2512 \ + --hash=sha256:db691fa174e8f7036afefe3061bc40ac2b770718be2862bfb03aabae09051aca \ + --hash=sha256:e7a903b5b45b0d9fa03ac6a331e1c1d6b7e0ab41c63b6217b3d10357b83c8b00 \ + --hash=sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3 \ + --hash=sha256:f42f23e152e4545157fa367b2435a1ace7571cab016ca26038867eb7df2c3631 \ + --hash=sha256:fe2b3b4927d0bc03d02ad883f402d5de201dbc8894ac87d2e981e7d87430e60d # via # -r requirements.in # alembic From 86df25180998b1a3b3ee6360419246db41c5afec Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:26:51 +0200 Subject: [PATCH 503/582] chore(deps): update dependency grpcio-status to v1.74.0 (#724) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index f76df6a55459..df761dfa5bf1 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -277,9 +277,9 @@ grpcio==1.74.0 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.73.1 \ - --hash=sha256:538595c32a6c819c32b46a621a51e9ae4ffcd7e7e1bce35f728ef3447e9809b6 \ - --hash=sha256:928f49ccf9688db5f20cd9e45c4578a1d01ccca29aeaabf066f2ac76aa886668 +grpcio-status==1.74.0 \ + --hash=sha256:52cdbd759a6760fc8f668098a03f208f493dd5c76bf8e02598bbbaf1f6fc2876 \ + --hash=sha256:c58c1b24aa454e30f1fc6a7e0dbbc194c54a408143971a94b5f4e40bb5831432 # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From 97b67b0d08b454f0eb69c5aa811be950df8a0b55 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:31:58 +0200 Subject: [PATCH 504/582] chore(deps): update dependency pip-tools to v7.5.0 (#731) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index df761dfa5bf1..fb5775c99ff7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -386,9 +386,9 @@ pep517==0.13.1 \ --hash=sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317 \ --hash=sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721 # via -r requirements.in -pip-tools==7.4.1 \ - --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \ - --hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9 +pip-tools==7.5.0 \ + --hash=sha256:30639f50961bb09f49d22f4389e8d7d990709677c094ce1114186b1f2e9b5821 \ + --hash=sha256:69758e4e5a65f160e315d74db46246fdbb30d549f1ed0c4236d057122c9b0f18 # via -r requirements.in proto-plus==1.26.1 \ --hash=sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66 \ From 0d803d5dbf4bc23b62cceb9111256dd7d87d463e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:35:57 +0200 Subject: [PATCH 505/582] chore(deps): update dependency charset-normalizer to v3.4.3 (#736) --- packages/sqlalchemy-spanner/requirements.txt | 173 +++++++++---------- 1 file changed, 80 insertions(+), 93 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index fb5775c99ff7..076a86310317 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -22,99 +22,86 @@ certifi==2025.8.3 \ --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ --hash=sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5 # via requests -charset-normalizer==3.4.2 \ - --hash=sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4 \ - --hash=sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45 \ - --hash=sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7 \ - --hash=sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0 \ - --hash=sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7 \ - --hash=sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d \ - --hash=sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d \ - --hash=sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0 \ - --hash=sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184 \ - --hash=sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db \ - --hash=sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b \ - --hash=sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64 \ - --hash=sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b \ - --hash=sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8 \ - --hash=sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff \ - --hash=sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344 \ - --hash=sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58 \ - --hash=sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e \ - --hash=sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471 \ - --hash=sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148 \ - --hash=sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a \ - --hash=sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836 \ - --hash=sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e \ - --hash=sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63 \ - --hash=sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c \ - --hash=sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1 \ - --hash=sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01 \ - --hash=sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366 \ - --hash=sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58 \ - --hash=sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5 \ - --hash=sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c \ - --hash=sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2 \ - --hash=sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a \ - --hash=sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597 \ - --hash=sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b \ - --hash=sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5 \ - --hash=sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb \ - --hash=sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f \ - --hash=sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0 \ - --hash=sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941 \ - --hash=sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0 \ - --hash=sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86 \ - --hash=sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7 \ - --hash=sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7 \ - --hash=sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455 \ - --hash=sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6 \ - --hash=sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4 \ - --hash=sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0 \ - --hash=sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3 \ - --hash=sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1 \ - --hash=sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6 \ - --hash=sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981 \ - --hash=sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c \ - --hash=sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980 \ - --hash=sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645 \ - --hash=sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7 \ - --hash=sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12 \ - --hash=sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa \ - --hash=sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd \ - --hash=sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef \ - --hash=sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f \ - --hash=sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2 \ - --hash=sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d \ - --hash=sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5 \ - --hash=sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02 \ - --hash=sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3 \ - --hash=sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd \ - --hash=sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e \ - --hash=sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214 \ - --hash=sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd \ - --hash=sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a \ - --hash=sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c \ - --hash=sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681 \ - --hash=sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba \ - --hash=sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f \ - --hash=sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a \ - --hash=sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28 \ - --hash=sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691 \ - --hash=sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82 \ - --hash=sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a \ - --hash=sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027 \ - --hash=sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7 \ - --hash=sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518 \ - --hash=sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf \ - --hash=sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b \ - --hash=sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9 \ - --hash=sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544 \ - --hash=sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da \ - --hash=sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509 \ - --hash=sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f \ - --hash=sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a \ - --hash=sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f +charset-normalizer==3.4.3 \ + --hash=sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91 \ + --hash=sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0 \ + --hash=sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154 \ + --hash=sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601 \ + --hash=sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884 \ + --hash=sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07 \ + --hash=sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c \ + --hash=sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64 \ + --hash=sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe \ + --hash=sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f \ + --hash=sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432 \ + --hash=sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc \ + --hash=sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa \ + --hash=sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9 \ + --hash=sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae \ + --hash=sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19 \ + --hash=sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d \ + --hash=sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e \ + --hash=sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4 \ + --hash=sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7 \ + --hash=sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312 \ + --hash=sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92 \ + --hash=sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31 \ + --hash=sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c \ + --hash=sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f \ + --hash=sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99 \ + --hash=sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b \ + --hash=sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15 \ + --hash=sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392 \ + --hash=sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f \ + --hash=sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8 \ + --hash=sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491 \ + --hash=sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0 \ + --hash=sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc \ + --hash=sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0 \ + --hash=sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f \ + --hash=sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a \ + --hash=sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40 \ + --hash=sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927 \ + --hash=sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849 \ + --hash=sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce \ + --hash=sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14 \ + --hash=sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05 \ + --hash=sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c \ + --hash=sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c \ + --hash=sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a \ + --hash=sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc \ + --hash=sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34 \ + --hash=sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9 \ + --hash=sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096 \ + --hash=sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14 \ + --hash=sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30 \ + --hash=sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b \ + --hash=sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b \ + --hash=sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942 \ + --hash=sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db \ + --hash=sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5 \ + --hash=sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b \ + --hash=sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce \ + --hash=sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669 \ + --hash=sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0 \ + --hash=sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018 \ + --hash=sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93 \ + --hash=sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe \ + --hash=sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049 \ + --hash=sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a \ + --hash=sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef \ + --hash=sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2 \ + --hash=sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca \ + --hash=sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16 \ + --hash=sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f \ + --hash=sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb \ + --hash=sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1 \ + --hash=sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557 \ + --hash=sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37 \ + --hash=sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7 \ + --hash=sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72 \ + --hash=sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c \ + --hash=sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9 # via requests click==8.2.1 \ --hash=sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202 \ From a4e15c1e1b18639fc59c4d98d4adca2214344ed6 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:38:29 +0200 Subject: [PATCH 506/582] chore(deps): update dependency greenlet to v3.2.4 (#737) --- packages/sqlalchemy-spanner/requirements.txt | 110 +++++++++---------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 076a86310317..39a6ef855fd2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -142,61 +142,61 @@ googleapis-common-protos[grpc]==1.70.0 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -greenlet==3.2.3 \ - --hash=sha256:003c930e0e074db83559edc8705f3a2d066d4aa8c2f198aff1e454946efd0f26 \ - --hash=sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36 \ - --hash=sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892 \ - --hash=sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83 \ - --hash=sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688 \ - --hash=sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be \ - --hash=sha256:22eb5ba839c4b2156f18f76768233fe44b23a31decd9cc0d4cc8141c211fd1b4 \ - --hash=sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d \ - --hash=sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5 \ - --hash=sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b \ - --hash=sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb \ - --hash=sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86 \ - --hash=sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c \ - --hash=sha256:42efc522c0bd75ffa11a71e09cd8a399d83fafe36db250a87cf1dacfaa15dc64 \ - --hash=sha256:4532f0d25df67f896d137431b13f4cdce89f7e3d4a96387a41290910df4d3a57 \ - --hash=sha256:49c8cfb18fb419b3d08e011228ef8a25882397f3a859b9fe1436946140b6756b \ - --hash=sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad \ - --hash=sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95 \ - --hash=sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3 \ - --hash=sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147 \ - --hash=sha256:68671180e3849b963649254a882cd544a3c75bfcd2c527346ad8bb53494444db \ - --hash=sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb \ - --hash=sha256:72e77ed69312bab0434d7292316d5afd6896192ac4327d44f3d613ecb85b037c \ - --hash=sha256:731e154aba8e757aedd0781d4b240f1225b075b4409f1bb83b05ff410582cf00 \ - --hash=sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849 \ - --hash=sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba \ - --hash=sha256:761917cac215c61e9dc7324b2606107b3b292a8349bdebb31503ab4de3f559ac \ - --hash=sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822 \ - --hash=sha256:7e70ea4384b81ef9e84192e8a77fb87573138aa5d4feee541d8014e452b434da \ - --hash=sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97 \ - --hash=sha256:8324319cbd7b35b97990090808fdc99c27fe5338f87db50514959f8059999805 \ - --hash=sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34 \ - --hash=sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141 \ - --hash=sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3 \ - --hash=sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0 \ - --hash=sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b \ - --hash=sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365 \ - --hash=sha256:8c37ef5b3787567d322331d5250e44e42b58c8c713859b8a04c6065f27efbf72 \ - --hash=sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a \ - --hash=sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc \ - --hash=sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163 \ - --hash=sha256:96c20252c2f792defe9a115d3287e14811036d51e78b3aaddbee23b69b216302 \ - --hash=sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef \ - --hash=sha256:a433dbc54e4a37e4fff90ef34f25a8c00aed99b06856f0119dcf09fbafa16392 \ - --hash=sha256:aaa7aae1e7f75eaa3ae400ad98f8644bb81e1dc6ba47ce8a93d3f17274e08322 \ - --hash=sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d \ - --hash=sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264 \ - --hash=sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b \ - --hash=sha256:ce539fb52fb774d0802175d37fcff5c723e2c7d249c65916257f0a940cee8904 \ - --hash=sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf \ - --hash=sha256:d760f9bdfe79bff803bad32b4d8ffb2c1d2ce906313fc10a83976ffb73d64ca7 \ - --hash=sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a \ - --hash=sha256:efc6dc8a792243c31f2f5674b670b3a95d46fa1c6a912b8e310d6f542e7b0712 \ - --hash=sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728 +greenlet==3.2.4 \ + --hash=sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b \ + --hash=sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735 \ + --hash=sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079 \ + --hash=sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d \ + --hash=sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433 \ + --hash=sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58 \ + --hash=sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52 \ + --hash=sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31 \ + --hash=sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246 \ + --hash=sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f \ + --hash=sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671 \ + --hash=sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8 \ + --hash=sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d \ + --hash=sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f \ + --hash=sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0 \ + --hash=sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd \ + --hash=sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337 \ + --hash=sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0 \ + --hash=sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633 \ + --hash=sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b \ + --hash=sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa \ + --hash=sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31 \ + --hash=sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9 \ + --hash=sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b \ + --hash=sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4 \ + --hash=sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc \ + --hash=sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c \ + --hash=sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98 \ + --hash=sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f \ + --hash=sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c \ + --hash=sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590 \ + --hash=sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3 \ + --hash=sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2 \ + --hash=sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9 \ + --hash=sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5 \ + --hash=sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02 \ + --hash=sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0 \ + --hash=sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1 \ + --hash=sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c \ + --hash=sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594 \ + --hash=sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5 \ + --hash=sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d \ + --hash=sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a \ + --hash=sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6 \ + --hash=sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b \ + --hash=sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df \ + --hash=sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945 \ + --hash=sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae \ + --hash=sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb \ + --hash=sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504 \ + --hash=sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb \ + --hash=sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01 \ + --hash=sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c \ + --hash=sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968 # via sqlalchemy grpc-google-iam-v1==0.14.2 \ --hash=sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351 \ From 9330f63a3ea8ac8721129b10f2064d7d26b34e60 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:41:18 +0200 Subject: [PATCH 507/582] chore(deps): update dependency wrapt to v1.17.3 (#738) --- packages/sqlalchemy-spanner/requirements.txt | 162 ++++++++++--------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 39a6ef855fd2..4d0f9aadd1e9 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -544,86 +544,88 @@ wheel==0.45.1 \ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248 # via pip-tools -wrapt==1.17.2 \ - --hash=sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f \ - --hash=sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c \ - --hash=sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a \ - --hash=sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b \ - --hash=sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555 \ - --hash=sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c \ - --hash=sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b \ - --hash=sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6 \ - --hash=sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8 \ - --hash=sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662 \ - --hash=sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061 \ - --hash=sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998 \ - --hash=sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb \ - --hash=sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62 \ - --hash=sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984 \ - --hash=sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392 \ - --hash=sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2 \ - --hash=sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306 \ - --hash=sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7 \ - --hash=sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3 \ - --hash=sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9 \ - --hash=sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6 \ - --hash=sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192 \ - --hash=sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317 \ - --hash=sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f \ - --hash=sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda \ - --hash=sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563 \ - --hash=sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a \ - --hash=sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f \ - --hash=sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d \ - --hash=sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9 \ - --hash=sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8 \ - --hash=sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82 \ - --hash=sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9 \ - --hash=sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845 \ - --hash=sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82 \ - --hash=sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125 \ - --hash=sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504 \ - --hash=sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b \ - --hash=sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7 \ - --hash=sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc \ - --hash=sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6 \ - --hash=sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40 \ - --hash=sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a \ - --hash=sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3 \ - --hash=sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a \ - --hash=sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72 \ - --hash=sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681 \ - --hash=sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438 \ - --hash=sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae \ - --hash=sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2 \ - --hash=sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb \ - --hash=sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5 \ - --hash=sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a \ - --hash=sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3 \ - --hash=sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8 \ - --hash=sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2 \ - --hash=sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22 \ - --hash=sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72 \ - --hash=sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061 \ - --hash=sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f \ - --hash=sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9 \ - --hash=sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04 \ - --hash=sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98 \ - --hash=sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9 \ - --hash=sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f \ - --hash=sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b \ - --hash=sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925 \ - --hash=sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6 \ - --hash=sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0 \ - --hash=sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9 \ - --hash=sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c \ - --hash=sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991 \ - --hash=sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6 \ - --hash=sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000 \ - --hash=sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb \ - --hash=sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119 \ - --hash=sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b \ - --hash=sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58 +wrapt==1.17.3 \ + --hash=sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56 \ + --hash=sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828 \ + --hash=sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f \ + --hash=sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396 \ + --hash=sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77 \ + --hash=sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d \ + --hash=sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139 \ + --hash=sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7 \ + --hash=sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb \ + --hash=sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f \ + --hash=sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f \ + --hash=sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067 \ + --hash=sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f \ + --hash=sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7 \ + --hash=sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b \ + --hash=sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc \ + --hash=sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05 \ + --hash=sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd \ + --hash=sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7 \ + --hash=sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9 \ + --hash=sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81 \ + --hash=sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977 \ + --hash=sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa \ + --hash=sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b \ + --hash=sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe \ + --hash=sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58 \ + --hash=sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8 \ + --hash=sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77 \ + --hash=sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85 \ + --hash=sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c \ + --hash=sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df \ + --hash=sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454 \ + --hash=sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a \ + --hash=sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e \ + --hash=sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c \ + --hash=sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6 \ + --hash=sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5 \ + --hash=sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9 \ + --hash=sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd \ + --hash=sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277 \ + --hash=sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225 \ + --hash=sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22 \ + --hash=sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116 \ + --hash=sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16 \ + --hash=sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc \ + --hash=sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00 \ + --hash=sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2 \ + --hash=sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a \ + --hash=sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804 \ + --hash=sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04 \ + --hash=sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1 \ + --hash=sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba \ + --hash=sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390 \ + --hash=sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0 \ + --hash=sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d \ + --hash=sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22 \ + --hash=sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0 \ + --hash=sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2 \ + --hash=sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18 \ + --hash=sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6 \ + --hash=sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311 \ + --hash=sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89 \ + --hash=sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f \ + --hash=sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39 \ + --hash=sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4 \ + --hash=sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5 \ + --hash=sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa \ + --hash=sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a \ + --hash=sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050 \ + --hash=sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6 \ + --hash=sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235 \ + --hash=sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056 \ + --hash=sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2 \ + --hash=sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418 \ + --hash=sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c \ + --hash=sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a \ + --hash=sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6 \ + --hash=sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0 \ + --hash=sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775 \ + --hash=sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10 \ + --hash=sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c # via opentelemetry-instrumentation zipp==3.23.0 \ --hash=sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e \ From a36bbc8e2fed53ec1823f14f88113080d4e54fc5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:42:57 +0200 Subject: [PATCH 508/582] chore(deps): update dependency build to v1.3.0 (#739) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4d0f9aadd1e9..bc60545e76b7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -8,9 +8,9 @@ alembic==1.16.4 \ --hash=sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d \ --hash=sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2 # via -r requirements.in -build==1.2.2.post1 \ - --hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \ - --hash=sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7 +build==1.3.0 \ + --hash=sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397 \ + --hash=sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4 # via # -r requirements.in # pip-tools From fff395c96be3c34678a28779405482828c57200a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 10:46:39 +0200 Subject: [PATCH 509/582] chore(deps): update dependency typing-extensions to v4.14.1 (#711) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index bc60545e76b7..7401c958cee6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -527,9 +527,9 @@ tomli==2.2.1 \ --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in -typing-extensions==4.14.0 \ - --hash=sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4 \ - --hash=sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af +typing-extensions==4.14.1 \ + --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ + --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 # via # alembic # opentelemetry-api From 87e0174379697df9e95c886537162558a38cf684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 18 Aug 2025 11:18:44 +0200 Subject: [PATCH 510/582] chore: update blunderbuss config (#734) --- packages/sqlalchemy-spanner/.github/blunderbuss.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/.github/blunderbuss.yml b/packages/sqlalchemy-spanner/.github/blunderbuss.yml index 68b2d1df5465..479642220940 100644 --- a/packages/sqlalchemy-spanner/.github/blunderbuss.yml +++ b/packages/sqlalchemy-spanner/.github/blunderbuss.yml @@ -1,2 +1,2 @@ assign_issues: - - harshachinta + - olavloite From 261c7b31ece8417d59538bedcea74c16fe65c3fa Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 18 Aug 2025 02:28:22 -0700 Subject: [PATCH 511/582] feat: add license metadata to setup.py (#712) Add license metadata to setup.py Mirrors what we do in similar repos like: https://togithub.com/googleapis/python-spanner/blob/main/setup.py#L81 --- packages/sqlalchemy-spanner/setup.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 2c039fe76278..67cd184b94c4 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -58,7 +58,11 @@ setuptools.setup( author="Google LLC", author_email="googleapis-packages@google.com", - classifiers=["Intended Audience :: Developers"], + license="Apache 2.0", + classifiers=[ + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + ], description=description, long_description=readme, entry_points={ From c2f5a3d19d7eed1bdfb005dc1f0cb08a11882b9e Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 18 Aug 2025 03:12:27 -0700 Subject: [PATCH 512/582] feat: support informational foreign keys (#719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support informational foreign keys Add support for informational foreign keys with the 'not enforced' keyword: https://cloud.google.com/spanner/docs/foreign-keys/overview#create-table-with-informational-fk Fixes #718 * chore: create runnable sample --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 6 ++ .../samples/informational_fk_sample.py | 92 +++++++++++++++++++ packages/sqlalchemy-spanner/samples/model.py | 12 ++- .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../samples/sample_helper.py | 26 ++++-- .../mockserver_tests/not_enforced_fk_model.py | 37 ++++++++ .../mockserver_tests/test_not_enforced_fk.py | 74 +++++++++++++++ 7 files changed, 244 insertions(+), 8 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/informational_fk_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/not_enforced_fk_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_not_enforced_fk.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index d868daf94079..ffa393fdb68f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -652,6 +652,12 @@ def visit_unique_constraint(self, constraint, **kw): "Create UNIQUE indexes instead." ) + def visit_foreign_key_constraint(self, constraint, **kw): + text = super().visit_foreign_key_constraint(constraint, **kw) + if constraint.dialect_options.get("spanner", {}).get("not_enforced", False): + text += " NOT ENFORCED" + return text + def post_create_table(self, table): """Build statements to be executed after CREATE TABLE. diff --git a/packages/sqlalchemy-spanner/samples/informational_fk_sample.py b/packages/sqlalchemy-spanner/samples/informational_fk_sample.py new file mode 100644 index 000000000000..4e330dae5ca4 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/informational_fk_sample.py @@ -0,0 +1,92 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import uuid + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Singer, Concert, Venue, TicketSale + + +# Shows how to create a non-enforced foreign key. +# +# The TicketSale model contains two foreign keys that are not enforced by Spanner. +# This allows the related records to be deleted without the need to delete the +# corresponding TicketSale record. +# +# __table_args__ = ( +# ForeignKeyConstraint( +# ["venue_code", "start_time", "singer_id"], +# ["concerts.venue_code", "concerts.start_time", "concerts.singer_id"], +# spanner_not_enforced=True, +# ), +# ) +# singer_id: Mapped[str] = mapped_column(String(36), ForeignKey("singers.id", spanner_not_enforced=True)) +# +# See https://cloud.google.com/spanner/docs/foreign-keys/overview#informational-foreign-keys +# for more information on informational foreign key constrains. +def informational_fk_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # First create a singer, venue, concert and ticket_sale. + singer_id = str(uuid.uuid4()) + ticket_sale_id = None + with Session(engine) as session: + singer = Singer(id=singer_id, first_name="John", last_name="Doe") + venue = Venue(code="CH", name="Concert Hall", active=True) + concert = Concert( + venue=venue, + start_time=datetime.datetime(2024, 11, 7, 19, 30, 0), + singer=singer, + title="John Doe - Live in Concert Hall", + ) + ticket_sale = TicketSale( + concert=concert, customer_name="Alice Doe", seats=["A010", "A011", "A012"] + ) + session.add_all([singer, venue, concert, ticket_sale]) + session.commit() + ticket_sale_id = ticket_sale.id + + # Now delete both the singer and concert that are referenced by the ticket_sale record. + # This is possible as the foreign key constraints between ticket_sales and singers/concerts + # are not enforced. + with Session(engine) as session: + session.delete(concert) + session.delete(singer) + session.commit() + + # Verify that the ticket_sale record still exists, while the concert and singer have been + # deleted. + with Session(engine) as session: + ticket_sale = session.get(TicketSale, ticket_sale_id) + singer = session.get(Singer, singer_id) + concert = session.get( + Concert, ("CH", datetime.datetime(2024, 11, 7, 19, 30, 0), singer_id) + ) + print( + "Ticket sale found: {}\nSinger found: {}\nConcert found: {}\n".format( + ticket_sale is not None, singer is not None, concert is not None + ) + ) + + +if __name__ == "__main__": + run_sample(informational_fk_sample) diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index c7c683011e8b..faa8a53588c1 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -154,7 +154,9 @@ class Concert(Base): title: Mapped[str] = mapped_column(String(200), nullable=False) singer: Mapped["Singer"] = relationship(back_populates="concerts") venue: Mapped["Venue"] = relationship(back_populates="concerts") - ticket_sales: Mapped[List["TicketSale"]] = relationship(back_populates="concert") + ticket_sales: Mapped[List["TicketSale"]] = relationship( + back_populates="concert", passive_deletes=True + ) class TicketSale(Base): @@ -163,6 +165,7 @@ class TicketSale(Base): ForeignKeyConstraint( ["venue_code", "start_time", "singer_id"], ["concerts.venue_code", "concerts.start_time", "concerts.singer_id"], + spanner_not_enforced=True, ), ) id: Mapped[int] = mapped_column( @@ -178,7 +181,12 @@ class TicketSale(Base): start_time: Mapped[Optional[datetime.datetime]] = mapped_column( DateTime, nullable=False ) - singer_id: Mapped[str] = mapped_column(String(36), ForeignKey("singers.id")) + # Create an informational foreign key that is not enforced by Spanner. + # See https://cloud.google.com/spanner/docs/foreign-keys/overview#informational-foreign-keys + # for more information. + singer_id: Mapped[str] = mapped_column( + String(36), ForeignKey("singers.id", spanner_not_enforced=True) + ) # Create a commit timestamp column and set a client-side default of # PENDING_COMMIT_TIMESTAMP() An event handler below is responsible for # setting PENDING_COMMIT_TIMESTAMP() on updates. If using SQLAlchemy diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 8c95f052c07b..880bca48c307 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -87,6 +87,11 @@ def database_role(session): _sample(session) +@nox.session() +def informational_fk(session): + _sample(session) + + @nox.session() def _all_samples(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/samples/sample_helper.py b/packages/sqlalchemy-spanner/samples/sample_helper.py index b1c068f8cf7c..f10268b2cb8c 100644 --- a/packages/sqlalchemy-spanner/samples/sample_helper.py +++ b/packages/sqlalchemy-spanner/samples/sample_helper.py @@ -16,8 +16,10 @@ from typing import Callable from google.api_core.client_options import ClientOptions +from google.api_core.exceptions import AlreadyExists from google.auth.credentials import AnonymousCredentials from google.cloud.spanner_v1 import Client +from google.cloud.spanner_v1.database import Database from sqlalchemy import create_engine from sqlalchemy.dialects import registry from testcontainers.core.container import DockerContainer @@ -32,9 +34,15 @@ def run_sample(sample_method: Callable): "google.cloud.sqlalchemy_spanner.sqlalchemy_spanner", "SpannerDialect", ) - os.environ["SPANNER_EMULATOR_HOST"] = "" - emulator, port = start_emulator() - os.environ["SPANNER_EMULATOR_HOST"] = "localhost:" + str(port) + emulator = None + if os.getenv("USE_EXISTING_EMULATOR") == "true": + if os.getenv("SPANNER_EMULATOR_HOST") is None: + os.environ["SPANNER_EMULATOR_HOST"] = "localhost:9010" + _create_instance_and_database("9010") + else: + os.environ["SPANNER_EMULATOR_HOST"] = "" + emulator, port = start_emulator() + os.environ["SPANNER_EMULATOR_HOST"] = "localhost:" + str(port) try: _create_tables() sample_method() @@ -68,10 +76,16 @@ def _create_instance_and_database(port: str): database_id = "sample-database" instance = client.instance(instance_id, instance_config) - created_op = instance.create() - created_op.result(1800) # block until completion + try: + created_op = instance.create() + created_op.result(1800) # block until completion + except AlreadyExists: + # Ignore + print("Using existing instance") - database = instance.database(database_id) + database: Database = instance.database(database_id) + if database.exists(): + database.drop() created_op = database.create() created_op.result(1800) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/not_enforced_fk_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/not_enforced_fk_model.py new file mode 100644 index 000000000000..36965f01dfd4 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/not_enforced_fk_model.py @@ -0,0 +1,37 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import ForeignKey +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[str] = mapped_column(primary_key=True) + name: Mapped[str] + + +class Album(Base): + __tablename__ = "albums" + id: Mapped[str] = mapped_column(primary_key=True) + name: Mapped[str] + singer_id: Mapped[str] = mapped_column( + ForeignKey("singers.id", spanner_not_enforced=True) + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_not_enforced_fk.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_not_enforced_fk.py new file mode 100644 index 000000000000..b2253d1b92f0 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_not_enforced_fk.py @@ -0,0 +1,74 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest + + +class TestNotEnforcedFK(MockServerTestBase): + """Ensure we emit correct DDL for not enforced foreign keys.""" + + def test_create_table(self): + from test.mockserver_tests.not_enforced_fk_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="albums" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(2, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid STRING(MAX) NOT NULL, \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + eq_( + "CREATE TABLE albums (\n" + "\tid STRING(MAX) NOT NULL, \n" + "\tname STRING(MAX) NOT NULL, \n" + "\tsinger_id STRING(MAX) NOT NULL, \n" + "\tFOREIGN KEY(singer_id) REFERENCES singers (id) NOT ENFORCED\n" + ") PRIMARY KEY (id)", + requests[0].statements[1], + ) From 4cdc01be2fd82334fe940dfc3142ecde57bab9fd Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 12:43:38 +0200 Subject: [PATCH 513/582] chore(deps): update actions/checkout action to v5 (#741) --- .../.github/workflows/test_suite.yml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 6ffc17d25806..d1627b90bb2e 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -58,7 +58,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -104,7 +104,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -129,7 +129,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -153,7 +153,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -177,7 +177,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: @@ -201,7 +201,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python uses: actions/setup-python@v5 with: From de0f29c273bcca95f9fc270f8e7de25755427a0b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 18 Aug 2025 13:34:43 +0200 Subject: [PATCH 514/582] chore(deps): update dependency cachetools to v6 (#742) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7401c958cee6..11c52cc534c4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.3.0 \ # via # -r requirements.in # pip-tools -cachetools==5.5.2 \ - --hash=sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4 \ - --hash=sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a +cachetools==6.1.0 \ + --hash=sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e \ + --hash=sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587 # via google-auth certifi==2025.8.3 \ --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ From 454849f90e0c5c06a2a7d3603d39501eac6a8f65 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 18 Aug 2025 07:10:26 -0700 Subject: [PATCH 515/582] feat: enable SQLAlchemy 2.0's insertmany feature (#721) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: enable SQLAlchemy 2.0's insertmany feature - Enable the use_insertmanyvalues flag on the dialect to support SQLAlchemy 2.0's insertmany feature, which allows multiple ORM objects to be inserted together in bulk, even if the table has server-side generated values which must be included in a THEN RETURN clause - Provide an example for using the feature with client-side supplied UUIDs and insert_sentinel columns. - Ensure that the feature is not enables for bit-reversed primary keys. In other dialects, an incrementing primary key can be used rather than a sentinel column. In Spanner, the bit-reversed integers do not meet the ordering requirement to be used as implicit sentinels https://docs.sqlalchemy.org/en/20/core/internals.html#sqlalchemy.engine.default.DefaultDialect.use_insertmanyvalues https://docs.sqlalchemy.org/en/20/core/connections.html#insert-many-values-behavior-for-insert-statements https://docs.sqlalchemy.org/en/20/core/connections.html#configuring-sentinel-columns Fixes: #720 * chore: update tests for multiplexed sessions * chore: make sample runnable * fix: exclude commit_timestamp col from THEN RETURN --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 10 +- .../samples/insertmany_sample.py | 84 ++++++++ .../sqlalchemy-spanner/samples/noxfile.py | 5 + .../test/mockserver_tests/insertmany_model.py | 48 +++++ .../test/mockserver_tests/test_insertmany.py | 191 ++++++++++++++++++ .../test/system/test_basics.py | 2 + 6 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 packages/sqlalchemy-spanner/samples/insertmany_sample.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/insertmany_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_insertmany.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index ffa393fdb68f..e3fb563c2524 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -425,7 +425,14 @@ def returning_clause(self, stmt, returning_cols, **kw): self._label_select_column( None, c, True, False, {"spanner_is_returning": True} ) - for c in expression._select_iterables(returning_cols) + for c in expression._select_iterables( + filter( + lambda col: not col.dialect_options.get("spanner", {}).get( + "exclude_from_returning", False + ), + returning_cols, + ) + ) ] return "THEN RETURN " + ", ".join(columns) @@ -831,6 +838,7 @@ class SpannerDialect(DefaultDialect): update_returning = True delete_returning = True supports_multivalues_insert = True + use_insertmanyvalues = True ddl_compiler = SpannerDDLCompiler preparer = SpannerIdentifierPreparer diff --git a/packages/sqlalchemy-spanner/samples/insertmany_sample.py b/packages/sqlalchemy-spanner/samples/insertmany_sample.py new file mode 100644 index 000000000000..859bc1588d69 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/insertmany_sample.py @@ -0,0 +1,84 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from datetime import datetime +import uuid +from sqlalchemy import text, String, create_engine +from sqlalchemy.orm import DeclarativeBase, Session +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column +from sample_helper import run_sample + + +class Base(DeclarativeBase): + pass + + +# To use SQLAlchemy 2.0's insertmany feature, models must have a +# unique column marked as an "insert_sentinal" with client-side +# generated values passed into it. This allows SQLAlchemy to perform a +# single bulk insert, even if the table has columns with server-side +# defaults which must be retrieved from a THEN RETURN clause, for +# operations like: +# +# with Session.begin() as session: +# session.add(Singer(name="a")) +# session.add(Singer(name="b")) +# +# Read more in the SQLAlchemy documentation of this feature: +# https://docs.sqlalchemy.org/en/20/core/connections.html#configuring-sentinel-columns + + +class Singer(Base): + __tablename__ = "singers_with_sentinel" + id: Mapped[str] = mapped_column( + String(36), + primary_key=True, + # Supply a unique UUID client-side + default=lambda: str(uuid.uuid4()), + # The column is unique and can be used as an insert_sentinel + insert_sentinel=True, + # Set a server-side default for write outside SQLAlchemy + server_default=text("GENERATE_UUID()"), + ) + name: Mapped[str] + inserted_at: Mapped[datetime] = mapped_column( + server_default=text("CURRENT_TIMESTAMP()") + ) + + +# Shows how to insert data using SQLAlchemy, including relationships that are +# defined both as foreign keys and as interleaved tables. +def insertmany(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + # Create the sample table. + Base.metadata.create_all(engine) + + # Insert two singers in one session. These two singers will be inserted using + # a single INSERT statement with a THEN RETURN clause to return the generated + # creation timestamp. + with Session(engine) as session: + session.add(Singer(name="John Smith")) + session.add(Singer(name="Jane Smith")) + session.commit() + + +if __name__ == "__main__": + run_sample(insertmany) diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index 880bca48c307..cd28a3f0be95 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -92,6 +92,11 @@ def informational_fk(session): _sample(session) +@nox.session() +def insertmany(session): + _sample(session) + + @nox.session() def _all_samples(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/insertmany_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/insertmany_model.py new file mode 100644 index 000000000000..a196e142db16 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/insertmany_model.py @@ -0,0 +1,48 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from datetime import datetime +import uuid +from sqlalchemy import text, String +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class SingerUUID(Base): + __tablename__ = "singers_uuid" + id: Mapped[str] = mapped_column( + String(36), + primary_key=True, + server_default=text("GENERATE_UUID()"), + default=lambda: str(uuid.uuid4()), + insert_sentinel=True, + ) + name: Mapped[str] + inserted_at: Mapped[datetime] = mapped_column( + server_default=text("CURRENT_TIMESTAMP()") + ) + + +class SingerIntID(Base): + __tablename__ = "singers_int_id" + id: Mapped[int] = mapped_column(primary_key=True) + name: Mapped[str] = mapped_column(String) + inserted_at: Mapped[datetime] = mapped_column( + server_default=text("CURRENT_TIMESTAMP()") + ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_insertmany.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_insertmany.py new file mode 100644 index 000000000000..f5b9f882e3a4 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_insertmany.py @@ -0,0 +1,191 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid +from unittest import mock + +import sqlalchemy +from sqlalchemy.orm import Session +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + ExecuteSqlRequest, + CommitRequest, + RollbackRequest, + BeginTransactionRequest, + CreateSessionRequest, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +import google.cloud.spanner_v1.types.type as spanner_type +import google.cloud.spanner_v1.types.result_set as result_set + + +class TestInsertmany(MockServerTestBase): + @mock.patch.object(uuid, "uuid4", mock.MagicMock(side_effect=["a", "b"])) + def test_insertmany_with_uuid_sentinels(self): + """Ensures one bulk insert for ORM objects distinguished by uuid.""" + from test.mockserver_tests.insertmany_model import SingerUUID + + self.add_uuid_insert_result( + "INSERT INTO singers_uuid (id, name) " + "VALUES (@a0, @a1), (@a2, @a3) " + "THEN RETURN inserted_at, id" + ) + engine = self.create_engine() + + with Session(engine) as session: + session.add(SingerUUID(name="a")) + session.add(SingerUUID(name="b")) + session.commit() + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(4, 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) + + def test_no_insertmany_with_bit_reversed_id(self): + """Ensures we don't try to bulk insert rows with bit-reversed PKs. + + SQLAlchemy's insertmany support requires either incrementing + PKs or client-side supplied sentinel values such as UUIDs. + Spanner's bit-reversed integer PKs don't meet the ordering + requirement, so we need to make sure we don't try to bulk + insert with them. + """ + from test.mockserver_tests.insertmany_model import SingerIntID + + self.add_int_id_insert_result( + "INSERT INTO singers_int_id (name) " + "VALUES (@a0) " + "THEN RETURN id, inserted_at" + ) + engine = self.create_engine() + + with Session(engine) as session: + session.add(SingerIntID(name="a")) + session.add(SingerIntID(name="b")) + try: + session.commit() + except sqlalchemy.exc.SAWarning: + # This will fail because we're returning the same PK + # for two rows. The mock server doesn't currently + # support associating the same query with two + # different results. For our purposes that's okay -- + # we just want to ensure we generate two INSERTs, not + # one. + pass + + # Verify the requests that we got. + requests = self.spanner_service.requests + eq_(5, 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], ExecuteSqlRequest) + is_instance_of(requests[4], RollbackRequest) + + def add_uuid_insert_result(self, sql): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="inserted_at", + type=spanner_type.Type( + dict( + code=spanner_type.TypeCode.TIMESTAMP + ) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.STRING) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "2020-06-02T23:58:40Z", + "a", + ), + ( + "2020-06-02T23:58:41Z", + "b", + ), + ] + ) + add_result(sql, result) + + def add_int_id_insert_result(self, sql): + result = result_set.ResultSet( + dict( + metadata=result_set.ResultSetMetadata( + dict( + row_type=spanner_type.StructType( + dict( + fields=[ + spanner_type.StructType.Field( + dict( + name="id", + type=spanner_type.Type( + dict(code=spanner_type.TypeCode.INT64) + ), + ) + ), + spanner_type.StructType.Field( + dict( + name="inserted_at", + type=spanner_type.Type( + dict( + code=spanner_type.TypeCode.TIMESTAMP + ) + ), + ) + ), + ] + ) + ) + ) + ), + ) + ) + result.rows.extend( + [ + ( + "1", + "2020-06-02T23:58:40Z", + ), + ] + ) + add_result(sql, result) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 7ea6fa2bda5d..30a61865ab1a 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -316,6 +316,8 @@ class TimestampUser(Base): updated_at: Mapped[datetime.datetime] = mapped_column( spanner_allow_commit_timestamp=True, default=text("PENDING_COMMIT_TIMESTAMP()"), + # Make sure that this column is never part of a THEN RETURN clause. + spanner_exclude_from_returning=True, ) @event.listens_for(TimestampUser, "before_update") From 6dbd4d3f90bc78f4f334882f0ef64da0a6c92e50 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 18 Aug 2025 07:12:48 -0700 Subject: [PATCH 516/582] fix: Respect existing server default in alter column DDL (#733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Correctly Generate DDL for ALTER COLUMN ... SET DEFAULT Alembic expects `get_column_default_string` to be implemented in order to use it for `ALTER TABLE.. ALTER COLUMN .. SET DEFAULT` DDL. In our case, this means wrapping the default value in parentheses. We implement `get_column_default_string` and have it add parentheses for use in both `CREATE TABLE` and `ALTER TABLE` DDL. Call path for alembic relying on `get_column_default_string` is here: https://github.com/sqlalchemy/alembic/blob/cd4f404358f101b2b930013c609c074baca61468/alembic/ddl/base.py#L252 https://github.com/sqlalchemy/alembic/blob/cd4f404358f101b2b930013c609c074baca61468/alembic/ddl/base.py#L315 * fix: Respect existing server default in alter column DDL Include `DEFAULT (default_value)` stanzas in `ALTER COLUMN` DDL to avoid removing `DEFAULT` values when changing a column's type or nullability. Fixes: #732 * chore: ignore booleans --------- Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 58 ++++++++--- .../test/mockserver_tests/default_model.py | 30 ++++++ .../test/mockserver_tests/test_default.py | 49 ++++++++++ .../sqlalchemy-spanner/test/unit/__init__.py | 0 .../test/unit/test_alembic.py | 97 +++++++++++++++++++ 5 files changed, 223 insertions(+), 11 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/default_model.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_default.py create mode 100644 packages/sqlalchemy-spanner/test/unit/__init__.py create mode 100644 packages/sqlalchemy-spanner/test/unit/test_alembic.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e3fb563c2524..2ece349f0dd0 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -20,6 +20,7 @@ ColumnType, alter_column, alter_table, + format_server_default, format_type, ) from google.api_core.client_options import ClientOptions @@ -579,7 +580,7 @@ def get_column_specification(self, column, **kwargs): elif has_identity: colspec += " " + self.process(column.identity) elif default is not None: - colspec += " DEFAULT (" + default + ")" + colspec += f" DEFAULT {default}" elif hasattr(column, "computed") and column.computed is not None: colspec += " " + self.process(column.computed) @@ -590,6 +591,13 @@ def get_column_specification(self, column, **kwargs): return colspec + def get_column_default_string(self, column): + default = super().get_column_default_string(column) + if default is not None: + return f"({default})" + + return default + def visit_computed_column(self, generated, **kw): """Computed column operator.""" text = "AS (%s) STORED" % self.sql_compiler.process( @@ -1860,11 +1868,14 @@ def do_execute_no_params(self, cursor, statement, context=None): def visit_column_nullable( element: "ColumnNullable", compiler: "SpannerDDLCompiler", **kw ) -> str: - return "%s %s %s %s" % ( - alter_table(compiler, element.table_name, element.schema), - alter_column(compiler, element.column_name), - format_type(compiler, element.existing_type), - "" if element.nullable else "NOT NULL", + return _format_alter_column( + compiler, + element.table_name, + element.schema, + element.column_name, + element.existing_type, + element.nullable, + element.existing_server_default, ) @@ -1873,9 +1884,34 @@ def visit_column_nullable( def visit_column_type( element: "ColumnType", compiler: "SpannerDDLCompiler", **kw ) -> str: - return "%s %s %s %s" % ( - alter_table(compiler, element.table_name, element.schema), - alter_column(compiler, element.column_name), - "%s" % format_type(compiler, element.type_), - "" if element.existing_nullable else "NOT NULL", + return _format_alter_column( + compiler, + element.table_name, + element.schema, + element.column_name, + element.type_, + element.existing_nullable, + element.existing_server_default, + ) + + +def _format_alter_column( + compiler, table_name, schema, column_name, type_, nullable, server_default +): + # Older versions of SQLAlchemy pass in a boolean to indicate whether there + # is an existing DEFAULT constraint, instead of the actual DEFAULT constraint + # expression. In those cases, we do not want to explicitly include the DEFAULT + # constraint in the expression that is generated here. + if isinstance(server_default, bool): + server_default = None + return "%s %s %s%s%s" % ( + alter_table(compiler, table_name, schema), + alter_column(compiler, column_name), + format_type(compiler, type_), + "" if nullable else " NOT NULL", + ( + "" + if server_default is None + else f" DEFAULT {format_server_default(compiler, server_default)}" + ), ) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/default_model.py b/packages/sqlalchemy-spanner/test/mockserver_tests/default_model.py new file mode 100644 index 000000000000..6a363c572598 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/default_model.py @@ -0,0 +1,30 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import func +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + id: Mapped[str] = mapped_column( + server_default=func.GENERATE_UUID(), primary_key=True + ) + name: Mapped[str] diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_default.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_default.py new file mode 100644 index 000000000000..9b46ede00d5d --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_default.py @@ -0,0 +1,49 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import FixedSizePool, ResultSet +from test.mockserver_tests.mock_server_test_base import MockServerTestBase, add_result +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest + + +class TestCreateTableDefault(MockServerTestBase): + def test_create_table_with_default(self): + from test.mockserver_tests.default_model import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(1, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid STRING(MAX) NOT NULL DEFAULT (GENERATE_UUID()), \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) diff --git a/packages/sqlalchemy-spanner/test/unit/__init__.py b/packages/sqlalchemy-spanner/test/unit/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/sqlalchemy-spanner/test/unit/test_alembic.py b/packages/sqlalchemy-spanner/test/unit/test_alembic.py new file mode 100644 index 000000000000..75e395618f25 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/unit/test_alembic.py @@ -0,0 +1,97 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from alembic.ddl import base as ddl_base +from google.cloud.sqlalchemy_spanner import sqlalchemy_spanner +from sqlalchemy import String, TextClause +from sqlalchemy.testing import eq_ +from sqlalchemy.testing.plugin.plugin_base import fixtures + + +class TestAlembicTest(fixtures.TestBase): + def test_visit_column_nullable_with_not_null_column(self): + ddl = sqlalchemy_spanner.visit_column_nullable( + ddl_base.ColumnNullable( + name="tbl", column_name="col", nullable=False, existing_type=String(256) + ), + sqlalchemy_spanner.SpannerDDLCompiler( + sqlalchemy_spanner.SpannerDialect(), None + ), + ) + eq_(ddl, "ALTER TABLE tbl ALTER COLUMN col STRING(256) NOT NULL") + + def test_visit_column_nullable_with_nullable_column(self): + ddl = sqlalchemy_spanner.visit_column_nullable( + ddl_base.ColumnNullable( + name="tbl", column_name="col", nullable=True, existing_type=String(256) + ), + sqlalchemy_spanner.SpannerDDLCompiler( + sqlalchemy_spanner.SpannerDialect(), None + ), + ) + eq_(ddl, "ALTER TABLE tbl ALTER COLUMN col STRING(256)") + + def test_visit_column_nullable_with_default(self): + ddl = sqlalchemy_spanner.visit_column_nullable( + ddl_base.ColumnNullable( + name="tbl", + column_name="col", + nullable=False, + existing_type=String(256), + existing_server_default=TextClause("GENERATE_UUID()"), + ), + sqlalchemy_spanner.SpannerDDLCompiler( + sqlalchemy_spanner.SpannerDialect(), None + ), + ) + eq_( + ddl, + "ALTER TABLE tbl " + "ALTER COLUMN col " + "STRING(256) NOT NULL DEFAULT (GENERATE_UUID())", + ) + + def test_visit_column_type(self): + ddl = sqlalchemy_spanner.visit_column_type( + ddl_base.ColumnType( + name="tbl", + column_name="col", + type_=String(256), + existing_nullable=True, + ), + sqlalchemy_spanner.SpannerDDLCompiler( + sqlalchemy_spanner.SpannerDialect(), None + ), + ) + eq_(ddl, "ALTER TABLE tbl ALTER COLUMN col STRING(256)") + + def test_visit_column_type_with_default(self): + ddl = sqlalchemy_spanner.visit_column_type( + ddl_base.ColumnType( + name="tbl", + column_name="col", + type_=String(256), + existing_nullable=False, + existing_server_default=TextClause("GENERATE_UUID()"), + ), + sqlalchemy_spanner.SpannerDDLCompiler( + sqlalchemy_spanner.SpannerDialect(), None + ), + ) + eq_( + ddl, + "ALTER TABLE tbl " + "ALTER COLUMN col " + "STRING(256) NOT NULL DEFAULT (GENERATE_UUID())", + ) From 5795ecb673950432efda5ea18b2dfb3dd877f72d Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Tue, 19 Aug 2025 06:25:54 -0700 Subject: [PATCH 517/582] fix: Report column defaults in introspection (#744) Retrieve the column default when introspecting columns. Currently, the default is hard-coded to None. Fixes: #730 --- .../google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py | 5 +++-- packages/sqlalchemy-spanner/test/system/test_basics.py | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 2ece349f0dd0..480747b02a6e 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1122,7 +1122,8 @@ def get_multi_columns( sql = """ SELECT col.table_schema, col.table_name, col.column_name, - col.spanner_type, col.is_nullable, col.generation_expression + col.spanner_type, col.is_nullable, col.generation_expression, + col.column_default FROM information_schema.columns as col JOIN information_schema.tables AS t USING (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) @@ -1150,7 +1151,7 @@ def get_multi_columns( "name": col[2], "type": self._designate_type(col[3]), "nullable": col[4] == "YES", - "default": None, + "default": col[6] if col[6] is not None else None, } if col[5] is not None: diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 30a61865ab1a..75d9682fb085 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -34,7 +34,7 @@ ) from sqlalchemy.orm import Session, DeclarativeBase, Mapped, mapped_column from sqlalchemy.types import REAL -from sqlalchemy.testing import eq_, is_true, is_not_none +from sqlalchemy.testing import eq_, is_true, is_not_none, is_none from sqlalchemy.testing.plugin.plugin_base import fixtures @@ -47,7 +47,7 @@ def define_tables(cls, metadata): Column("number", Integer), Column("name", String(20)), Column("alternative_name", String(20)), - Column("prime", Boolean), + Column("prime", Boolean, server_default=text("FALSE")), Column("ln", REAL), PrimaryKeyConstraint("number"), ) @@ -120,12 +120,15 @@ def test_reflect(self, connection): eq_(5, len(table.columns)) eq_("number", table.columns[0].name) eq_(BIGINT, type(table.columns[0].type)) + is_none(table.columns[0].server_default) eq_("name", table.columns[1].name) eq_(String, type(table.columns[1].type)) eq_("alternative_name", table.columns[2].name) eq_(String, type(table.columns[2].type)) eq_("prime", table.columns[3].name) eq_(Boolean, type(table.columns[3].type)) + is_not_none(table.columns[3].server_default) + eq_("FALSE", table.columns[3].server_default.arg.text) eq_("ln", table.columns[4].name) eq_(REAL, type(table.columns[4].type)) eq_(1, len(table.indexes)) From e6df532587efc3cdf6db1ea5388d1ba95717d933 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 19 Aug 2025 15:28:07 +0200 Subject: [PATCH 518/582] chore(deps): update dependency requests to v2.32.5 (#745) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 11c52cc534c4..843c977b8d4b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -420,9 +420,9 @@ pyproject-hooks==1.2.0 \ # via # build # pip-tools -requests==2.32.4 \ - --hash=sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c \ - --hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422 +requests==2.32.5 \ + --hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \ + --hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf # via google-api-core rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ From 2b8a3ee834c481199c311e910493cc4622d42c16 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 16:24:12 +0200 Subject: [PATCH 519/582] chore(main): release 1.15.0 (#743) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 15 +++++++++++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index fc7918b08214..1db3c76fee38 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.15.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.14.0...v1.15.0) (2025-08-19) + + +### Features + +* Add license metadata to setup.py ([#712](https://github.com/googleapis/python-spanner-sqlalchemy/issues/712)) ([8f2e97e](https://github.com/googleapis/python-spanner-sqlalchemy/commit/8f2e97e527b00bfb6db40d946a21f522177eab7b)) +* Enable SQLAlchemy 2.0's insertmany feature ([#721](https://github.com/googleapis/python-spanner-sqlalchemy/issues/721)) ([1fe9f4b](https://github.com/googleapis/python-spanner-sqlalchemy/commit/1fe9f4b0a2f94d66c925d1d60a1fd83fc45e9c89)) +* Support informational foreign keys ([#719](https://github.com/googleapis/python-spanner-sqlalchemy/issues/719)) ([c565ae1](https://github.com/googleapis/python-spanner-sqlalchemy/commit/c565ae12b1b429c66037e9cd0c4be427a60ab5b0)) + + +### Bug Fixes + +* Report column defaults in introspection ([#744](https://github.com/googleapis/python-spanner-sqlalchemy/issues/744)) ([309c641](https://github.com/googleapis/python-spanner-sqlalchemy/commit/309c64179d668dbe24881e6d7fb4783fb1d8bbf2)), closes [#730](https://github.com/googleapis/python-spanner-sqlalchemy/issues/730) +* Respect existing server default in alter column DDL ([#733](https://github.com/googleapis/python-spanner-sqlalchemy/issues/733)) ([1f8a25f](https://github.com/googleapis/python-spanner-sqlalchemy/commit/1f8a25f63286c1241141985d4f10f558e929a272)) + ## [1.14.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.13.1...v1.14.0) (2025-06-27) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index af1f26ba58a4..a55a585cbce4 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.14.0" +__version__ = "1.15.0" From 6030e071b68642076bce14f3d63dd2e02551e36f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 1 Sep 2025 11:06:24 +0200 Subject: [PATCH 520/582] chore(deps): update dependency typing-extensions to v4.15.0 (#746) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [typing-extensions](https://redirect.github.com/python/typing_extensions) ([changelog](https://redirect.github.com/python/typing_extensions/blob/main/CHANGELOG.md)) | `==4.14.1` -> `==4.15.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/typing-extensions/4.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/typing-extensions/4.14.1/4.15.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
python/typing_extensions (typing-extensions) ### [`v4.15.0`](https://redirect.github.com/python/typing_extensions/blob/HEAD/CHANGELOG.md#Release-4150-August-25-2025) [Compare Source](https://redirect.github.com/python/typing_extensions/compare/4.14.1...4.15.0) No user-facing changes since 4.15.0rc1.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 843c977b8d4b..7e9d725a20b4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -527,9 +527,9 @@ tomli==2.2.1 \ --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 # via -r requirements.in -typing-extensions==4.14.1 \ - --hash=sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36 \ - --hash=sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76 +typing-extensions==4.15.0 \ + --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ + --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 # via # alembic # opentelemetry-api From 1762c411434cb98f16518ae581d8bef808c4ce64 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 1 Sep 2025 11:08:27 +0200 Subject: [PATCH 521/582] chore(deps): update dependency cachetools to v6.2.0 (#747) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [cachetools](https://redirect.github.com/tkem/cachetools) | `==6.1.0` -> `==6.2.0` | [![age](https://developer.mend.io/api/mc/badges/age/pypi/cachetools/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/cachetools/6.1.0/6.2.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
tkem/cachetools (cachetools) ### [`v6.2.0`](https://redirect.github.com/tkem/cachetools/blob/HEAD/CHANGELOG.rst#v620-2025-08-25) [Compare Source](https://redirect.github.com/tkem/cachetools/compare/v6.1.0...v6.2.0) \=================== - Improve general `RRCache` performance by storing cache keys in an additional sequence container. Note that this will increase memory consumption. - Add more unit tests.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7e9d725a20b4..a722de062dbc 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.3.0 \ # via # -r requirements.in # pip-tools -cachetools==6.1.0 \ - --hash=sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e \ - --hash=sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587 +cachetools==6.2.0 \ + --hash=sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6 \ + --hash=sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32 # via google-auth certifi==2025.8.3 \ --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ From ecfcc37c26def8e54505157fca01ed3490cf05f0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 1 Sep 2025 11:25:02 +0200 Subject: [PATCH 522/582] chore(deps): update dependency alembic to v1.16.5 (#748) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index a722de062dbc..79fe090d44a5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.16.4 \ - --hash=sha256:b05e51e8e82efc1abd14ba2af6392897e145930c3e0a2faf2b0da2f7f7fd660d \ - --hash=sha256:efab6ada0dd0fae2c92060800e0bf5c1dc26af15a10e02fb4babff164b4725e2 +alembic==1.16.5 \ + --hash=sha256:a88bb7f6e513bd4301ecf4c7f2206fe93f9913f9b48dac3b78babde2d6fe765e \ + --hash=sha256:e845dfe090c5ffa7b92593ae6687c5cb1a101e91fa53868497dbd79847f9dbe3 # via -r requirements.in build==1.3.0 \ --hash=sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397 \ From b45297985dfd0ee53b976c230e2e7254efae73c5 Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 1 Sep 2025 03:03:49 -0700 Subject: [PATCH 523/582] feat: Support NULL FILTERED indexes (#750) Add support for the NULL FILTERED index option: https://cloud.google.com/spanner/docs/secondary-indexes#null-indexing-disable --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 9 +++ .../samples/null_filtered_index.py | 75 +++++++++++++++++ .../mockserver_tests/null_filtered_index.py | 37 +++++++++ .../test_null_filtered_index.py | 80 +++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 packages/sqlalchemy-spanner/samples/null_filtered_index.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/null_filtered_index.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_null_filtered_index.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 480747b02a6e..4ab387a9a662 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -718,6 +718,15 @@ def visit_create_index( text += " STORING (%s)" % ", ".join( [self.preparer.quote(c.name) for c in storing_columns] ) + + if options.get("null_filtered", False): + text = re.sub( + r"(^\s*CREATE\s+(?:UNIQUE\s+)?)INDEX", + r"\1NULL_FILTERED INDEX", + text, + flags=re.IGNORECASE, + ) + return text def get_identity_options(self, identity_options): diff --git a/packages/sqlalchemy-spanner/samples/null_filtered_index.py b/packages/sqlalchemy-spanner/samples/null_filtered_index.py new file mode 100644 index 000000000000..d8d9556f2bc4 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/null_filtered_index.py @@ -0,0 +1,75 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import uuid + +from sqlalchemy import create_engine, Index +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import mapped_column, DeclarativeBase, Mapped, Session + +from sample_helper import run_sample + +# Shows how to create a null-filtered index. +# +# A null-filtered index does not index NULL values. This is useful for +# maintaining smaller indexes over sparse columns. +# https://cloud.google.com/spanner/docs/secondary-indexes#null-indexing-disable + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers_with_null_filtered_index" + __table_args__ = ( + Index("uq_null_filtered_name", "name", unique=True, spanner_null_filtered=True), + ) + + id: Mapped[str] = mapped_column(primary_key=True, default=lambda: str(uuid.uuid4())) + name: Mapped[str | None] + + +def null_filtered_index_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + Base.metadata.create_all(engine) + + # We can create singers with a name of jdoe and NULL. + with Session(engine) as session: + session.add(Singer(name="jdoe")) + session.add(Singer(name=None)) + session.commit() + + # The unique index will stop us from adding another jdoe. + with Session(engine) as session: + session.add(Singer(name="jdoe")) + try: + session.commit() + except IntegrityError: + session.rollback() + + # The index is null filtered, so we can still add another + # NULL name. The NULL values are not part of the index. + with Session(engine) as session: + session.add(Singer(name=None)) + session.commit() + + +if __name__ == "__main__": + run_sample(null_filtered_index_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/null_filtered_index.py b/packages/sqlalchemy-spanner/test/mockserver_tests/null_filtered_index.py new file mode 100644 index 000000000000..e4ca5d69d778 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/null_filtered_index.py @@ -0,0 +1,37 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import Index +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + __table_args__ = ( + Index("idx_name", "name"), + Index("idx_uq_name", "name", unique=True), + Index("idx_null_filtered_name", "name", spanner_null_filtered=True), + Index( + "idx_uq_null_filtered_name", "name", unique=True, spanner_null_filtered=True + ), + ) + + id: Mapped[str] = mapped_column(primary_key=True) + name: Mapped[str] diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_null_filtered_index.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_null_filtered_index.py new file mode 100644 index 000000000000..28ed1b5db5d2 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_null_filtered_index.py @@ -0,0 +1,80 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest + + +class TestNullFilteredIndex(MockServerTestBase): + """Ensure we emit correct DDL for not null filtered indexes.""" + + def test_create_table(self): + from test.mockserver_tests.null_filtered_index import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="albums" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(5, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tid STRING(MAX) NOT NULL, \n" + "\tname STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (id)", + requests[0].statements[0], + ) + + # The order of the CREATE INDEX statements appears to be + # arbitrary, so we sort it for test consistency. + index_statements = sorted(requests[0].statements[1:]) + eq_("CREATE INDEX idx_name ON singers (name)", index_statements[0]) + eq_( + "CREATE NULL_FILTERED INDEX idx_null_filtered_name ON singers (name)", + index_statements[1], + ) + eq_("CREATE UNIQUE INDEX idx_uq_name ON singers (name)", index_statements[2]) + eq_( + "CREATE UNIQUE NULL_FILTERED INDEX " + "idx_uq_null_filtered_name ON singers (name)", + index_statements[3], + ) From ffbdd26e88b8214ee7bdcc6fcce927ab1d9a36ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Tue, 2 Sep 2025 10:09:08 +0200 Subject: [PATCH 524/582] docs: add sample for parse_json (#752) Add a sample and test for using the parse_json function with SQLAlchemy. Fixes #735 --- .../sqlalchemy-spanner/samples/noxfile.py | 5 ++ .../samples/parse_json_sample.py | 50 +++++++++++++++++++ .../test/mockserver_tests/test_json.py | 23 +++++++-- 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 packages/sqlalchemy-spanner/samples/parse_json_sample.py diff --git a/packages/sqlalchemy-spanner/samples/noxfile.py b/packages/sqlalchemy-spanner/samples/noxfile.py index cd28a3f0be95..29709cd1c37b 100644 --- a/packages/sqlalchemy-spanner/samples/noxfile.py +++ b/packages/sqlalchemy-spanner/samples/noxfile.py @@ -97,6 +97,11 @@ def insertmany(session): _sample(session) +@nox.session() +def parse_json(session): + _sample(session) + + @nox.session() def _all_samples(session): _sample(session) diff --git a/packages/sqlalchemy-spanner/samples/parse_json_sample.py b/packages/sqlalchemy-spanner/samples/parse_json_sample.py new file mode 100644 index 000000000000..b0868ea8d193 --- /dev/null +++ b/packages/sqlalchemy-spanner/samples/parse_json_sample.py @@ -0,0 +1,50 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine, func, text +from sqlalchemy.orm import Session + +from sample_helper import run_sample +from model import Venue + +# Shows how to use the PARSE_JSON function in Spanner using SQLAlchemy. +def parse_json_sample(): + engine = create_engine( + "spanner:///projects/sample-project/" + "instances/sample-instance/" + "databases/sample-database", + echo=True, + ) + with Session(engine) as session: + venue = Venue( + code="LCH", + active=True, + name="Large Concert Hall", + # The SQLAlchemy func function is very lenient and allows you to call any + # database function that Spanner supports. Use a text instance to add a + # specific SQL fragment to the function call. + description=func.parse_json( + '{"type": "Stadium", "size": 13.7391432}', + text("wide_number_mode=>'round'"), + ), + ) + session.add(venue) + session.commit() + + venue = session.query(Venue).filter_by(code="LCH").one() + print(venue.description) + + +if __name__ == "__main__": + run_sample(parse_json_sample) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py index 2d37a3350a3b..244e5d627576 100644 --- a/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_json.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sqlalchemy import select +from sqlalchemy import func, select, text from sqlalchemy.orm import Session from sqlalchemy.testing import eq_, is_instance_of from google.cloud.spanner_v1 import ( @@ -73,7 +73,24 @@ def test_insert_array(self): '[{"size":"Great","type":"Stadium"}]', ) - def _test_insert_json(self, description, expected): + def test_insert_fn(self): + add_update_count( + "INSERT INTO venues (id, name, description) " + "VALUES (@a0, @a1, parse_json(@a2, wide_number_mode=>'round'))", + 1, + ) + self._test_insert_json( + func.parse_json( + '{"type": "Stadium", "size": "Great"}', + text("wide_number_mode=>'round'"), + ), + '{"type": "Stadium", "size": "Great"}', + expected_type_code=TypeCode.STRING, + ) + + def _test_insert_json( + self, description, expected, expected_type_code=TypeCode.JSON + ): from test.mockserver_tests.json_model import Venue add_update_count( @@ -100,7 +117,7 @@ def _test_insert_json(self, description, expected): eq_(expected, request.params["a2"]) eq_(TypeCode.INT64, request.param_types["a0"].code) eq_(TypeCode.STRING, request.param_types["a1"].code) - eq_(TypeCode.JSON, request.param_types["a2"].code) + eq_(expected_type_code, request.param_types["a2"].code) def test_select_dict(self): self._test_select_json( From d33bc34c5efd23087ed3ed7269206c42717ea55a Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 10:16:17 +0200 Subject: [PATCH 525/582] chore(main): release 1.16.0 (#751) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 12 ++++++++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 1db3c76fee38..cf7788e2af6d 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.16.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.15.0...v1.16.0) (2025-09-02) + + +### Features + +* Support NULL FILTERED indexes ([#750](https://github.com/googleapis/python-spanner-sqlalchemy/issues/750)) ([4bc0589](https://github.com/googleapis/python-spanner-sqlalchemy/commit/4bc05898995a586816e116e0a3205966a52d1ef8)) + + +### Documentation + +* Add sample for parse_json ([#752](https://github.com/googleapis/python-spanner-sqlalchemy/issues/752)) ([b2f0e89](https://github.com/googleapis/python-spanner-sqlalchemy/commit/b2f0e89b8f01481fa6f29da055300eeb533591cc)), closes [#735](https://github.com/googleapis/python-spanner-sqlalchemy/issues/735) + ## [1.15.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.14.0...v1.15.0) (2025-08-19) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index a55a585cbce4..66d505de6c38 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.15.0" +__version__ = "1.16.0" From 8b2d350524e142fbe29bab81a4c830d23ba13b99 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 10:19:52 +0100 Subject: [PATCH 526/582] chore(deps): update actions/setup-python action to v6 (#753) --- .../.github/workflows/test_suite.yml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index d1627b90bb2e..82ddea2c3553 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Install nox @@ -27,7 +27,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.8 - name: Install nox @@ -45,7 +45,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Install nox @@ -60,7 +60,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Install nox @@ -82,7 +82,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.8 - name: Install nox @@ -106,7 +106,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.8 - name: Install nox @@ -131,7 +131,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Install nox @@ -155,7 +155,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Install nox @@ -179,7 +179,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.8 - name: Install nox @@ -203,7 +203,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.8 - name: Install nox From 04d9712d0219baaa9a9783761db4768364d1081f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 10:28:12 +0100 Subject: [PATCH 527/582] chore(deps): update opentelemetry-python monorepo to v1.37.0 (#754) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 79fe090d44a5..580559ca619f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -343,9 +343,9 @@ markupsafe==3.0.2 \ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 # via mako -opentelemetry-api==1.36.0 \ - --hash=sha256:02f20bcacf666e1333b6b1f04e647dc1d5111f86b8e510238fcc56d7762cda8c \ - --hash=sha256:9a72572b9c416d004d492cbc6e61962c0501eaf945ece9b5a0f56597d8348aa0 +opentelemetry-api==1.37.0 \ + --hash=sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7 \ + --hash=sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47 # via # -r requirements.in # opentelemetry-instrumentation @@ -355,9 +355,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.36.0 \ - --hash=sha256:19c8c81599f51b71670661ff7495c905d8fdf6976e41622d5245b791b06fa581 \ - --hash=sha256:19fe048b42e98c5c1ffe85b569b7073576ad4ce0bcb6e9b4c6a39e890a6c45fb +opentelemetry-sdk==1.37.0 \ + --hash=sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c \ + --hash=sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5 # via -r requirements.in opentelemetry-semantic-conventions==0.55b1 \ --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ From 03d5c3402c998faa1646b80a7ce3f184c3713554 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 10:30:05 +0100 Subject: [PATCH 528/582] chore(deps): update dependency protobuf to v6.32.1 (#755) --- packages/sqlalchemy-spanner/requirements.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 580559ca619f..792763e931db 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -383,16 +383,16 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==6.32.0 \ - --hash=sha256:15eba1b86f193a407607112ceb9ea0ba9569aed24f93333fe9a497cf2fda37d3 \ - --hash=sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1 \ - --hash=sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c \ - --hash=sha256:7db8ed09024f115ac877a1427557b838705359f047b2ff2f2b2364892d19dacb \ - --hash=sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741 \ - --hash=sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2 \ - --hash=sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e \ - --hash=sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783 \ - --hash=sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0 +protobuf==6.32.1 \ + --hash=sha256:2601b779fc7d32a866c6b4404f9d42a3f67c5b9f3f15b4db3cccabe06b95c346 \ + --hash=sha256:2f5b80a49e1eb7b86d85fcd23fe92df154b9730a725c3b38c4e43b9d77018bf4 \ + --hash=sha256:68ff170bac18c8178f130d1ccb94700cf72852298e016a2443bdb9502279e5f1 \ + --hash=sha256:a8a32a84bc9f2aad712041b8b366190f71dde248926da517bde9e832e4412085 \ + --hash=sha256:b00a7d8c25fa471f16bc8153d0e53d6c9e827f0953f3c09aaa4331c718cae5e1 \ + --hash=sha256:b1864818300c297265c83a4982fd3169f97122c299f56a56e2445c3698d34710 \ + --hash=sha256:d0975d0b2f3e6957111aa3935d08a0eb7e006b1505d825f862a1fffc8348e122 \ + --hash=sha256:d8c7e6eb619ffdf105ee4ab76af5a68b60a9d0f66da3ea12d1640e6d8dab7281 \ + --hash=sha256:ee2469e4a021474ab9baafea6cd070e5bf27c7d29433504ddea1a4ee5850f68d # via # google-api-core # google-cloud-spanner From a996309604faa6ebb30dba06799b9c0b5a600761 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 10:56:01 +0100 Subject: [PATCH 529/582] chore(deps): update dependency pyparsing to v3.2.5 (#756) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 792763e931db..db47209db3a3 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -410,9 +410,9 @@ pyasn1-modules==0.4.2 \ --hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \ --hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6 # via google-auth -pyparsing==3.2.3 \ - --hash=sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf \ - --hash=sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be +pyparsing==3.2.5 \ + --hash=sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6 \ + --hash=sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e # via -r requirements.in pyproject-hooks==1.2.0 \ --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ From 9e1d1c680e6d9d2393711173ed866fbab1396f50 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 10:58:23 +0100 Subject: [PATCH 530/582] chore(deps): update dependency grpcio to v1.75.1 (#757) --- packages/sqlalchemy-spanner/requirements.txt | 114 ++++++++++--------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index db47209db3a3..10ad7ba94eac 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -206,58 +206,68 @@ grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ --hash=sha256:1f45c0bcb58b6f332f37c637632247c9b02bc6af0fdceb7ba7ce8d2ebbfb0926 # via google-cloud-spanner -grpcio==1.74.0 \ - --hash=sha256:0f87bddd6e27fc776aacf7ebfec367b6d49cad0455123951e4488ea99d9b9b8f \ - --hash=sha256:136b53c91ac1d02c8c24201bfdeb56f8b3ac3278668cbb8e0ba49c88069e1bdc \ - --hash=sha256:1733969040989f7acc3d94c22f55b4a9501a30f6aaacdbccfaba0a3ffb255ab7 \ - --hash=sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7 \ - --hash=sha256:1a2b06afe2e50ebfd46247ac3ba60cac523f54ec7792ae9ba6073c12daf26f0a \ - --hash=sha256:1bf949792cee20d2078323a9b02bacbbae002b9e3b9e2433f2741c15bdeba1c4 \ - --hash=sha256:22b834cef33429ca6cc28303c9c327ba9a3fafecbf62fae17e9a7b7163cc43ac \ - --hash=sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6 \ - --hash=sha256:2bc2d7d8d184e2362b53905cb1708c84cb16354771c04b490485fa07ce3a1d89 \ - --hash=sha256:2f609a39f62a6f6f05c7512746798282546358a37ea93c1fcbadf8b2fed162e3 \ - --hash=sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49 \ - --hash=sha256:3b03d8f2a07f0fea8c8f74deb59f8352b770e3900d143b3d1475effcb08eec20 \ - --hash=sha256:3d14e3c4d65e19d8430a4e28ceb71ace4728776fd6c3ce34016947474479683f \ - --hash=sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc \ - --hash=sha256:4bc5fca10aaf74779081e16c2bcc3d5ec643ffd528d9e7b1c9039000ead73bae \ - --hash=sha256:4e4181bfc24413d1e3a37a0b7889bea68d973d4b45dd2bc68bb766c140718f82 \ - --hash=sha256:55b453812fa7c7ce2f5c88be3018fb4a490519b6ce80788d5913f3f9d7da8c7b \ - --hash=sha256:566b9395b90cc3d0d0c6404bc8572c7c18786ede549cdb540ae27b58afe0fb91 \ - --hash=sha256:5f251c355167b2360537cf17bea2cf0197995e551ab9da6a0a59b3da5e8704f9 \ - --hash=sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5 \ - --hash=sha256:64229c1e9cea079420527fa8ac45d80fc1e8d3f94deaa35643c381fa8d98f362 \ - --hash=sha256:655726919b75ab3c34cdad39da5c530ac6fa32696fb23119e36b64adcfca174a \ - --hash=sha256:662456c4513e298db6d7bd9c3b8df6f75f8752f0ba01fb653e252ed4a59b5a5d \ - --hash=sha256:68c8ebcca945efff9d86d8d6d7bfb0841cf0071024417e2d7f45c5e46b5b08eb \ - --hash=sha256:69e1a8180868a2576f02356565f16635b99088da7df3d45aaa7e24e73a054e31 \ - --hash=sha256:6bab67d15ad617aff094c382c882e0177637da73cbc5532d52c07b4ee887a87b \ - --hash=sha256:7d95d71ff35291bab3f1c52f52f474c632db26ea12700c2ff0ea0532cb0b5854 \ - --hash=sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1 \ - --hash=sha256:834988b6c34515545b3edd13e902c1acdd9f2465d386ea5143fb558f153a7176 \ - --hash=sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8 \ - --hash=sha256:85bd5cdf4ed7b2d6438871adf6afff9af7096486fcf51818a81b77ef4dd30907 \ - --hash=sha256:86ad489db097141a907c559988c29718719aa3e13370d40e20506f11b4de0d11 \ - --hash=sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c \ - --hash=sha256:8efe72fde5500f47aca1ef59495cb59c885afe04ac89dd11d810f2de87d935d4 \ - --hash=sha256:8f7b5882fb50632ab1e48cb3122d6df55b9afabc265582808036b6e51b9fd6b7 \ - --hash=sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707 \ - --hash=sha256:9e912d3c993a29df6c627459af58975b2e5c897d93287939b9d5065f000249b5 \ - --hash=sha256:a8f0302f9ac4e9923f98d8e243939a6fb627cd048f5cd38595c97e38020dffce \ - --hash=sha256:b6a73b2ba83e663b2480a90b82fdae6a7aa6427f62bf43b29912c0cfd1aa2bfa \ - --hash=sha256:c14e803037e572c177ba54a3e090d6eb12efd795d49327c5ee2b3bddb836bf01 \ - --hash=sha256:c3d7bd6e3929fd2ea7fbc3f562e4987229ead70c9ae5f01501a46701e08f1ad9 \ - --hash=sha256:c98e0b7434a7fa4e3e63f250456eaef52499fba5ae661c58cc5b5477d11e7182 \ - --hash=sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b \ - --hash=sha256:e154d230dc1bbbd78ad2fdc3039fa50ad7ffcf438e4eb2fa30bce223a70c7486 \ - --hash=sha256:e1ea6176d7dfd5b941ea01c2ec34de9531ba494d541fe2057c904e601879f249 \ - --hash=sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3 \ - --hash=sha256:e8978003816c7b9eabe217f88c78bc26adc8f9304bf6a594b02e5a49b2ef9c11 \ - --hash=sha256:ecde9ab49f58433abe02f9ed076c7b5be839cf0153883a6d23995937a82392fa \ - --hash=sha256:f6ec94f0e50eb8fa1744a731088b966427575e40c2944a980049798b127a687e \ - --hash=sha256:fd3c71aeee838299c5887230b8a1822795325ddfea635edd82954c1eaa831e24 \ - --hash=sha256:fe0f540750a13fd8e5da4b3eaba91a785eea8dca5ccd2bc2ffe978caa403090e +grpcio==1.75.1 \ + --hash=sha256:0049a7bf547dafaeeb1db17079ce79596c298bfe308fc084d023c8907a845b9a \ + --hash=sha256:030a6164bc2ca726052778c0cf8e3249617a34e368354f9e6107c27ad4af8c28 \ + --hash=sha256:06373a94fd16ec287116a825161dca179a0402d0c60674ceeec8c9fba344fe66 \ + --hash=sha256:07a554fa31c668cf0e7a188678ceeca3cb8fead29bbe455352e712ec33ca701c \ + --hash=sha256:0ee119f4f88d9f75414217823d21d75bfe0e6ed40135b0cbbfc6376bc9f7757d \ + --hash=sha256:1712b5890b22547dd29f3215c5788d8fc759ce6dd0b85a6ba6e2731f2d04c088 \ + --hash=sha256:259526a7159d39e2db40d566fe3e8f8e034d0fb2db5bf9c00e09aace655a4c2b \ + --hash=sha256:2720c239c1180eee69f7883c1d4c83fc1a495a2535b5fa322887c70bf02b16e8 \ + --hash=sha256:3652516048bf4c314ce12be37423c79829f46efffb390ad64149a10c6071e8de \ + --hash=sha256:36990d629c3c9fb41e546414e5af52d0a7af37ce7113d9682c46d7e2919e4cca \ + --hash=sha256:3bed22e750d91d53d9e31e0af35a7b0b51367e974e14a4ff229db5b207647884 \ + --hash=sha256:3d86880ecaeb5b2f0a8afa63824de93adb8ebe4e49d0e51442532f4e08add7d6 \ + --hash=sha256:3e71a2105210366bfc398eef7f57a664df99194f3520edb88b9c3a7e46ee0d64 \ + --hash=sha256:3e81d89ece99b9ace23a6916880baca613c03a799925afb2857887efa8b1b3d2 \ + --hash=sha256:4484f4b7287bdaa7a5b3980f3c7224c3c622669405d20f69549f5fb956ad0421 \ + --hash=sha256:44b62345d8403975513af88da2f3d5cc76f73ca538ba46596f92a127c2aea945 \ + --hash=sha256:491444c081a54dcd5e6ada57314321ae526377f498d4aa09d975c3241c5b9e1c \ + --hash=sha256:4b4c678e7ed50f8ae8b8dbad15a865ee73ce12668b6aaf411bf3258b5bc3f970 \ + --hash=sha256:4b7177a1cdb3c51b02b0c0a256b0a72fdab719600a693e0e9037949efffb200b \ + --hash=sha256:4e1c28f51c1cf67eccdfc1065e8e866c9ed622f09773ca60947089c117f848a1 \ + --hash=sha256:52015cf73eb5d76f6404e0ce0505a69b51fd1f35810b3a01233b34b10baafb41 \ + --hash=sha256:5573f51e3f296a1bcf71e7a690c092845fb223072120f4bdb7a5b48e111def66 \ + --hash=sha256:573855ca2e58e35032aff30bfbd1ee103fbcf4472e4b28d4010757700918e326 \ + --hash=sha256:5a2acda37fc926ccc4547977ac3e56b1df48fe200de968e8c8421f6e3093df6c \ + --hash=sha256:5b8ea230c7f77c0a1a3208a04a1eda164633fb0767b4cefd65a01079b65e5b1f \ + --hash=sha256:5b8f381eadcd6ecaa143a21e9e80a26424c76a0a9b3d546febe6648f3a36a5ac \ + --hash=sha256:5bf4001d3293e3414d0cf99ff9b1139106e57c3a66dfff0c5f60b2a6286ec133 \ + --hash=sha256:5cebe13088b9254f6e615bcf1da9131d46cfa4e88039454aca9cb65f639bd3bc \ + --hash=sha256:61c692fb05956b17dd6d1ab480f7f10ad0536dba3bc8fd4e3c7263dc244ed772 \ + --hash=sha256:62ce42d9994446b307649cb2a23335fa8e927f7ab2cbf5fcb844d6acb4d85f9c \ + --hash=sha256:664eecc3abe6d916fa6cf8dd6b778e62fb264a70f3430a3180995bf2da935446 \ + --hash=sha256:67697efef5a98d46d5db7b1720fa4043536f8b8e5072a5d61cfca762f287e939 \ + --hash=sha256:683cfc70be0c1383449097cba637317e4737a357cfc185d887fd984206380403 \ + --hash=sha256:6a4996a2c8accc37976dc142d5991adf60733e223e5c9a2219e157dc6a8fd3a2 \ + --hash=sha256:73577a93e692b3474b1bfe84285d098de36705dbd838bb4d6a056d326e4dc880 \ + --hash=sha256:745c5fe6bf05df6a04bf2d11552c7d867a2690759e7ab6b05c318a772739bd75 \ + --hash=sha256:7b888b33cd14085d86176b1628ad2fcbff94cfbbe7809465097aa0132e58b018 \ + --hash=sha256:7d4fa6ccc3ec2e68a04f7b883d354d7fea22a34c44ce535a2f0c0049cf626ddf \ + --hash=sha256:7e21400b037be29545704889e72e586c238e346dcb2d08d8a7288d16c883a9ec \ + --hash=sha256:8679aa8a5b67976776d3c6b0521e99d1c34db8a312a12bcfd78a7085cb9b604e \ + --hash=sha256:8775036efe4ad2085975531d221535329f5dac99b6c2a854a995456098f99546 \ + --hash=sha256:8d04e101bba4b55cea9954e4aa71c24153ba6182481b487ff376da28d4ba46cf \ + --hash=sha256:9f82ff474103e26351dacfe8d50214e7c9322960d8d07ba7fa1d05ff981c8b2d \ + --hash=sha256:9fe51e4a1f896ea84ac750900eae34d9e9b896b5b1e4a30b02dc31ad29f36383 \ + --hash=sha256:a8041d2f9e8a742aeae96f4b047ee44e73619f4f9d24565e84d5446c623673b6 \ + --hash=sha256:aad1c774f4ebf0696a7f148a56d39a3432550612597331792528895258966dc0 \ + --hash=sha256:b10ad908118d38c2453ade7ff790e5bce36580c3742919007a2a78e3a1e521ca \ + --hash=sha256:b1e191c5c465fa777d4cafbaacf0c01e0d5278022082c0abbd2ee1d6454ed94d \ + --hash=sha256:b1ea1bbe77ecbc1be00af2769f4ae4a88ce93be57a4f3eebd91087898ed749f9 \ + --hash=sha256:bb658f703468d7fbb5dcc4037c65391b7dc34f808ac46ed9136c24fc5eeb041d \ + --hash=sha256:c05da79068dd96723793bffc8d0e64c45f316248417515f28d22204d9dae51c7 \ + --hash=sha256:c09fba33327c3ac11b5c33dbdd8218eef8990d78f83b1656d628831812a8c0fb \ + --hash=sha256:c12121e509b9f8b0914d10054d24120237d19e870b1cd82acbb8a9b9ddd198a3 \ + --hash=sha256:c32193fa08b2fbebf08fe08e84f8a0aad32d87c3ad42999c65e9449871b1c66e \ + --hash=sha256:ce08d4e112d0d38487c2b631ec8723deac9bc404e9c7b1011426af50a79999e4 \ + --hash=sha256:cf2e760978dcce7ff7d465cbc7e276c3157eedc4c27aa6de7b594c7a295d3d61 \ + --hash=sha256:d6be2b5ee7bea656c954dcf6aa8093c6f0e6a3ef9945c99d99fcbfc88c5c0bfe \ + --hash=sha256:e19e7dfa0d7ca7dea22be464339e18ac608fd75d88c56770c646cdabe54bc724 \ + --hash=sha256:e5b425aee54cc5e3e3c58f00731e8a33f5567965d478d516d35ef99fd648ab68 \ + --hash=sha256:f4b29b9aabe33fed5df0a85e5f13b09ff25e2c05bd5946d25270a8bd5682dac9 \ + --hash=sha256:f86e92275710bea3000cb79feca1762dc0ad3b27830dd1a74e82ab321d4ee464 # via # google-api-core # googleapis-common-protos From 46f2bb044d4d3529ce2233d0b8efce3a897bc642 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 11:00:13 +0100 Subject: [PATCH 531/582] chore(deps): update dependency grpcio-status to v1.75.1 (#758) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 10ad7ba94eac..6717366b7f9d 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -274,9 +274,9 @@ grpcio==1.75.1 \ # grpc-google-iam-v1 # grpc-interceptor # grpcio-status -grpcio-status==1.74.0 \ - --hash=sha256:52cdbd759a6760fc8f668098a03f208f493dd5c76bf8e02598bbbaf1f6fc2876 \ - --hash=sha256:c58c1b24aa454e30f1fc6a7e0dbbc194c54a408143971a94b5f4e40bb5831432 +grpcio-status==1.75.1 \ + --hash=sha256:8162afa21833a2085c91089cc395ad880fac1378a1d60233d976649ed724cbf8 \ + --hash=sha256:f681b301be26dcf7abf5c765d4a22e4098765e1a65cbdfa3efca384edf8e4e3c # via google-api-core idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ From bf2add4fea4b60a16791994a0710e6e8ace936d7 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 11:21:17 +0100 Subject: [PATCH 532/582] chore(deps): update dependency click to v8.3.0 (#759) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6717366b7f9d..87c7194a0734 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -103,9 +103,9 @@ charset-normalizer==3.4.3 \ --hash=sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c \ --hash=sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9 # via requests -click==8.2.1 \ - --hash=sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202 \ - --hash=sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b +click==8.3.0 \ + --hash=sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc \ + --hash=sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4 # via # -r requirements.in # pip-tools From bc3a2b67dc5bfddd574f5df33af0ac514ad1fa44 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 12:13:45 +0100 Subject: [PATCH 533/582] chore(deps): update dependency google-cloud-spanner to v3.58.0 (#760) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 87c7194a0734..e5df269a567b 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -131,9 +131,9 @@ google-cloud-core==2.4.3 \ --hash=sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53 \ --hash=sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e # via google-cloud-spanner -google-cloud-spanner==3.57.0 \ - --hash=sha256:5b10b40bc646091f1b4cbb2e7e2e82ec66bcce52c7105f86b65070d34d6df86f \ - --hash=sha256:73f52f58617449fcff7073274a7f7a798f4f7b2788eda26de3b7f98ad857ab99 +google-cloud-spanner==3.58.0 \ + --hash=sha256:00d9a809155d9a92e891a0a2b2568b920016652549864024da30940ac780cc2c \ + --hash=sha256:db1c632ac5d0a1188cfe45b31db416120d3e0b07e885d0443a398c99e9fec542 # via -r requirements.in googleapis-common-protos[grpc]==1.70.0 \ --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ From 5bbe0509e120c12b30ce83579d8c840a30fc3288 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 12:26:06 +0100 Subject: [PATCH 534/582] chore(deps): update dependency markupsafe to v3.0.3 (#763) --- packages/sqlalchemy-spanner/requirements.txt | 152 +++++++++++-------- 1 file changed, 90 insertions(+), 62 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index e5df269a567b..c4a33808f0f4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -290,68 +290,96 @@ mako==1.3.10 \ --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ --hash=sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59 # via alembic -markupsafe==3.0.2 \ - --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ - --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ - --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ - --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ - --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ - --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ - --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ - --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ - --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ - --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ - --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ - --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ - --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ - --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ - --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ - --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ - --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ - --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ - --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ - --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ - --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ - --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ - --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ - --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ - --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ - --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ - --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ - --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ - --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ - --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ - --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ - --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ - --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ - --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ - --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ - --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ - --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ - --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ - --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ - --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ - --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ - --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ - --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ - --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ - --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ - --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ - --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ - --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ - --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ - --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ - --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ - --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ - --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ - --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ - --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ - --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ - --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ - --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ - --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ - --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ - --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 +MarkupSafe==3.0.3 \ + --hash=sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f \ + --hash=sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a \ + --hash=sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf \ + --hash=sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19 \ + --hash=sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf \ + --hash=sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c \ + --hash=sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175 \ + --hash=sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219 \ + --hash=sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb \ + --hash=sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6 \ + --hash=sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab \ + --hash=sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26 \ + --hash=sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1 \ + --hash=sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce \ + --hash=sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218 \ + --hash=sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634 \ + --hash=sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695 \ + --hash=sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad \ + --hash=sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73 \ + --hash=sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c \ + --hash=sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe \ + --hash=sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa \ + --hash=sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559 \ + --hash=sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa \ + --hash=sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37 \ + --hash=sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758 \ + --hash=sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f \ + --hash=sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8 \ + --hash=sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d \ + --hash=sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c \ + --hash=sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97 \ + --hash=sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a \ + --hash=sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19 \ + --hash=sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9 \ + --hash=sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9 \ + --hash=sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc \ + --hash=sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2 \ + --hash=sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4 \ + --hash=sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354 \ + --hash=sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50 \ + --hash=sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698 \ + --hash=sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9 \ + --hash=sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b \ + --hash=sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc \ + --hash=sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115 \ + --hash=sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e \ + --hash=sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485 \ + --hash=sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f \ + --hash=sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12 \ + --hash=sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025 \ + --hash=sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009 \ + --hash=sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d \ + --hash=sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b \ + --hash=sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a \ + --hash=sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5 \ + --hash=sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f \ + --hash=sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d \ + --hash=sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1 \ + --hash=sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287 \ + --hash=sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6 \ + --hash=sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f \ + --hash=sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581 \ + --hash=sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed \ + --hash=sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b \ + --hash=sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c \ + --hash=sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026 \ + --hash=sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8 \ + --hash=sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676 \ + --hash=sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6 \ + --hash=sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e \ + --hash=sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d \ + --hash=sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d \ + --hash=sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01 \ + --hash=sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7 \ + --hash=sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419 \ + --hash=sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795 \ + --hash=sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1 \ + --hash=sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5 \ + --hash=sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d \ + --hash=sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42 \ + --hash=sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe \ + --hash=sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda \ + --hash=sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e \ + --hash=sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737 \ + --hash=sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523 \ + --hash=sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591 \ + --hash=sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc \ + --hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \ + --hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50 # via mako opentelemetry-api==1.37.0 \ --hash=sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7 \ From bd2ae541e553b70d27e64f3c7b24e1ebfad524e5 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 12:31:05 +0100 Subject: [PATCH 535/582] chore(deps): update dependency google-auth to v2.41.1 (#764) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index c4a33808f0f4..ae922d12093f 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -121,9 +121,9 @@ google-api-core[grpc]==2.25.1 \ # via # google-cloud-core # google-cloud-spanner -google-auth==2.40.3 \ - --hash=sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca \ - --hash=sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77 +google-auth==2.41.1 \ + --hash=sha256:754843be95575b9a19c604a848a41be03f7f2afd8c019f716dc1f51ee41c639d \ + --hash=sha256:b76b7b1f9e61f0cb7e88870d14f6a94aeef248959ef6992670efee37709cbfd2 # via # google-api-core # google-cloud-core From 7b8011a8b38693e2656113462d6b19b81ea2fcfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 8 Oct 2025 14:32:58 +0200 Subject: [PATCH 536/582] build: update default python version to 3.12 (#770) --- .../.github/workflows/test_suite.yml | 54 +--------------- .../migration_test_cleanup.py | 2 +- packages/sqlalchemy-spanner/noxfile.py | 62 +------------------ 3 files changed, 7 insertions(+), 111 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 82ddea2c3553..a21f86616203 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -29,7 +29,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.8 + python-version: 3.12 - name: Install nox run: python -m pip install nox - name: Run Unit Tests @@ -69,30 +69,6 @@ jobs: run: nox -s _all_samples working-directory: samples - compliance_tests_13: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v5 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.8 - - name: Install nox - run: python -m pip install nox - - name: Run Compliance Tests - run: nox -s compliance_test_13 - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - compliance_tests_14: runs-on: ubuntu-latest @@ -108,7 +84,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.8 + python-version: 3.12 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -181,7 +157,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.8 + python-version: 3.12 - name: Install nox run: python -m pip install nox - name: Run Migration Tests @@ -189,27 +165,3 @@ jobs: env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - - migration1310_tests: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v5 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.8 - - name: Install nox - run: python -m pip install nox - - name: Run Migration Tests - run: nox -s migration_test_1310 - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging diff --git a/packages/sqlalchemy-spanner/migration_test_cleanup.py b/packages/sqlalchemy-spanner/migration_test_cleanup.py index c56b10d0cecd..89b1064d88ee 100644 --- a/packages/sqlalchemy-spanner/migration_test_cleanup.py +++ b/packages/sqlalchemy-spanner/migration_test_cleanup.py @@ -31,7 +31,7 @@ def main(argv): instance = client.instance(instance_id="".join(instance_id).replace("/", "")) database = instance.database("".join(database_id).replace("/", "")) - database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120) + database.update_ddl(["DROP TABLE IF EXISTS account", "DROP TABLE IF EXISTS alembic_version"]).result(120) if __name__ == "__main__": diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 974daf99bb6c..c9f1cb248eb1 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -77,7 +77,7 @@ class = StreamHandler BLACK_VERSION = "black==22.3.0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] -DEFAULT_PYTHON_VERSION = "3.8" +DEFAULT_PYTHON_VERSION = "3.12" DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.12" @@ -126,50 +126,6 @@ def lint_setup_py(session): session.run("python", "setup.py", "check", "--restructuredtext", "--strict") -@nox.session(python=DEFAULT_PYTHON_VERSION) -def compliance_test_13(session): - """Run SQLAlchemy dialect compliance test suite.""" - - # Check the value of `RUN_COMPLIANCE_TESTS` env var. It defaults to true. - if os.environ.get("RUN_COMPLIANCE_TESTS", "true") == "false": - session.skip("RUN_COMPLIANCE_TESTS is set to false, skipping") - # Sanity check: Only run tests if the environment variable is set. - if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", "") and not os.environ.get( - "SPANNER_EMULATOR_HOST", "" - ): - session.skip( - "Credentials or emulator host must be set via environment variable" - ) - - session.install( - "pytest-cov", - ) - - session.install("mock") - session.install(".[tracing]") - session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.24", "--force-reinstall") - session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") - session.run("pip", "install", "opentelemetry-sdk<=1.10", "--force-reinstall") - session.run("python", "create_test_database.py") - session.run("pip", "install", "pytest==6.2.2", "--force-reinstall") - session.run( - "pip", "install", "pytest-asyncio<0.21.0", "--force-reinstall", "--no-deps" - ) - - session.run( - "py.test", - "--cov=google.cloud.sqlalchemy_spanner", - "--cov=test", - "--cov-append", - "--cov-config=.coveragerc", - "--cov-report=", - "--cov-fail-under=0", - "--asyncio-mode=auto", - "test/test_suite_13.py", - *session.posargs, - ) - - @nox.session(python=DEFAULT_PYTHON_VERSION) def compliance_test_14(session): """Run SQLAlchemy dialect compliance test suite.""" @@ -333,15 +289,8 @@ def mockserver(session): @nox.session(python=DEFAULT_PYTHON_VERSION) def migration_test(session): - """Test migrations with SQLAlchemy v1.3.11+ and Alembic""" - session.run("pip", "install", "sqlalchemy>=1.3.11,<2.0", "--force-reinstall") - _migration_test(session) - - -@nox.session(python=DEFAULT_PYTHON_VERSION) -def migration_test_1310(session): - """Test migrations with SQLAlchemy 1.3.10 or lower and Alembic""" - session.run("pip", "install", "sqlalchemy>=1.1.13,<=1.3.10", "--force-reinstall") + """Test migrations with SQLAlchemy v1.4 and Alembic""" + session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") _migration_test(session) @@ -352,11 +301,6 @@ def _migration_test(session): import os import shutil - try: - import sqlalchemy - except: - session.run("pip", "install", "sqlalchemy>=1.3.11,<2.0", "--force-reinstall") - session.install("pytest") session.install(".") session.install("alembic") From bb0ef374ed41298d4109ae2c76373db1db33a150 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 14:34:43 +0100 Subject: [PATCH 537/582] chore(deps): update dependency google-api-core to v2.25.2 (#766) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index ae922d12093f..1245757c49fa 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -115,9 +115,9 @@ deprecated==1.2.18 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.25.1 \ - --hash=sha256:8a2a56c1fef82987a524371f99f3bd0143702fecc670c72e600c1cda6bf8dbb7 \ - --hash=sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8 +google-api-core[grpc]==2.25.2 \ + --hash=sha256:1c63aa6af0d0d5e37966f157a77f9396d820fba59f9e43e9415bc3dc5baff300 \ + --hash=sha256:e9a8f62d363dc8424a8497f4c2a47d6bcda6c16514c935629c257ab5d10210e7 # via # google-cloud-core # google-cloud-spanner From 5e38a25a59c207959f70d0dfd1f978bad1667e1a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 14:42:18 +0100 Subject: [PATCH 538/582] chore(deps): update dependency pip-tools to v7.5.1 (#767) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1245757c49fa..30a6a5665dda 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -411,9 +411,9 @@ pep517==0.13.1 \ --hash=sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317 \ --hash=sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721 # via -r requirements.in -pip-tools==7.5.0 \ - --hash=sha256:30639f50961bb09f49d22f4389e8d7d990709677c094ce1114186b1f2e9b5821 \ - --hash=sha256:69758e4e5a65f160e315d74db46246fdbb30d549f1ed0c4236d057122c9b0f18 +pip-tools==7.5.1 \ + --hash=sha256:a051a94794ba52df9acad2d7c9b0b09ae001617db458a543f8287fea7b89c2cf \ + --hash=sha256:f5ff803823529edc0e6e40c86b1aa7da7266fb1078093c8beea4e5b77877036a # via -r requirements.in proto-plus==1.26.1 \ --hash=sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66 \ From 6c606a4584536c75b57912b51479c162f1d9fb4c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 8 Oct 2025 14:54:59 +0100 Subject: [PATCH 539/582] chore(deps): update dependency certifi to v2025.10.5 (#768) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 30a6a5665dda..233337b54816 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==6.2.0 \ --hash=sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6 \ --hash=sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32 # via google-auth -certifi==2025.8.3 \ - --hash=sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407 \ - --hash=sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5 +certifi==2025.10.5 \ + --hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \ + --hash=sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43 # via requests charset-normalizer==3.4.3 \ --hash=sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91 \ From bfa1b0277162a61ec1941b49dada63f7255050ec Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Wed, 8 Oct 2025 23:47:52 -0700 Subject: [PATCH 540/582] feat: Add Support for Interleaved Indexes (#762) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes: #761 Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 4 + packages/sqlalchemy-spanner/samples/model.py | 21 +++- .../mockserver_tests/interleaved_index.py | 74 +++++++++++++ .../test_interleaved_index.py | 102 ++++++++++++++++++ 4 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/interleaved_index.py create mode 100644 packages/sqlalchemy-spanner/test/mockserver_tests/test_interleaved_index.py diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 4ab387a9a662..78cd4fab6c2f 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -719,6 +719,10 @@ def visit_create_index( [self.preparer.quote(c.name) for c in storing_columns] ) + interleave_in = options.get("interleave_in") + if interleave_in is not None: + text += f", INTERLEAVE IN {self.preparer.quote(interleave_in)}" + if options.get("null_filtered", False): text = re.sub( r"(^\s*CREATE\s+(?:UNIQUE\s+)?)INDEX", diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index faa8a53588c1..a4af86e4e7ac 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -95,11 +95,22 @@ class Album(Base): class Track(Base): __tablename__ = "tracks" - # This interleaves the table `tracks` in its parent `albums`. - __table_args__ = { - "spanner_interleave_in": "albums", - "spanner_interleave_on_delete_cascade": True, - } + __table_args__ = ( + # Use the spanner_interleave_in argument to add an INTERLEAVED IN clause to the index. + # You can read additional details at: + # https://cloud.google.com/spanner/docs/secondary-indexes#indexes_and_interleaving + Index( + "idx_tracks_id_title", + "id", + "title", + spanner_interleave_in="albums", + ), + # This interleaves the table `tracks` in its parent `albums`. + { + "spanner_interleave_in": "albums", + "spanner_interleave_on_delete_cascade": True, + }, + ) id: Mapped[str] = mapped_column(String(36), primary_key=True) track_number: Mapped[int] = mapped_column(Integer, primary_key=True) title: Mapped[str] = mapped_column(String(200), nullable=False) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/interleaved_index.py b/packages/sqlalchemy-spanner/test/mockserver_tests/interleaved_index.py new file mode 100644 index 000000000000..7e59b8e1008d --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/interleaved_index.py @@ -0,0 +1,74 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import ForeignKey, Index, String +from sqlalchemy.orm import DeclarativeBase +from sqlalchemy.orm import Mapped +from sqlalchemy.orm import mapped_column + + +class Base(DeclarativeBase): + pass + + +class Singer(Base): + __tablename__ = "singers" + + singer_id: Mapped[str] = mapped_column(String(36), primary_key=True) + first_name: Mapped[str] + last_name: Mapped[str] + + +class Album(Base): + __tablename__ = "albums" + __table_args__ = { + "spanner_interleave_in": "singers", + "spanner_interleave_on_delete_cascade": True, + } + + singer_id: Mapped[str] = mapped_column( + ForeignKey("singers.singer_id"), primary_key=True + ) + album_id: Mapped[str] = mapped_column(String(36), primary_key=True) + album_title: Mapped[str] + + +class Track(Base): + __tablename__ = "tracks" + __table_args__ = ( + Index( + "idx_name", + "singer_id", + "album_id", + "song_name", + spanner_interleave_in="albums", + ), + { + "spanner_interleave_in": "albums", + "spanner_interleave_on_delete_cascade": True, + }, + ) + + singer_id: Mapped[str] = mapped_column( + ForeignKey("singers.singer_id"), primary_key=True + ) + album_id: Mapped[str] = mapped_column( + ForeignKey("albums.album_id"), primary_key=True + ) + track_id: Mapped[str] = mapped_column(String(36), primary_key=True) + song_name: Mapped[str] + + +Album.__table__.add_is_dependent_on(Singer.__table__) +Track.__table__.add_is_dependent_on(Album.__table__) diff --git a/packages/sqlalchemy-spanner/test/mockserver_tests/test_interleaved_index.py b/packages/sqlalchemy-spanner/test/mockserver_tests/test_interleaved_index.py new file mode 100644 index 000000000000..198f64318dd5 --- /dev/null +++ b/packages/sqlalchemy-spanner/test/mockserver_tests/test_interleaved_index.py @@ -0,0 +1,102 @@ +# Copyright 2025 Google LLC All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sqlalchemy import create_engine +from sqlalchemy.testing import eq_, is_instance_of +from google.cloud.spanner_v1 import ( + FixedSizePool, + ResultSet, +) +from test.mockserver_tests.mock_server_test_base import ( + MockServerTestBase, + add_result, +) +from google.cloud.spanner_admin_database_v1 import UpdateDatabaseDdlRequest + + +class TestNullFilteredIndex(MockServerTestBase): + """Ensure we emit correct DDL for not null filtered indexes.""" + + def test_create_table(self): + from test.mockserver_tests.interleaved_index import Base + + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="singers" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="albums" +LIMIT 1 +""", + ResultSet(), + ) + add_result( + """SELECT true +FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA="" AND TABLE_NAME="tracks" +LIMIT 1 +""", + ResultSet(), + ) + engine = create_engine( + "spanner:///projects/p/instances/i/databases/d", + connect_args={"client": self.client, "pool": FixedSizePool(size=10)}, + ) + Base.metadata.create_all(engine) + requests = self.database_admin_service.requests + eq_(1, len(requests)) + is_instance_of(requests[0], UpdateDatabaseDdlRequest) + eq_(4, len(requests[0].statements)) + eq_( + "CREATE TABLE singers (\n" + "\tsinger_id STRING(36) NOT NULL, \n" + "\tfirst_name STRING(MAX) NOT NULL, \n" + "\tlast_name STRING(MAX) NOT NULL\n" + ") PRIMARY KEY (singer_id)", + requests[0].statements[0], + ) + eq_( + "CREATE TABLE albums (\n" + "\tsinger_id STRING(36) NOT NULL, \n" + "\talbum_id STRING(36) NOT NULL, \n" + "\talbum_title STRING(MAX) NOT NULL, \n" + "\tFOREIGN KEY(singer_id) REFERENCES singers (singer_id)\n" + ") PRIMARY KEY (singer_id, album_id),\n" + "INTERLEAVE IN PARENT singers ON DELETE CASCADE", + requests[0].statements[1], + ) + eq_( + "CREATE TABLE tracks (\n" + "\tsinger_id STRING(36) NOT NULL, \n" + "\talbum_id STRING(36) NOT NULL, \n" + "\ttrack_id STRING(36) NOT NULL, \n" + "\tsong_name STRING(MAX) NOT NULL, \n" + "\tFOREIGN KEY(singer_id) REFERENCES singers (singer_id), \n" + "\tFOREIGN KEY(album_id) REFERENCES albums (album_id)\n" + ") PRIMARY KEY (singer_id, album_id, track_id),\n" + "INTERLEAVE IN PARENT albums ON DELETE CASCADE", + requests[0].statements[2], + ) + eq_( + "CREATE INDEX idx_name ON tracks " + "(singer_id, album_id, song_name), " + "INTERLEAVE IN albums", + requests[0].statements[3], + ) From 08fa626561430d332f87f79517504512cf8ca989 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 9 Oct 2025 07:48:13 +0100 Subject: [PATCH 541/582] chore(deps): update dependency google-api-core to v2.26.0 (#771) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 233337b54816..4920f9c75115 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -115,9 +115,9 @@ deprecated==1.2.18 \ # via # opentelemetry-api # opentelemetry-semantic-conventions -google-api-core[grpc]==2.25.2 \ - --hash=sha256:1c63aa6af0d0d5e37966f157a77f9396d820fba59f9e43e9415bc3dc5baff300 \ - --hash=sha256:e9a8f62d363dc8424a8497f4c2a47d6bcda6c16514c935629c257ab5d10210e7 +google-api-core[grpc]==2.26.0 \ + --hash=sha256:2b204bd0da2c81f918e3582c48458e24c11771f987f6258e6e227212af78f3ed \ + --hash=sha256:e6e6d78bd6cf757f4aee41dcc85b07f485fbb069d5daa3afb126defba1e91a62 # via # google-cloud-core # google-cloud-spanner From 4ba42c60a703ed78842608bae22af953d81715b0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 9 Oct 2025 07:54:43 +0100 Subject: [PATCH 542/582] chore(deps): update dependency tomli to v2.3.0 (#772) --- packages/sqlalchemy-spanner/requirements.txt | 76 +++++++++++--------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4920f9c75115..50e119f0653a 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -531,39 +531,49 @@ sqlparse==0.5.3 \ --hash=sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272 \ --hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca # via google-cloud-spanner -tomli==2.2.1 \ - --hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \ - --hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \ - --hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \ - --hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \ - --hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \ - --hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \ - --hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \ - --hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \ - --hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \ - --hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \ - --hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \ - --hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \ - --hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \ - --hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \ - --hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \ - --hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \ - --hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \ - --hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \ - --hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \ - --hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \ - --hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \ - --hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \ - --hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \ - --hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \ - --hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \ - --hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \ - --hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \ - --hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \ - --hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \ - --hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \ - --hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \ - --hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7 +tomli==2.3.0 \ + --hash=sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456 \ + --hash=sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845 \ + --hash=sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999 \ + --hash=sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0 \ + --hash=sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878 \ + --hash=sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf \ + --hash=sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3 \ + --hash=sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be \ + --hash=sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52 \ + --hash=sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b \ + --hash=sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67 \ + --hash=sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549 \ + --hash=sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba \ + --hash=sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22 \ + --hash=sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c \ + --hash=sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f \ + --hash=sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6 \ + --hash=sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba \ + --hash=sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45 \ + --hash=sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f \ + --hash=sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77 \ + --hash=sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606 \ + --hash=sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441 \ + --hash=sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0 \ + --hash=sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f \ + --hash=sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530 \ + --hash=sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05 \ + --hash=sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8 \ + --hash=sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005 \ + --hash=sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879 \ + --hash=sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae \ + --hash=sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc \ + --hash=sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b \ + --hash=sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b \ + --hash=sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e \ + --hash=sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf \ + --hash=sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac \ + --hash=sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8 \ + --hash=sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b \ + --hash=sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf \ + --hash=sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463 \ + --hash=sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876 # via -r requirements.in typing-extensions==4.15.0 \ --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ From 14ebe90eb7e1eb609b3ce8c05a397ec1d4330f13 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 11:17:29 +0200 Subject: [PATCH 543/582] chore(main): release 1.17.0 (#773) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index cf7788e2af6d..0265b1e83c57 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.17.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.16.0...v1.17.0) (2025-10-09) + + +### Features + +* Add Support for Interleaved Indexes ([#762](https://github.com/googleapis/python-spanner-sqlalchemy/issues/762)) ([77b86f1](https://github.com/googleapis/python-spanner-sqlalchemy/commit/77b86f1ad9d31932c960497eb1fb29635b74cb92)), closes [#761](https://github.com/googleapis/python-spanner-sqlalchemy/issues/761) + ## [1.16.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.15.0...v1.16.0) (2025-09-02) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index 66d505de6c38..5cc0f2611f8b 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.16.0" +__version__ = "1.17.0" From bbdb734406dd06e332e79b128c5d3da8a5ff5487 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:27:57 +0100 Subject: [PATCH 544/582] chore(deps): update dependency sqlalchemy to v2.0.44 (#774) --- packages/sqlalchemy-spanner/requirements.txt | 116 +++++++++---------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 50e119f0653a..81f765d7bcbd 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -466,64 +466,64 @@ rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth -SQLAlchemy==2.0.43 \ - --hash=sha256:022e436a1cb39b13756cf93b48ecce7aa95382b9cfacceb80a7d263129dfd019 \ - --hash=sha256:03d73ab2a37d9e40dec4984d1813d7878e01dbdc742448d44a7341b7a9f408c7 \ - --hash=sha256:07097c0a1886c150ef2adba2ff7437e84d40c0f7dcb44a2c2b9c905ccfc6361c \ - --hash=sha256:11b9503fa6f8721bef9b8567730f664c5a5153d25e247aadc69247c4bc605227 \ - --hash=sha256:11f43c39b4b2ec755573952bbcc58d976779d482f6f832d7f33a8d869ae891bf \ - --hash=sha256:13194276e69bb2af56198fef7909d48fd34820de01d9c92711a5fa45497cc7ed \ - --hash=sha256:136063a68644eca9339d02e6693932116f6a8591ac013b0014479a1de664e40a \ - --hash=sha256:14111d22c29efad445cd5021a70a8b42f7d9152d8ba7f73304c4d82460946aaa \ - --hash=sha256:1681c21dd2ccee222c2fe0bef671d1aef7c504087c9c4e800371cfcc8ac966fc \ - --hash=sha256:1a113da919c25f7f641ffbd07fbc9077abd4b3b75097c888ab818f962707eb48 \ - --hash=sha256:1c6d85327ca688dbae7e2b06d7d84cfe4f3fffa5b5f9e21bb6ce9d0e1a0e0e0a \ - --hash=sha256:20d81fc2736509d7a2bd33292e489b056cbae543661bb7de7ce9f1c0cd6e7f24 \ - --hash=sha256:21b27b56eb2f82653168cefe6cb8e970cdaf4f3a6cb2c5e3c3c1cf3158968ff9 \ - --hash=sha256:21ba7a08a4253c5825d1db389d4299f64a100ef9800e4624c8bf70d8f136e6ed \ - --hash=sha256:227119ce0a89e762ecd882dc661e0aa677a690c914e358f0dd8932a2e8b2765b \ - --hash=sha256:25b9fc27650ff5a2c9d490c13c14906b918b0de1f8fcbb4c992712d8caf40e83 \ - --hash=sha256:334f41fa28de9f9be4b78445e68530da3c5fa054c907176460c81494f4ae1f5e \ - --hash=sha256:413391b2239db55be14fa4223034d7e13325a1812c8396ecd4f2c08696d5ccad \ - --hash=sha256:4286a1139f14b7d70141c67a8ae1582fc2b69105f1b09d9573494eb4bb4b2687 \ - --hash=sha256:44337823462291f17f994d64282a71c51d738fc9ef561bf265f1d0fd9116a782 \ - --hash=sha256:46293c39252f93ea0910aababa8752ad628bcce3a10d3f260648dd472256983f \ - --hash=sha256:4bf0edb24c128b7be0c61cd17eef432e4bef507013292415f3fb7023f02b7d4b \ - --hash=sha256:4d3d9b904ad4a6b175a2de0738248822f5ac410f52c2fd389ada0b5262d6a1e3 \ - --hash=sha256:4e6aeb2e0932f32950cf56a8b4813cb15ff792fc0c9b3752eaf067cfe298496a \ - --hash=sha256:4fb1a8c5438e0c5ea51afe9c6564f951525795cf432bed0c028c1cb081276685 \ - --hash=sha256:529064085be2f4d8a6e5fab12d36ad44f1909a18848fcfbdb59cc6d4bbe48efe \ - --hash=sha256:52d9b73b8fb3e9da34c2b31e6d99d60f5f99fd8c1225c9dad24aeb74a91e1d29 \ - --hash=sha256:5cda6b51faff2639296e276591808c1726c4a77929cfaa0f514f30a5f6156921 \ - --hash=sha256:5d79f9fdc9584ec83d1b3c75e9f4595c49017f5594fee1a2217117647225d738 \ - --hash=sha256:61f964a05356f4bca4112e6334ed7c208174511bd56e6b8fc86dad4d024d4185 \ - --hash=sha256:6772e3ca8a43a65a37c88e2f3e2adfd511b0b1da37ef11ed78dea16aeae85bd9 \ - --hash=sha256:6e2bf13d9256398d037fef09fd8bf9b0bf77876e22647d10761d35593b9ac547 \ - --hash=sha256:70322986c0c699dca241418fcf18e637a4369e0ec50540a2b907b184c8bca069 \ - --hash=sha256:788bfcef6787a7764169cfe9859fe425bf44559619e1d9f56f5bddf2ebf6f417 \ - --hash=sha256:7f1ac7828857fcedb0361b48b9ac4821469f7694089d15550bbcf9ab22564a1d \ - --hash=sha256:87accdbba88f33efa7b592dc2e8b2a9c2cdbca73db2f9d5c510790428c09c154 \ - --hash=sha256:8cee08f15d9e238ede42e9bbc1d6e7158d0ca4f176e4eab21f88ac819ae3bd7b \ - --hash=sha256:971ba928fcde01869361f504fcff3b7143b47d30de188b11c6357c0505824197 \ - --hash=sha256:9c2e02f06c68092b875d5cbe4824238ab93a7fa35d9c38052c033f7ca45daa18 \ - --hash=sha256:9c5a9da957c56e43d72126a3f5845603da00e0293720b03bde0aacffcf2dc04f \ - --hash=sha256:9df7126fd9db49e3a5a3999442cc67e9ee8971f3cb9644250107d7296cb2a164 \ - --hash=sha256:b3edaec7e8b6dc5cd94523c6df4f294014df67097c8217a89929c99975811414 \ - --hash=sha256:b535d35dea8bbb8195e7e2b40059e2253acb2b7579b73c1b432a35363694641d \ - --hash=sha256:bcf0724a62a5670e5718957e05c56ec2d6850267ea859f8ad2481838f889b42c \ - --hash=sha256:c00e7845d2f692ebfc7d5e4ec1a3fd87698e4337d09e58d6749a16aedfdf8612 \ - --hash=sha256:c379e37b08c6c527181a397212346be39319fb64323741d23e46abd97a400d34 \ - --hash=sha256:c5d1730b25d9a07727d20ad74bc1039bbbb0a6ca24e6769861c1aa5bf2c4c4a8 \ - --hash=sha256:c5e73ba0d76eefc82ec0219d2301cb33bfe5205ed7a2602523111e2e56ccbd20 \ - --hash=sha256:c697575d0e2b0a5f0433f679bda22f63873821d991e95a90e9e52aae517b2e32 \ - --hash=sha256:cdeff998cb294896a34e5b2f00e383e7c5c4ef3b4bfa375d9104723f15186443 \ - --hash=sha256:ceb5c832cc30663aeaf5e39657712f4c4241ad1f638d487ef7216258f6d41fe7 \ - --hash=sha256:d34c0f6dbefd2e816e8f341d0df7d4763d382e3f452423e752ffd1e213da2512 \ - --hash=sha256:db691fa174e8f7036afefe3061bc40ac2b770718be2862bfb03aabae09051aca \ - --hash=sha256:e7a903b5b45b0d9fa03ac6a331e1c1d6b7e0ab41c63b6217b3d10357b83c8b00 \ - --hash=sha256:e7c08f57f75a2bb62d7ee80a89686a5e5669f199235c6d1dac75cd59374091c3 \ - --hash=sha256:f42f23e152e4545157fa367b2435a1ace7571cab016ca26038867eb7df2c3631 \ - --hash=sha256:fe2b3b4927d0bc03d02ad883f402d5de201dbc8894ac87d2e981e7d87430e60d +SQLAlchemy==2.0.44 \ + --hash=sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7 \ + --hash=sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22 \ + --hash=sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45 \ + --hash=sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd \ + --hash=sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1 \ + --hash=sha256:11bac86b0deada30b6b5f93382712ff0e911fe8d31cb9bf46e6b149ae175eff0 \ + --hash=sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d \ + --hash=sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749 \ + --hash=sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05 \ + --hash=sha256:1df4763760d1de0dfc8192cc96d8aa293eb1a44f8f7a5fbe74caf1b551905c5e \ + --hash=sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40 \ + --hash=sha256:22be14009339b8bc16d6b9dc8780bacaba3402aa7581658e246114abbd2236e3 \ + --hash=sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3 \ + --hash=sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976 \ + --hash=sha256:2bf4bb6b3d6228fcf3a71b50231199fb94d2dd2611b66d33be0578ea3e6c2726 \ + --hash=sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d \ + --hash=sha256:2f19644f27c76f07e10603580a47278abb2a70311136a7f8fd27dc2e096b9013 \ + --hash=sha256:2fc44e5965ea46909a416fff0af48a219faefd5773ab79e5f8a5fcd5d62b2667 \ + --hash=sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165 \ + --hash=sha256:3255d821ee91bdf824795e936642bbf43a4c7cedf5d1aed8d24524e66843aa74 \ + --hash=sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399 \ + --hash=sha256:357bade0e46064f88f2c3a99808233e67b0051cdddf82992379559322dfeb183 \ + --hash=sha256:3caef1ff89b1caefc28f0368b3bde21a7e3e630c2eddac16abd9e47bd27cc36a \ + --hash=sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e \ + --hash=sha256:3fe166c7d00912e8c10d3a9a0ce105569a31a3d0db1a6e82c4e0f4bf16d5eca9 \ + --hash=sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632 \ + --hash=sha256:4848395d932e93c1595e59a8672aa7400e8922c39bb9b0668ed99ac6fa867822 \ + --hash=sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f \ + --hash=sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985 \ + --hash=sha256:4d18cd0e9a0f37c9f4088e50e3839fcb69a380a0ec957408e0b57cff08ee0a26 \ + --hash=sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29 \ + --hash=sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b \ + --hash=sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250 \ + --hash=sha256:78e6c137ba35476adb5432103ae1534f2f5295605201d946a4198a0dea4b38e7 \ + --hash=sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5 \ + --hash=sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce \ + --hash=sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e \ + --hash=sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4 \ + --hash=sha256:8e0e4e66fd80f277a8c3de016a81a554e76ccf6b8d881ee0b53200305a8433f6 \ + --hash=sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5 \ + --hash=sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44 \ + --hash=sha256:9e9018544ab07614d591a26c1bd4293ddf40752cc435caf69196740516af7100 \ + --hash=sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c \ + --hash=sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e \ + --hash=sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e \ + --hash=sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2 \ + --hash=sha256:cc2856d24afa44295735e72f3c75d6ee7fdd4336d8d3a8f3d44de7aa6b766df2 \ + --hash=sha256:d733dec0614bb8f4bcb7c8af88172b974f685a31dc3a65cca0527e3120de5606 \ + --hash=sha256:dc8b3850d2a601ca2320d081874033684e246d28e1c5e89db0864077cfc8f5a9 \ + --hash=sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa \ + --hash=sha256:e998cf7c29473bd077704cea3577d23123094311f59bdc4af551923b168332b1 \ + --hash=sha256:ebac3f0b5732014a126b43c2b7567f2f0e0afea7d9119a3378bde46d3dcad88e \ + --hash=sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73 \ + --hash=sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0 \ + --hash=sha256:f7027414f2b88992877573ab780c19ecb54d3a536bef3397933573d6b5068be4 \ + --hash=sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e \ + --hash=sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1 # via # -r requirements.in # alembic From 74f069828f697368de06b6cf2c759e4bf89acd79 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:29:54 +0100 Subject: [PATCH 545/582] chore(deps): update dependency alembic to v1.17.0 (#775) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 81f765d7bcbd..1239b48c3405 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -4,9 +4,9 @@ # # pip-compile --generate-hashes # -alembic==1.16.5 \ - --hash=sha256:a88bb7f6e513bd4301ecf4c7f2206fe93f9913f9b48dac3b78babde2d6fe765e \ - --hash=sha256:e845dfe090c5ffa7b92593ae6687c5cb1a101e91fa53868497dbd79847f9dbe3 +alembic==1.17.0 \ + --hash=sha256:4652a0b3e19616b57d652b82bfa5e38bf5dbea0813eed971612671cb9e90c0fe \ + --hash=sha256:80523bc437d41b35c5db7e525ad9d908f79de65c27d6a5a5eab6df348a352d99 # via -r requirements.in build==1.3.0 \ --hash=sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397 \ From 1c0f2467dd7897162dd0a611f920a246f11905a0 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:32:00 +0100 Subject: [PATCH 546/582] chore(deps): update dependency cachetools to v6.2.1 (#776) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1239b48c3405..0dded843a7a0 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.3.0 \ # via # -r requirements.in # pip-tools -cachetools==6.2.0 \ - --hash=sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6 \ - --hash=sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32 +cachetools==6.2.1 \ + --hash=sha256:09868944b6dde876dfd44e1d47e18484541eaf12f26f29b7af91b26cc892d701 \ + --hash=sha256:3f391e4bd8f8bf0931169baf7456cc822705f4e2a31f840d218f445b9a854201 # via google-auth certifi==2025.10.5 \ --hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \ From 1d3d152197674832d5b9df127594b7ba33032742 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:34:32 +0100 Subject: [PATCH 547/582] chore(deps): update dependency idna to v3.11 (#777) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0dded843a7a0..005dc6aee30e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -278,9 +278,9 @@ grpcio-status==1.75.1 \ --hash=sha256:8162afa21833a2085c91089cc395ad880fac1378a1d60233d976649ed724cbf8 \ --hash=sha256:f681b301be26dcf7abf5c765d4a22e4098765e1a65cbdfa3efca384edf8e4e3c # via google-api-core -idna==3.10 \ - --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ - --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 +idna==3.11 \ + --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \ + --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902 # via requests importlib-metadata==8.7.0 \ --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ From 15a808b04d1a52843e2f559315f31f46465bffac Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:36:19 +0100 Subject: [PATCH 548/582] chore(deps): update dependency charset-normalizer to v3.4.4 (#778) --- packages/sqlalchemy-spanner/requirements.txt | 194 +++++++++++-------- 1 file changed, 114 insertions(+), 80 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 005dc6aee30e..8935471025cc 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -22,86 +22,120 @@ certifi==2025.10.5 \ --hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \ --hash=sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43 # via requests -charset-normalizer==3.4.3 \ - --hash=sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91 \ - --hash=sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0 \ - --hash=sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154 \ - --hash=sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601 \ - --hash=sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884 \ - --hash=sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07 \ - --hash=sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c \ - --hash=sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64 \ - --hash=sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe \ - --hash=sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f \ - --hash=sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432 \ - --hash=sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc \ - --hash=sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa \ - --hash=sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9 \ - --hash=sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae \ - --hash=sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19 \ - --hash=sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d \ - --hash=sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e \ - --hash=sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4 \ - --hash=sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7 \ - --hash=sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312 \ - --hash=sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92 \ - --hash=sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31 \ - --hash=sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c \ - --hash=sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f \ - --hash=sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99 \ - --hash=sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b \ - --hash=sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15 \ - --hash=sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392 \ - --hash=sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f \ - --hash=sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8 \ - --hash=sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491 \ - --hash=sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0 \ - --hash=sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc \ - --hash=sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0 \ - --hash=sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f \ - --hash=sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a \ - --hash=sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40 \ - --hash=sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927 \ - --hash=sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849 \ - --hash=sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce \ - --hash=sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14 \ - --hash=sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05 \ - --hash=sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c \ - --hash=sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c \ - --hash=sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a \ - --hash=sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc \ - --hash=sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34 \ - --hash=sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9 \ - --hash=sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096 \ - --hash=sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14 \ - --hash=sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30 \ - --hash=sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b \ - --hash=sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b \ - --hash=sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942 \ - --hash=sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db \ - --hash=sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5 \ - --hash=sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b \ - --hash=sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce \ - --hash=sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669 \ - --hash=sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0 \ - --hash=sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018 \ - --hash=sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93 \ - --hash=sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe \ - --hash=sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049 \ - --hash=sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a \ - --hash=sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef \ - --hash=sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2 \ - --hash=sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca \ - --hash=sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16 \ - --hash=sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f \ - --hash=sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb \ - --hash=sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1 \ - --hash=sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557 \ - --hash=sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37 \ - --hash=sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7 \ - --hash=sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72 \ - --hash=sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c \ - --hash=sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9 +charset-normalizer==3.4.4 \ + --hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \ + --hash=sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93 \ + --hash=sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394 \ + --hash=sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89 \ + --hash=sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc \ + --hash=sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86 \ + --hash=sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63 \ + --hash=sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d \ + --hash=sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f \ + --hash=sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8 \ + --hash=sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0 \ + --hash=sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505 \ + --hash=sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161 \ + --hash=sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af \ + --hash=sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152 \ + --hash=sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318 \ + --hash=sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72 \ + --hash=sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4 \ + --hash=sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e \ + --hash=sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3 \ + --hash=sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576 \ + --hash=sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c \ + --hash=sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1 \ + --hash=sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8 \ + --hash=sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1 \ + --hash=sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2 \ + --hash=sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44 \ + --hash=sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26 \ + --hash=sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88 \ + --hash=sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016 \ + --hash=sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede \ + --hash=sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf \ + --hash=sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a \ + --hash=sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc \ + --hash=sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0 \ + --hash=sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84 \ + --hash=sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db \ + --hash=sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1 \ + --hash=sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7 \ + --hash=sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed \ + --hash=sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8 \ + --hash=sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133 \ + --hash=sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e \ + --hash=sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef \ + --hash=sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14 \ + --hash=sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2 \ + --hash=sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0 \ + --hash=sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d \ + --hash=sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828 \ + --hash=sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f \ + --hash=sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf \ + --hash=sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6 \ + --hash=sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328 \ + --hash=sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090 \ + --hash=sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa \ + --hash=sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381 \ + --hash=sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c \ + --hash=sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb \ + --hash=sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc \ + --hash=sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a \ + --hash=sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec \ + --hash=sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc \ + --hash=sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac \ + --hash=sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e \ + --hash=sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313 \ + --hash=sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569 \ + --hash=sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3 \ + --hash=sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d \ + --hash=sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525 \ + --hash=sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894 \ + --hash=sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3 \ + --hash=sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9 \ + --hash=sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a \ + --hash=sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9 \ + --hash=sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14 \ + --hash=sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25 \ + --hash=sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50 \ + --hash=sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf \ + --hash=sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1 \ + --hash=sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3 \ + --hash=sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac \ + --hash=sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e \ + --hash=sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815 \ + --hash=sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c \ + --hash=sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6 \ + --hash=sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6 \ + --hash=sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e \ + --hash=sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4 \ + --hash=sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84 \ + --hash=sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69 \ + --hash=sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15 \ + --hash=sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191 \ + --hash=sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0 \ + --hash=sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897 \ + --hash=sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd \ + --hash=sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2 \ + --hash=sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794 \ + --hash=sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d \ + --hash=sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074 \ + --hash=sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3 \ + --hash=sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224 \ + --hash=sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838 \ + --hash=sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a \ + --hash=sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d \ + --hash=sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d \ + --hash=sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f \ + --hash=sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8 \ + --hash=sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490 \ + --hash=sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966 \ + --hash=sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9 \ + --hash=sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3 \ + --hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \ + --hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608 # via requests click==8.3.0 \ --hash=sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc \ From 6d32db6e24b6fa160bb01ed704d49a44a67f9831 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:38:25 +0100 Subject: [PATCH 549/582] chore(deps): update dependency grpc-google-iam-v1 to v0.14.3 (#780) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8935471025cc..11afa2f7d852 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -232,9 +232,9 @@ greenlet==3.2.4 \ --hash=sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c \ --hash=sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968 # via sqlalchemy -grpc-google-iam-v1==0.14.2 \ - --hash=sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351 \ - --hash=sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20 +grpc-google-iam-v1==0.14.3 \ + --hash=sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6 \ + --hash=sha256:879ac4ef33136c5491a6300e27575a9ec760f6cdf9a2518798c1b8977a5dc389 # via google-cloud-spanner grpc-interceptor==0.15.4 \ --hash=sha256:0035f33228693ed3767ee49d937bac424318db173fef4d2d0170b3215f254d9d \ From 700c02109c147c750a2de7831d4c928cb004c486 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:40:37 +0100 Subject: [PATCH 550/582] chore(deps): update dependency protobuf to v6.33.0 (#781) --- packages/sqlalchemy-spanner/requirements.txt | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 11afa2f7d852..939cd7a485a2 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -455,16 +455,17 @@ proto-plus==1.26.1 \ # via # google-api-core # google-cloud-spanner -protobuf==6.32.1 \ - --hash=sha256:2601b779fc7d32a866c6b4404f9d42a3f67c5b9f3f15b4db3cccabe06b95c346 \ - --hash=sha256:2f5b80a49e1eb7b86d85fcd23fe92df154b9730a725c3b38c4e43b9d77018bf4 \ - --hash=sha256:68ff170bac18c8178f130d1ccb94700cf72852298e016a2443bdb9502279e5f1 \ - --hash=sha256:a8a32a84bc9f2aad712041b8b366190f71dde248926da517bde9e832e4412085 \ - --hash=sha256:b00a7d8c25fa471f16bc8153d0e53d6c9e827f0953f3c09aaa4331c718cae5e1 \ - --hash=sha256:b1864818300c297265c83a4982fd3169f97122c299f56a56e2445c3698d34710 \ - --hash=sha256:d0975d0b2f3e6957111aa3935d08a0eb7e006b1505d825f862a1fffc8348e122 \ - --hash=sha256:d8c7e6eb619ffdf105ee4ab76af5a68b60a9d0f66da3ea12d1640e6d8dab7281 \ - --hash=sha256:ee2469e4a021474ab9baafea6cd070e5bf27c7d29433504ddea1a4ee5850f68d +protobuf==6.33.0 \ + --hash=sha256:140303d5c8d2037730c548f8c7b93b20bb1dc301be280c378b82b8894589c954 \ + --hash=sha256:25c9e1963c6734448ea2d308cfa610e692b801304ba0908d7bfa564ac5132995 \ + --hash=sha256:35be49fd3f4fefa4e6e2aacc35e8b837d6703c37a2168a55ac21e9b1bc7559ef \ + --hash=sha256:905b07a65f1a4b72412314082c7dbfae91a9e8b68a0cc1577515f8df58ecf455 \ + --hash=sha256:9a031d10f703f03768f2743a1c403af050b6ae1f3480e9c140f39c45f81b13ee \ + --hash=sha256:c963e86c3655af3a917962c9619e1a6b9670540351d7af9439d06064e3317cc9 \ + --hash=sha256:cd33a8e38ea3e39df66e1bbc462b076d6e5ba3a4ebbde58219d777223a7873d3 \ + --hash=sha256:d6101ded078042a8f17959eccd9236fb7a9ca20d3b0098bbcb91533a5680d035 \ + --hash=sha256:e0697ece353e6239b90ee43a9231318302ad8353c70e6e45499fa52396debf90 \ + --hash=sha256:e0a1715e4f27355afd9570f3ea369735afc853a6c3951a6afe1f80d8569ad298 # via # google-api-core # google-cloud-spanner From b69866a31785993e21bedfb58dc8b499588cfd9a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Mon, 20 Oct 2025 14:42:48 +0100 Subject: [PATCH 551/582] chore(deps): update opentelemetry-python monorepo to v1.38.0 (#782) --- packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 939cd7a485a2..6aa8fda386c3 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -415,9 +415,9 @@ MarkupSafe==3.0.3 \ --hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \ --hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50 # via mako -opentelemetry-api==1.37.0 \ - --hash=sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7 \ - --hash=sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47 +opentelemetry-api==1.38.0 \ + --hash=sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582 \ + --hash=sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12 # via # -r requirements.in # opentelemetry-instrumentation @@ -427,9 +427,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.37.0 \ - --hash=sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c \ - --hash=sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5 +opentelemetry-sdk==1.38.0 \ + --hash=sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b \ + --hash=sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe # via -r requirements.in opentelemetry-semantic-conventions==0.55b1 \ --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ From eae2f3aa8d182d04ebe765472b5afc0a0edcd2ac Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Tue, 21 Oct 2025 06:40:35 -0700 Subject: [PATCH 552/582] fix: Return Correct Column Order in get_multi_foreign_keys (#783) Ensure both referred and constrained columns reported by `get_multi_foreign_keys` are in the same order matching the constraint declaration. Uses information for the unique constraint corresponding to the foreign key constraint in order to ensure its columns are ordered correctly. Previously, the `CONSTRAINT_COLUMN` view in the information schema was used to retrieve the referred columns, and that view offers no information about column order. Instead, we use the KEY_COLUMN_USAGE view for the corresponding unique constraint, which is ordered. This requires consulting the `REFERENTIAL_CONSTRAINTS` view in order to find the unique constraint associated with the foreign key. Unfortunately, this view has a [bug in the emulator](https://github.com/GoogleCloudPlatform/cloud-spanner-emulator/issues/279) related to cross-schema foreign keys. I had to skip a test for cross-schema foreign keys due to the emulator issue. I've confirmed a real spanner does not have this issue. fixes: #779 --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 74 +++++++++---------- .../test/system/test_basics.py | 52 ++++++++++++- 2 files changed, 84 insertions(+), 42 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index 78cd4fab6c2f..e30f0e1f1740 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1513,40 +1513,45 @@ def get_multi_foreign_keys( tc.table_schema, tc.table_name, tc.constraint_name, - ctu.table_name, - ctu.table_schema, - ARRAY_AGG(DISTINCT ccu.column_name), - ARRAY_AGG( - DISTINCT CONCAT( - CAST(kcu.ordinal_position AS STRING), - '_____', - kcu.column_name - ) + tc_uq.table_name, + tc_uq.table_schema, + -- Find the corresponding pairs of columns for the foreign key constraint + -- and its related unique constraint. + ARRAY( + SELECT (kcu.column_name, kcu_uq.column_name) + FROM information_schema.key_column_usage AS kcu + JOIN information_schema.key_column_usage AS kcu_uq + ON kcu_uq.constraint_catalog = rc.unique_constraint_catalog + AND kcu_uq.constraint_schema = rc.unique_constraint_schema + AND kcu_uq.constraint_name = rc.unique_constraint_name + AND kcu_uq.ordinal_position = kcu.ordinal_position + WHERE + kcu.constraint_catalog = tc.constraint_catalog + AND kcu.constraint_schema = tc.constraint_schema + AND kcu.constraint_name = tc.constraint_name + ORDER BY kcu.ordinal_position ) FROM information_schema.table_constraints AS tc - JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_catalog = tc.table_catalog - and ccu.constraint_schema = tc.table_schema - and ccu.constraint_name = tc.constraint_name - JOIN information_schema.constraint_table_usage AS ctu - ON ctu.constraint_catalog = tc.table_catalog - and ctu.constraint_schema = tc.table_schema - and ctu.constraint_name = tc.constraint_name - JOIN information_schema.key_column_usage AS kcu - ON kcu.table_catalog = tc.table_catalog - and kcu.table_schema = tc.table_schema - and kcu.constraint_name = tc.constraint_name + -- Join the foreign key constraint for the referring table. + JOIN information_schema.referential_constraints AS rc + ON rc.constraint_catalog = tc.constraint_catalog + AND rc.constraint_schema = tc.constraint_schema + AND rc.constraint_name = tc.constraint_name + -- Join the corresponding unique constraint on the referenced table. + JOIN information_schema.table_constraints AS tc_uq + ON tc_uq.constraint_catalog = rc.unique_constraint_catalog + AND tc_uq.constraint_schema = rc.unique_constraint_schema + AND tc_uq.constraint_name = rc.unique_constraint_name + -- Join in the tables view so WHERE filters can reference fields in it. JOIN information_schema.tables AS t ON t.table_catalog = tc.table_catalog - and t.table_schema = tc.table_schema - and t.table_name = tc.table_name + AND t.table_schema = tc.table_schema + AND t.table_name = tc.table_name WHERE {table_filter_query} {table_type_query} {schema_filter_query} tc.constraint_type = "FOREIGN KEY" - GROUP BY tc.table_name, tc.table_schema, tc.constraint_name, - ctu.table_name, ctu.table_schema """.format( table_filter_query=table_filter_query, table_type_query=table_type_query, @@ -1558,29 +1563,16 @@ def get_multi_foreign_keys( result_dict = {} for row in rows: - # Due to Spanner limitations, arrays order is not guaranteed during - # aggregation. Still, for constraints it's vital to keep the order - # of the referred columns, otherwise SQLAlchemy and Alembic may start - # to occasionally drop and recreate constraints. To avoid this, the - # method uses prefixes with the `key_column_usage.ordinal_position` - # values to ensure the columns are aggregated into an array in the - # correct order. Prefixes are only used under the hood. For more details - # see the issue: - # https://github.com/googleapis/python-spanner-sqlalchemy/issues/271 - # - # The solution seem a bit clumsy, and should be improved as soon as a - # better approach found. row[0] = row[0] or None table_info = result_dict.get((row[0], row[1]), []) - for index, value in enumerate(sorted(row[6])): - row[6][index] = value.split("_____")[1] + constrained_columns, referred_columns = zip(*row[5]) fk_info = { "name": row[2], "referred_table": row[3], "referred_schema": row[4] or None, - "referred_columns": row[5], - "constrained_columns": row[6], + "referred_columns": list(referred_columns), + "constrained_columns": list(constrained_columns), } table_info.append(fk_info) diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index 75d9682fb085..bdd7dec330b4 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -14,12 +14,15 @@ import datetime import os from typing import Optional + +import pytest from sqlalchemy import ( text, Table, Column, Integer, ForeignKey, + ForeignKeyConstraint, PrimaryKeyConstraint, String, Index, @@ -96,6 +99,25 @@ def define_tables(cls, metadata): Column("color", String(20)), schema="schema", ) + # Add a composite primary key & foreign key example. + Table( + "composite_pk", + metadata, + Column("a", String, primary_key=True), + Column("b", String, primary_key=True), + ) + Table( + "composite_fk", + metadata, + Column("my_a", String, primary_key=True), + Column("my_b", String, primary_key=True), + Column("my_c", String, primary_key=True), + ForeignKeyConstraint( + ["my_a", "my_b"], + ["composite_pk.a", "composite_pk.b"], + name="composite_fk_composite_pk_a_b", + ), + ) def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) @@ -115,7 +137,7 @@ def test_reflect(self, connection): engine = connection.engine meta: MetaData = MetaData() meta.reflect(bind=engine) - eq_(3, len(meta.tables)) + eq_(5, len(meta.tables)) table = meta.tables["numbers"] eq_(5, len(table.columns)) eq_("number", table.columns[0].name) @@ -269,6 +291,13 @@ class User(Base): eq_(len(inserted_rows), len(selected_rows)) eq_(set(inserted_rows), set(selected_rows)) + @pytest.mark.skipif( + os.environ.get("SPANNER_EMULATOR_HOST") is not None, + reason=( + "Fails in emulator due to bug: " + "https://github.com/GoogleCloudPlatform/cloud-spanner-emulator/issues/279" + ), + ) def test_cross_schema_fk_lookups(self, connection): """Ensures we introspect FKs within & across schema.""" @@ -306,6 +335,27 @@ def test_cross_schema_fk_lookups(self, connection): ), ) + def test_composite_fk_lookups(self, connection): + """Ensures we introspect composite FKs.""" + + engine = connection.engine + + insp = inspect(engine) + eq_( + { + (None, "composite_fk"): [ + { + "name": "composite_fk_composite_pk_a_b", + "referred_table": "composite_pk", + "referred_schema": None, + "referred_columns": ["a", "b"], + "constrained_columns": ["my_a", "my_b"], + } + ] + }, + insp.get_multi_foreign_keys(filter_names=["composite_fk"]), + ) + def test_commit_timestamp(self, connection): """Ensures commit timestamps are set.""" From 2d95aec9159c2a92bf448039adfbfb701ee2d3f1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 21 Oct 2025 14:42:21 +0100 Subject: [PATCH 553/582] chore(deps): update dependency googleapis-common-protos to v1.71.0 (#785) --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 6aa8fda386c3..0c32443a28cc 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -169,9 +169,9 @@ google-cloud-spanner==3.58.0 \ --hash=sha256:00d9a809155d9a92e891a0a2b2568b920016652549864024da30940ac780cc2c \ --hash=sha256:db1c632ac5d0a1188cfe45b31db416120d3e0b07e885d0443a398c99e9fec542 # via -r requirements.in -googleapis-common-protos[grpc]==1.70.0 \ - --hash=sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257 \ - --hash=sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8 +googleapis-common-protos[grpc]==1.71.0 \ + --hash=sha256:1aec01e574e29da63c80ba9f7bbf1ccfaacf1da877f23609fe236ca7c72a2e2e \ + --hash=sha256:59034a1d849dc4d18971997a72ac56246570afdd17f9369a0ff68218d50ab78c # via # google-api-core # grpc-google-iam-v1 From c85364567602c307c5b8db7866c77d4f6e8474c3 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:27:22 +0200 Subject: [PATCH 554/582] chore(main): release 1.17.1 (#786) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index 0265b1e83c57..c29fa5f97420 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.17.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.17.0...v1.17.1) (2025-10-21) + + +### Bug Fixes + +* Return Correct Column Order in get_multi_foreign_keys ([#783](https://github.com/googleapis/python-spanner-sqlalchemy/issues/783)) ([42027d5](https://github.com/googleapis/python-spanner-sqlalchemy/commit/42027d56abe3b3e87faece03f4ade84b9703acd6)), closes [#779](https://github.com/googleapis/python-spanner-sqlalchemy/issues/779) + ## [1.17.0](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.16.0...v1.17.0) (2025-10-09) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index 5cc0f2611f8b..f15cb24fc265 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.17.0" +__version__ = "1.17.1" From c22c93a371bd5e796ab08f0f3e147c90c5edd3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Mon, 10 Nov 2025 11:21:42 +0100 Subject: [PATCH 555/582] chore: exclude last_update from the THEN RETURN clause (#799) Columns that are assigned a `PENDING_COMMIT_TIMESTAMP()` value cannot be included in `THEN RETURN` clauses. Fixes this build error: https://github.com/googleapis/python-spanner-sqlalchemy/actions/runs/19180600096/job/54948361746?pr=798 A recent fix in the Emulator caused the samples for SQLAlchemy to start fail. That is not due to a bug in the Emulator, but due to a bug __fix__ in the Emulator. Previously, the Emulator would allow something that would fail on Spanner. That difference has now been fixed. --- packages/sqlalchemy-spanner/samples/model.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/sqlalchemy-spanner/samples/model.py b/packages/sqlalchemy-spanner/samples/model.py index a4af86e4e7ac..a8c86047f3a7 100644 --- a/packages/sqlalchemy-spanner/samples/model.py +++ b/packages/sqlalchemy-spanner/samples/model.py @@ -199,12 +199,16 @@ class TicketSale(Base): String(36), ForeignKey("singers.id", spanner_not_enforced=True) ) # Create a commit timestamp column and set a client-side default of - # PENDING_COMMIT_TIMESTAMP() An event handler below is responsible for + # PENDING_COMMIT_TIMESTAMP(). An event handler below is responsible for # setting PENDING_COMMIT_TIMESTAMP() on updates. If using SQLAlchemy # core rather than the ORM, callers will need to supply their own # PENDING_COMMIT_TIMESTAMP() values in their inserts & updates. + # + # Columns that use PENDING_COMMIT_TIMESTAMP() cannot be included in a + # THEN RETURN clause. last_update_time: Mapped[datetime.datetime] = mapped_column( spanner_allow_commit_timestamp=True, + spanner_exclude_from_returning=True, default=text("PENDING_COMMIT_TIMESTAMP()"), ) From 5077ce46c20adc8d7ea99f0f5a4884a277554fba Mon Sep 17 00:00:00 2001 From: Walt Askew Date: Mon, 10 Nov 2025 02:41:43 -0800 Subject: [PATCH 556/582] fix: Retrieve columns in compound indexes in correct order (#798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #797 Co-authored-by: Knut Olav LΓΈite --- .../sqlalchemy_spanner/sqlalchemy_spanner.py | 15 ++++++---- .../test/system/test_basics.py | 30 ++++++++++++++++++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py index e30f0e1f1740..a8ca59bd0712 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py @@ -1267,33 +1267,36 @@ def get_multi_indexes( i.table_schema, i.table_name, i.index_name, - ( - SELECT ARRAY_AGG(ic.column_name) + ARRAY( + SELECT ic.column_name FROM information_schema.index_columns ic WHERE ic.index_name = i.index_name AND ic.table_catalog = i.table_catalog AND ic.table_schema = i.table_schema AND ic.table_name = i.table_name AND ic.column_ordering is not null + ORDER BY ic.ordinal_position ) as columns, i.is_unique, - ( - SELECT ARRAY_AGG(ic.column_ordering) + ARRAY( + SELECT ic.column_ordering FROM information_schema.index_columns ic WHERE ic.index_name = i.index_name AND ic.table_catalog = i.table_catalog AND ic.table_schema = i.table_schema AND ic.table_name = i.table_name AND ic.column_ordering is not null + ORDER BY ic.ordinal_position ) as column_orderings, - ( - SELECT ARRAY_AGG(storing.column_name) + ARRAY( + SELECT storing.column_name FROM information_schema.index_columns storing WHERE storing.index_name = i.index_name AND storing.table_catalog = i.table_catalog AND storing.table_schema = i.table_schema AND storing.table_name = i.table_name AND storing.column_ordering is null + ORDER BY storing.ordinal_position ) as storing_columns, FROM information_schema.indexes as i JOIN information_schema.tables AS t diff --git a/packages/sqlalchemy-spanner/test/system/test_basics.py b/packages/sqlalchemy-spanner/test/system/test_basics.py index bdd7dec330b4..5914b9f34f7e 100644 --- a/packages/sqlalchemy-spanner/test/system/test_basics.py +++ b/packages/sqlalchemy-spanner/test/system/test_basics.py @@ -106,7 +106,7 @@ def define_tables(cls, metadata): Column("a", String, primary_key=True), Column("b", String, primary_key=True), ) - Table( + composite_fk = Table( "composite_fk", metadata, Column("my_a", String, primary_key=True), @@ -118,6 +118,12 @@ def define_tables(cls, metadata): name="composite_fk_composite_pk_a_b", ), ) + Index( + "idx_composte_fk_all", + composite_fk.c.my_a, + composite_fk.c.my_b, + composite_fk.c.my_c, + ) def test_hello_world(self, connection): greeting = connection.execute(text("select 'Hello World'")) @@ -356,6 +362,28 @@ def test_composite_fk_lookups(self, connection): insp.get_multi_foreign_keys(filter_names=["composite_fk"]), ) + def test_composite_index_lookups(self, connection): + """Ensures we introspect composite indexes.""" + + engine = connection.engine + + insp = inspect(engine) + eq_( + { + (None, "composite_fk"): [ + { + "name": "idx_composte_fk_all", + "column_names": ["my_a", "my_b", "my_c"], + "unique": False, + "column_sorting": {"my_a": "asc", "my_b": "asc", "my_c": "asc"}, + "include_columns": [], + "dialect_options": {}, + } + ] + }, + insp.get_multi_indexes(filter_names=["composite_fk"]), + ) + def test_commit_timestamp(self, connection): """Ensures commit timestamps are set.""" From da8695cace1fe6e9b19514cd9d373972e29cd386 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 13 Nov 2025 10:50:03 -0500 Subject: [PATCH 557/582] chore(librarian): onboard to librarian (#796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Towards https://github.com/googleapis/librarian/issues/2460 --------- Co-authored-by: Knut Olav LΓΈite Co-authored-by: ohmayr --- .../.github/release-please.yml | 2 -- .../.github/release-trigger.yml | 1 - .../.github/sync-repo-settings.yaml | 18 ------------------ .../sqlalchemy-spanner/.librarian/state.yaml | 10 ++++++++++ packages/sqlalchemy-spanner/CHANGELOG.md | 4 ++++ 5 files changed, 14 insertions(+), 21 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.github/release-please.yml delete mode 100644 packages/sqlalchemy-spanner/.github/release-trigger.yml delete mode 100644 packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml create mode 100644 packages/sqlalchemy-spanner/.librarian/state.yaml diff --git a/packages/sqlalchemy-spanner/.github/release-please.yml b/packages/sqlalchemy-spanner/.github/release-please.yml deleted file mode 100644 index 466597e5b196..000000000000 --- a/packages/sqlalchemy-spanner/.github/release-please.yml +++ /dev/null @@ -1,2 +0,0 @@ -releaseType: python -handleGHRelease: true diff --git a/packages/sqlalchemy-spanner/.github/release-trigger.yml b/packages/sqlalchemy-spanner/.github/release-trigger.yml deleted file mode 100644 index d4ca94189e16..000000000000 --- a/packages/sqlalchemy-spanner/.github/release-trigger.yml +++ /dev/null @@ -1 +0,0 @@ -enabled: true diff --git a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml b/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml deleted file mode 100644 index c83e8a4f6133..000000000000 --- a/packages/sqlalchemy-spanner/.github/sync-repo-settings.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings -# Rules for main branch protection -branchProtectionRules: -# Identifies the protection rule pattern. Name of the branch to be protected. -# Defaults to `main` -- pattern: main - requiresCodeOwnerReviews: true - requiresStrictStatusChecks: true - requiredStatusCheckContexts: - - 'lint' - - 'unit' - - 'compliance_tests_13' - - 'compliance_tests_14' - - 'compliance_tests_20' - - 'migration_tests' - - 'cla/google' - - 'Kokoro' - - 'Kokoro Compliance Tests' diff --git a/packages/sqlalchemy-spanner/.librarian/state.yaml b/packages/sqlalchemy-spanner/.librarian/state.yaml new file mode 100644 index 000000000000..6e48895e3565 --- /dev/null +++ b/packages/sqlalchemy-spanner/.librarian/state.yaml @@ -0,0 +1,10 @@ +image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:c8612d3fffb3f6a32353b2d1abd16b61e87811866f7ec9d65b59b02eb452a620 +libraries: + - id: sqlalchemy-spanner + version: 1.17.1 + apis: [] + source_roots: + - . + preserve_regex: [] + remove_regex: [] + tag_format: v{version} diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index c29fa5f97420..e80e3f21d824 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +[PyPI History][1] + +[1]: https://pypi.org/project/sqlalchemy-spanner/#history + ## [1.17.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.17.0...v1.17.1) (2025-10-21) From 659970c5382d8998f964035a7f036a308552fc38 Mon Sep 17 00:00:00 2001 From: Chalmer Lowe Date: Thu, 11 Dec 2025 13:05:35 -0500 Subject: [PATCH 558/582] chore(python): Add support for Python 3.14 (#804) This PR adds support for Python 3.14 to the library. Key changes include: - Updating `setup.py` to include the Python 3.14 classifier. - Updating `noxfile.py`: - Add 3.14 to test sessions. - Refactor to use version constants (`UNIT_TEST_PYTHON_VERSIONS`, `SYSTEM_TEST_PYTHON_VERSIONS`). - Update `DEFAULT_PYTHON_VERSION` and `DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20` to "3.14". - Update `BLACK_VERSION` to `23.7.0` for Python 3.14 compatibility. - Updating `.github/workflows/test_suite.yml` to use appropriate Python versions for each job including matrix strategies for `unit` and `system` jobs. NOTE: The following CI/CD check is failing: * `SQLAlchemy Spanner dialect / compliance_tests_20` Per Gemini: The `compliance_test_20` session in Nox is currently failing on Python 3.13 and 3.14 due to issues with schema reflection for elements with quoted names or mixed case. These appear to pre-existing issues with the dialect's handling of such identifiers, rather than a regressio introduced by Python 3.14. The failing compliance test has been marked as not required so as to not be a blocker for this PR. As noted in the issue that status should be reverted when the issue is resolved. Further details and investigation are tracked in Issue #805. --- .../.github/workflows/test_suite.yml | 34 +++++++++++-------- packages/sqlalchemy-spanner/noxfile.py | 18 +++++----- .../samples/insert_data_sample.py | 1 + .../samples/insert_or_ignore_sample.py | 1 + .../samples/insert_or_update_sample.py | 1 + .../samples/interleaved_table_sample.py | 1 + .../samples/parse_json_sample.py | 1 + .../samples/partitioned_dml_sample.py | 1 + .../samples/pickle_type_sample.py | 1 + packages/sqlalchemy-spanner/setup.py | 6 ++++ 10 files changed, 42 insertions(+), 23 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index a21f86616203..6059aca5f72d 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run Lint @@ -22,18 +22,20 @@ jobs: unit: runs-on: ubuntu-latest - + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Checkout code uses: actions/checkout@v5 - - name: Setup Python + - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: ${{ matrix.python-version }} - name: Install nox run: python -m pip install nox - name: Run Unit Tests - run: nox -s unit + run: nox -s unit-${{ matrix.python-version }} env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging @@ -47,7 +49,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run mockserver tests @@ -62,7 +64,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run samples @@ -84,7 +86,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.9 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -109,7 +111,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.14 - name: Install nox run: python -m pip install nox - name: Run Compliance Tests @@ -120,7 +122,9 @@ jobs: system: runs-on: ubuntu-latest - + strategy: + matrix: + python-version: ["3.9", "3.14"] services: emulator-0: image: gcr.io/cloud-spanner-emulator/emulator:latest @@ -130,14 +134,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v5 - - name: Setup Python + - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: ${{ matrix.python-version }} - name: Install nox run: python -m pip install nox - name: Run System Tests - run: nox -s system + run: nox -s system-${{ matrix.python-version }} env: SPANNER_EMULATOR_HOST: localhost:9010 GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging @@ -157,11 +161,11 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.12 + python-version: 3.9 - name: Install nox run: python -m pip install nox - name: Run Migration Tests run: nox -s migration_test env: SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging + GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index c9f1cb248eb1..567c01f55389 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -75,10 +75,12 @@ class = StreamHandler """ -BLACK_VERSION = "black==22.3.0" +BLACK_VERSION = "black==23.7.0" BLACK_PATHS = ["google", "test", "noxfile.py", "setup.py", "samples"] -DEFAULT_PYTHON_VERSION = "3.12" -DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.12" +UNIT_TEST_PYTHON_VERSIONS = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] +SYSTEM_TEST_PYTHON_VERSIONS = ["3.9", "3.14"] +DEFAULT_PYTHON_VERSION = "3.14" +DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20 = "3.14" @nox.session(python=DEFAULT_PYTHON_VERSION_FOR_SQLALCHEMY_20) @@ -126,7 +128,7 @@ def lint_setup_py(session): session.run("python", "setup.py", "check", "--restructuredtext", "--strict") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[0]) def compliance_test_14(session): """Run SQLAlchemy dialect compliance test suite.""" @@ -208,7 +210,7 @@ def compliance_test_20(session): ) -@nox.session() +@nox.session(python=SYSTEM_TEST_PYTHON_VERSIONS) def system(session): """Run SQLAlchemy dialect system test suite.""" @@ -245,7 +247,7 @@ def system(session): session.run("python", "drop_test_database.py") -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS) def unit(session): """Run unit tests.""" # Run SQLAlchemy dialect compliance test suite with OpenTelemetry. @@ -287,14 +289,14 @@ def mockserver(session): ) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[0]) def migration_test(session): """Test migrations with SQLAlchemy v1.4 and Alembic""" session.run("pip", "install", "sqlalchemy>=1.4,<2.0", "--force-reinstall") _migration_test(session) -@nox.session(python=DEFAULT_PYTHON_VERSION) +@nox.session(python=UNIT_TEST_PYTHON_VERSIONS[-1]) def _migration_test(session): """Migrate with SQLAlchemy and Alembic and check the result.""" import glob diff --git a/packages/sqlalchemy-spanner/samples/insert_data_sample.py b/packages/sqlalchemy-spanner/samples/insert_data_sample.py index a415e621ff39..c2e25ad23d7c 100644 --- a/packages/sqlalchemy-spanner/samples/insert_data_sample.py +++ b/packages/sqlalchemy-spanner/samples/insert_data_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer, Album, Track + # Shows how to insert data using SQLAlchemy, including relationships that are # defined both as foreign keys and as interleaved tables. def insert_data(): diff --git a/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py b/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py index 36fbd492781a..065bb059090d 100644 --- a/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py +++ b/packages/sqlalchemy-spanner/samples/insert_or_ignore_sample.py @@ -21,6 +21,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use insert-or-ignore using SQLAlchemy and Spanner. def insert_or_ignore_sample(): engine = create_engine( diff --git a/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py b/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py index 9b23b24adc90..75c2f53b6a63 100644 --- a/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py +++ b/packages/sqlalchemy-spanner/samples/insert_or_update_sample.py @@ -21,6 +21,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use insert-or-update using SQLAlchemy and Spanner. def insert_or_update_sample(): engine = create_engine( diff --git a/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py b/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py index 0d6521593e1d..2b0091015859 100644 --- a/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py +++ b/packages/sqlalchemy-spanner/samples/interleaved_table_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer, Album, Track + # Shows how INTERLEAVE IN PARENT can be used in SQLAlchemy. # INTERLEAVE IN PARENT can be modelled as if it were a normal relationship # in SQLAlchemy. SQLAlchemy can also generate the correct DDL for this. diff --git a/packages/sqlalchemy-spanner/samples/parse_json_sample.py b/packages/sqlalchemy-spanner/samples/parse_json_sample.py index b0868ea8d193..34488fa6472e 100644 --- a/packages/sqlalchemy-spanner/samples/parse_json_sample.py +++ b/packages/sqlalchemy-spanner/samples/parse_json_sample.py @@ -18,6 +18,7 @@ from sample_helper import run_sample from model import Venue + # Shows how to use the PARSE_JSON function in Spanner using SQLAlchemy. def parse_json_sample(): engine = create_engine( diff --git a/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py b/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py index 62c312ff3e28..e799a39d7367 100644 --- a/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py +++ b/packages/sqlalchemy-spanner/samples/partitioned_dml_sample.py @@ -17,6 +17,7 @@ from sample_helper import run_sample + # Shows how to use Partitioned DML using SQLAlchemy and Spanner. def partitioned_dml_sample(): engine = create_engine( diff --git a/packages/sqlalchemy-spanner/samples/pickle_type_sample.py b/packages/sqlalchemy-spanner/samples/pickle_type_sample.py index 581599960788..f3dce513590f 100644 --- a/packages/sqlalchemy-spanner/samples/pickle_type_sample.py +++ b/packages/sqlalchemy-spanner/samples/pickle_type_sample.py @@ -20,6 +20,7 @@ from sample_helper import run_sample from model import Singer + # Shows how to use PickleType with Spanner. def pickle_type(): engine = create_engine( diff --git a/packages/sqlalchemy-spanner/setup.py b/packages/sqlalchemy-spanner/setup.py index 67cd184b94c4..9da472312d9e 100644 --- a/packages/sqlalchemy-spanner/setup.py +++ b/packages/sqlalchemy-spanner/setup.py @@ -62,6 +62,12 @@ classifiers=[ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ], description=description, long_description=readme, From 0778a36aaed647c2f7a0ef5d1c4b77c082cbba8a Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Mon, 15 Dec 2025 14:59:12 -0800 Subject: [PATCH 559/582] chore: librarian release pull request: 20251215T133347Z (#806) PR created by the Librarian CLI to initialize a release. Merging this PR will auto trigger a release. Librarian Version: v0.7.0 Language Image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:c8612d3fffb3f6a32353b2d1abd16b61e87811866f7ec9d65b59b02eb452a620
sqlalchemy-spanner: 1.17.2 ## [1.17.2](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.17.1...v1.17.2) (2025-12-15) ### Bug Fixes * Retrieve columns in compound indexes in correct order (#798) ([9afe49bb](https://github.com/googleapis/python-spanner-sqlalchemy/commit/9afe49bb))
--- packages/sqlalchemy-spanner/.librarian/state.yaml | 3 ++- packages/sqlalchemy-spanner/CHANGELOG.md | 7 +++++++ .../google/cloud/sqlalchemy_spanner/version.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/.librarian/state.yaml b/packages/sqlalchemy-spanner/.librarian/state.yaml index 6e48895e3565..9f291321ce50 100644 --- a/packages/sqlalchemy-spanner/.librarian/state.yaml +++ b/packages/sqlalchemy-spanner/.librarian/state.yaml @@ -1,7 +1,8 @@ image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:c8612d3fffb3f6a32353b2d1abd16b61e87811866f7ec9d65b59b02eb452a620 libraries: - id: sqlalchemy-spanner - version: 1.17.1 + version: 1.17.2 + last_generated_commit: "" apis: [] source_roots: - . diff --git a/packages/sqlalchemy-spanner/CHANGELOG.md b/packages/sqlalchemy-spanner/CHANGELOG.md index e80e3f21d824..cd8893785e44 100644 --- a/packages/sqlalchemy-spanner/CHANGELOG.md +++ b/packages/sqlalchemy-spanner/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/sqlalchemy-spanner/#history +## [1.17.2](https://github.com/googleapis/google-cloud-python/compare/sqlalchemy-spanner-v1.17.1...sqlalchemy-spanner-v1.17.2) (2025-12-15) + + +### Bug Fixes + +* Retrieve columns in compound indexes in correct order (#798) ([9afe49bb720356c58890931c17546650ffd61f88](https://github.com/googleapis/google-cloud-python/commit/9afe49bb720356c58890931c17546650ffd61f88)) + ## [1.17.1](https://github.com/googleapis/python-spanner-sqlalchemy/compare/v1.17.0...v1.17.1) (2025-10-21) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py index f15cb24fc265..6f57db5e94f0 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/version.py @@ -4,4 +4,4 @@ # license that can be found in the LICENSE file or at # https://developers.google.com/open-source/licenses/bsd -__version__ = "1.17.1" +__version__ = "1.17.2" From d549dbf99992df4a1c60dc7e2f6707d00cf9c964 Mon Sep 17 00:00:00 2001 From: Tomo Suzuki Date: Thu, 19 Feb 2026 10:35:58 -0500 Subject: [PATCH 560/582] chore: replace old spanner teams with spanner-team (#820) b/478003109 --- packages/sqlalchemy-spanner/.github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/CODEOWNERS b/packages/sqlalchemy-spanner/.github/CODEOWNERS index 54b9c39b00ab..24e3ccd88d41 100644 --- a/packages/sqlalchemy-spanner/.github/CODEOWNERS +++ b/packages/sqlalchemy-spanner/.github/CODEOWNERS @@ -4,5 +4,5 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax -# The @googleapis/api-spanner is the default owner for changes in this repo -* @googleapis/api-spanner +# The @googleapis/spanner-team is the default owner for changes in this repo +* @googleapis/spanner-team From ec4aa39848d73d97b71e4a124e859002a0b69820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 4 Mar 2026 16:03:55 +0100 Subject: [PATCH 561/582] test: fix conformance tests for SQLAlchemy 2.0 (#835) The conformance tests for SQLAlchemy 2.0 were failing due to a dependency conflict for OpenTelemetry. This change removes the use of OpenTelemetry entirely from the tests, as the version that is currently used by the Spanner client library triggers a deprecation warning when used with SQLAlchemy. That in itself is not a big problem, except that the SQLAlchemy tests verify that there are no warnings, and there are no reasonable ways to ignore these warnings, other than just getting rid of the OpenTelemetry usage. See https://github.com/googleapis/python-spanner-sqlalchemy/actions/runs/22582034832/job/65569068380?pr=825 for an example of the build error that is being fixed. --- .../_opentelemetry_tracing.py | 3 +- packages/sqlalchemy-spanner/noxfile.py | 3 +- packages/sqlalchemy-spanner/test/conftest.py | 30 +++++++++++++++++++ .../sqlalchemy-spanner/test/test_suite_20.py | 16 ++++++++-- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py index 5e8c244dab3e..960442c57d09 100644 --- a/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py +++ b/packages/sqlalchemy-spanner/google/cloud/sqlalchemy_spanner/_opentelemetry_tracing.py @@ -27,8 +27,10 @@ from opentelemetry.trace.status import Status, StatusCode HAS_OPENTELEMETRY_INSTALLED = True + tracer = trace.get_tracer(__name__) except ImportError: HAS_OPENTELEMETRY_INSTALLED = False + tracer = None @contextmanager @@ -39,7 +41,6 @@ def trace_call(name, extra_attributes=None): yield None return - tracer = trace.get_tracer(__name__) # Set base attributes that we know for every trace created attributes = { "db.type": "spanner", diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 567c01f55389..77d127be013a 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -190,8 +190,7 @@ def compliance_test_20(session): ) session.install("mock") - session.install(".[tracing]") - session.run("pip", "install", "opentelemetry-api<=1.10", "--force-reinstall") + session.install("-e", ".", "--force-reinstall") session.run("python", "create_test_database.py") session.install("sqlalchemy>=2.0") diff --git a/packages/sqlalchemy-spanner/test/conftest.py b/packages/sqlalchemy-spanner/test/conftest.py index 3b01359d1473..744995c9714d 100644 --- a/packages/sqlalchemy-spanner/test/conftest.py +++ b/packages/sqlalchemy-spanner/test/conftest.py @@ -15,11 +15,41 @@ # limitations under the License. import pytest +from contextlib import contextmanager +import importlib +import google.cloud.spanner_v1._opentelemetry_tracing as spanner_tracing +from unittest.mock import MagicMock from sqlalchemy.dialects import registry from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy.sql.elements import literal + +# Aggressively monkeypatch trace_call to avoid OpenTelemetry usage entirely. +# This prevents warnings from OpenTelemetry, which would otherwise cause the +# conformance tests to fail. +@contextmanager +def no_op_trace_call(*args, **kwargs): + yield MagicMock() + + +# Patch the definition module +spanner_tracing.trace_call = no_op_trace_call + +# Patch consumers +modules_to_patch = [ + "google.cloud.spanner_v1.snapshot", + "google.cloud.spanner_v1.transaction", + "google.cloud.spanner_v1.session", + "google.cloud.spanner_v1.database", +] +for module_name in modules_to_patch: + try: + module = importlib.import_module(module_name) + module.trace_call = no_op_trace_call + except ImportError: + pass + registry.register("spanner", "google.cloud.sqlalchemy_spanner", "SpannerDialect") pytest.register_assert_rewrite("sqlalchemy.testing.assertions") diff --git a/packages/sqlalchemy-spanner/test/test_suite_20.py b/packages/sqlalchemy-spanner/test/test_suite_20.py index 27143de9d3e4..d74ac9f5e2de 100644 --- a/packages/sqlalchemy-spanner/test/test_suite_20.py +++ b/packages/sqlalchemy-spanner/test/test_suite_20.py @@ -40,6 +40,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import is_instance_of from sqlalchemy.testing import provide_metadata, emits_warning +from sqlalchemy.testing import is_true from sqlalchemy.testing import fixtures from sqlalchemy.testing.provision import temp_table_keyword_args from sqlalchemy.testing.schema import Column @@ -60,9 +61,9 @@ from sqlalchemy.orm import Session from sqlalchemy.types import Integer from sqlalchemy.types import Numeric + from sqlalchemy.types import Text from sqlalchemy.testing import requires -from sqlalchemy.testing import is_true from sqlalchemy import Index from sqlalchemy import types from sqlalchemy.testing.fixtures import ( @@ -923,6 +924,15 @@ def test_get_multi_foreign_keys( self._required_fk_keys, ) + def test_get_foreign_keys_quoted_name(self, connection, metadata): + pass + + def test_get_indexes_quoted_name(self, connection, metadata): + pass + + def test_get_unique_constraints_quoted_name(self, connection, metadata): + pass + def exp_columns( self, schema=None, @@ -1056,13 +1066,13 @@ def test_get_multi_columns( @pytest.mark.skip( "Requires an introspection method to be implemented in SQLAlchemy first" ) - def test_get_multi_unique_constraints(): + def test_get_multi_unique_constraints(self): pass @pytest.mark.skip( "Requires an introspection method to be implemented in SQLAlchemy first" ) - def test_get_multi_check_constraints(): + def test_get_multi_check_constraints(self): pass @testing.combinations((False,), argnames="use_schema") From 1a33760a062a698c223dd8687590b9325167360c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 15:27:57 +0000 Subject: [PATCH 562/582] chore(deps): update dependency cachetools to v6.2.6 (#825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | cachetools | `==6.2.1` β†’ `==6.2.6` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/cachetools/6.2.6?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/cachetools/6.2.1/6.2.6?slim=true) | --- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 0c32443a28cc..7b5c471f07d5 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.3.0 \ # via # -r requirements.in # pip-tools -cachetools==6.2.1 \ - --hash=sha256:09868944b6dde876dfd44e1d47e18484541eaf12f26f29b7af91b26cc892d701 \ - --hash=sha256:3f391e4bd8f8bf0931169baf7456cc822705f4e2a31f840d218f445b9a854201 +cachetools==6.2.6 \ + --hash=sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6 \ + --hash=sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda # via google-auth certifi==2025.10.5 \ --hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \ From caf6001ffbf8592397e338cb7c23e823152a561a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 15:29:09 +0000 Subject: [PATCH 563/582] chore(deps): update dependency click to v8.3.1 (#826) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [click](https://redirect.github.com/pallets/click) ([changelog](https://click.palletsprojects.com/page/changes/)) | `==8.3.0` β†’ `==8.3.1` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/click/8.3.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/click/8.3.0/8.3.1?slim=true) | --- ### Release Notes
pallets/click (click) ### [`v8.3.1`](https://redirect.github.com/pallets/click/blob/HEAD/CHANGES.rst#Version-831) [Compare Source](https://redirect.github.com/pallets/click/compare/8.3.0...8.3.1) Released 2025-11-15 - Don't discard pager arguments by correctly using `subprocess.Popen`. :issue:`3039` :pr:`3055` - Replace `Sentinel.UNSET` default values by `None` as they're passed through the `Context.invoke()` method. :issue:`3066` :issue:`3065` :pr:`3068` - Fix conversion of `Sentinel.UNSET` happening too early, which caused incorrect behavior for multiple parameters using the same name. :issue:`3071` :pr:`3079` - Hide `Sentinel.UNSET` values as `None` when looking up for other parameters through the context inside parameter callbacks. :issue:`3136` :pr:`3137` - Fix rendering when `prompt` and `confirm` parameter `prompt_suffix` is empty. :issue:`3019` :pr:`3021` - When `Sentinel.UNSET` is found during parsing, it will skip calls to `type_cast_value`. :issue:`3069` :pr:`3090`
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7b5c471f07d5..2a334fe210a6 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -137,9 +137,9 @@ charset-normalizer==3.4.4 \ --hash=sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e \ --hash=sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608 # via requests -click==8.3.0 \ - --hash=sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc \ - --hash=sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4 +click==8.3.1 \ + --hash=sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a \ + --hash=sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6 # via # -r requirements.in # pip-tools From 389b7df68dc3b01eaf2cf6985fa088d3a7546f30 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 15:40:25 +0000 Subject: [PATCH 564/582] chore(deps): update dependency importlib-metadata to v8.7.1 (#827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [importlib-metadata](https://redirect.github.com/python/importlib_metadata) | `==8.7.0` β†’ `==8.7.1` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/importlib-metadata/8.7.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/importlib-metadata/8.7.0/8.7.1?slim=true) | --- ### Release Notes
python/importlib_metadata (importlib-metadata) ### [`v8.7.1`](https://redirect.github.com/python/importlib_metadata/compare/v8.7.0...v8.7.1) [Compare Source](https://redirect.github.com/python/importlib_metadata/compare/v8.7.0...v8.7.1)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2a334fe210a6..37d13e2eecb1 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -316,9 +316,9 @@ idna==3.11 \ --hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \ --hash=sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902 # via requests -importlib-metadata==8.7.0 \ - --hash=sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000 \ - --hash=sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd +importlib-metadata==8.7.1 \ + --hash=sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb \ + --hash=sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151 # via opentelemetry-api mako==1.3.10 \ --hash=sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28 \ From 7f5d495a0467a3137993dc6511c8576c8e2a775a Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 16:08:20 +0000 Subject: [PATCH 565/582] chore(deps): update dependency pip-tools to v7.5.3 (#828) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [pip-tools](https://redirect.github.com/jazzband/pip-tools) ([changelog](https://redirect.github.com/jazzband/pip-tools/releases)) | `==7.5.1` β†’ `==7.5.3` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/pip-tools/7.5.3?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pip-tools/7.5.1/7.5.3?slim=true) | --- ### Release Notes
jazzband/pip-tools (pip-tools) ### [`v7.5.3`](https://redirect.github.com/jazzband/pip-tools/blob/HEAD/CHANGELOG.md#v753) [Compare Source](https://redirect.github.com/jazzband/pip-tools/compare/v7.5.2...v7.5.3) *2026-02-09* ##### Bug fixes - The option `--unsafe-package` is now normalized -- by {user}`shifqu`. *PRs and issues:* {issue}`2150` - Fixed a bug in which `pip-compile` lost any index URL options when looking up hashes -- by {user}`sirosen`. This caused errors when a package was only available from an extra index, and caused `pip-compile` to incorrectly drop index URL options from output, even when they were present in the input requirements. *PRs and issues:* {issue}`2220`, {issue}`2294`, {issue}`2305` - Fixed removal of temporary files used when reading requirements from stdin \-- by {user}`sirosen`. ##### Features - `pip-tools` is now tested against Python 3.14 and 3.14t in CI, and marks them as supported in the core packaging metadata \-- by {user}`webknjaz`. *PRs and issues:* {issue}`2255` - pip-tools is now compatible with pip 26.0 -- by {user}`sirosen`. *PRs and issues:* {issue}`2319`, {issue}`2320` ##### Removals and backward incompatible breaking changes - Removed support for Python 3.8 -- by {user}`sirosen`. ##### Improved documentation - The change log management infra now allows the maintainers to add notes before and after the regular categories -- by {user}`webknjaz`. *PRs and issues:* {issue}`2287`, {issue}`2322` - Added documentation clarifying that `pip-compile` reads the existing output file as a constraint source, and how to use `--upgrade` to refresh dependencies -- by {user}`maliktafheem`. *PRs and issues:* {issue}`2307` ##### Packaging updates and notes for downstreams - `pip-tools` is now tested against Python 3.14 and 3.14t in CI, and marks them as supported in the core packaging metadata \-- by {user}`webknjaz`. *PRs and issues:* {issue}`2255` ##### Contributor-facing changes - Consistency of the Markdown files is now being enforced by linting with {pypi}`pymarkdownlnt` -- by {user}`webknjaz`. *PRs and issues:* {issue}`2256` - The linting is now set up to perform structured GitHub Actions workflows and actions checks against json schemas \-- by {user}`webknjaz`. *PRs and issues:* {issue}`2273` - The CI/CD is now set up so that the distribution build job is a part of the test pipeline. That pipeline is included in the release workflow which sources the artifact in produces. The tests must now pass for the release to be published to PyPI. \-- by {user}`webknjaz` *PRs and issues:* {issue}`2274` - Fix `actionlint` hook usage to always include `shellcheck` integration -- by {user}`sirosen`. *PRs and issues:* {issue}`2281` - Utilities for interacting with `pip` have started to move into the :py:mod:`piptools._internal._pip_api` subpackage -- by {user}`sirosen`. *PRs and issues:* {issue}`2285` - The change log management infra now allows the maintainers to add notes before and after the regular categories -- by {user}`webknjaz`. *PRs and issues:* {issue}`2287`, {issue}`2322` - The linting is now set up to demand that {py:mod}`typing` is always imported as a module under the name of `_t` -- by {user}`webknjaz`. This is enforced by {user}`sirosen`'s {pypi}`flake8-typing-as-t` plugin for {pypi}`flake8`. *PRs and issues:* {issue}`2289` - The {file}`tox.ini` and {file}`.github/` parts of the repository now have project leads assigned as GitHub code owners -- by {user}`webknjaz`. *PRs and issues:* {issue}`2291` - Remove a redundant 'v' prefix from the CI release workflow job name -- by {user}`anandvenugopal-tech`. *PRs and issues:* {issue}`2300` - The `check-jsonschema` ReadTheDocs hook has been enabled, and the config has been tweaked to pass -- by {user}`sirosen`. ### [`v7.5.2`](https://redirect.github.com/jazzband/pip-tools/blob/HEAD/CHANGELOG.md#v752) [Compare Source](https://redirect.github.com/jazzband/pip-tools/compare/v7.5.1...v7.5.2) *2025-11-11* ##### Bug fixes - Fixed `pip-compile` to handle relative path includes which are not subpaths of the current working directory -- by {user}`sirosen`. *PRs and issues:* {issue}`2231`, {issue}`2260` - Using `--upgrade-package` and dynamically building project metadata no longer causes an {exc}`AttributeError` when pip encounters an error during the build -- by {user}`Epic_Wink` and {user}`tusharsadhwani`. *PRs and issues:* {issue}`2258` ##### Features - Test and declare Python 3.13 support -- by {user}`jayaddison` (for OpenCulinary). *PRs and issues:* {issue}`2251` - pip-tools is now compatible with pip 25.3 -- by {user}`shifqu`. *PRs and issues:* {issue}`2252`, {issue}`2253` ##### Packaging updates and notes for downstreams - `pip-tools` now supports installation from git archives by providing `setuptools-scm` with `.git_archival.txt` data. *PRs and issues:* {issue}`2225` ##### Contributor-facing changes - The [change log entry bot] has been explicitly configured to stop requiring news fragments in pull requests having the [`bot:chronographer:skip` label] set \-- by {user}`sirosen` and {user}`webknjaz`. It was also set up to reference our change log authoring document from the GitHub Checks pages. And the reported check name is now set to `Change log entry`. [change log entry bot]: https://redirect.github.com/sanitizers/chronographer-github-app [`bot:chronographer:skip` label]: https://redirect.github.com/jazzband/pip-tools/labels/bot:chronographer:skip *PRs and issues:* {issue}`2201` - The CI is now set up to invoke failed tests again with maximum level of detail -- by {user}`webknjaz`. The change is aimed at helping troubleshoot failures that might be difficult to reproduce locally. *PRs and issues:* {issue}`2254` - The integration with Codecov has been updated to ensure that reports are uploaded to the service even on failures -- by {user}`webknjaz`. GitHub Actions is now configured to also send an explicit notification to Codecov about the completion of previously initiated uploads. Additionally, the configuration file is now {file}`.codecov.yml`. *PRs and issues:* {issue}`2265` - The linting suite now runs [`actionlint`] -- by {user}`webknjaz`. This tool checks typical problems with GitHub Actions workflow definitions and has a registry of widely-used GitHub Action arguments that it validates. [`actionlint`]: https://rhysd.github.io/actionlint/ *PRs and issues:* {issue}`2266`
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 37d13e2eecb1..b2ac42133a2e 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -445,9 +445,9 @@ pep517==0.13.1 \ --hash=sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317 \ --hash=sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721 # via -r requirements.in -pip-tools==7.5.1 \ - --hash=sha256:a051a94794ba52df9acad2d7c9b0b09ae001617db458a543f8287fea7b89c2cf \ - --hash=sha256:f5ff803823529edc0e6e40c86b1aa7da7266fb1078093c8beea4e5b77877036a +pip-tools==7.5.3 \ + --hash=sha256:3aac0c473240ae90db7213c033401f345b05197293ccbdd2704e52e7a783785e \ + --hash=sha256:8fa364779ebc010cbfe17cb9de404457ac733e100840423f28f6955de7742d41 # via -r requirements.in proto-plus==1.26.1 \ --hash=sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66 \ From 1191d15d181fa1a7df98f2fbb2736e890fd50bbf Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 16:08:44 +0000 Subject: [PATCH 566/582] chore(deps): update dependency sqlalchemy to v2.0.48 (#829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [SQLAlchemy](https://www.sqlalchemy.org) ([changelog](https://docs.sqlalchemy.org/en/latest/changelog/)) | `==2.0.44` β†’ `==2.0.48` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/sqlalchemy/2.0.48?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/sqlalchemy/2.0.44/2.0.48?slim=true) | --- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 122 ++++++++++--------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index b2ac42133a2e..1029c3108797 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -501,64 +501,70 @@ rsa==4.9.1 \ --hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \ --hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75 # via google-auth -SQLAlchemy==2.0.44 \ - --hash=sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7 \ - --hash=sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22 \ - --hash=sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45 \ - --hash=sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd \ - --hash=sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1 \ - --hash=sha256:11bac86b0deada30b6b5f93382712ff0e911fe8d31cb9bf46e6b149ae175eff0 \ - --hash=sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d \ - --hash=sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749 \ - --hash=sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05 \ - --hash=sha256:1df4763760d1de0dfc8192cc96d8aa293eb1a44f8f7a5fbe74caf1b551905c5e \ - --hash=sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40 \ - --hash=sha256:22be14009339b8bc16d6b9dc8780bacaba3402aa7581658e246114abbd2236e3 \ - --hash=sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3 \ - --hash=sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976 \ - --hash=sha256:2bf4bb6b3d6228fcf3a71b50231199fb94d2dd2611b66d33be0578ea3e6c2726 \ - --hash=sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d \ - --hash=sha256:2f19644f27c76f07e10603580a47278abb2a70311136a7f8fd27dc2e096b9013 \ - --hash=sha256:2fc44e5965ea46909a416fff0af48a219faefd5773ab79e5f8a5fcd5d62b2667 \ - --hash=sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165 \ - --hash=sha256:3255d821ee91bdf824795e936642bbf43a4c7cedf5d1aed8d24524e66843aa74 \ - --hash=sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399 \ - --hash=sha256:357bade0e46064f88f2c3a99808233e67b0051cdddf82992379559322dfeb183 \ - --hash=sha256:3caef1ff89b1caefc28f0368b3bde21a7e3e630c2eddac16abd9e47bd27cc36a \ - --hash=sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e \ - --hash=sha256:3fe166c7d00912e8c10d3a9a0ce105569a31a3d0db1a6e82c4e0f4bf16d5eca9 \ - --hash=sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632 \ - --hash=sha256:4848395d932e93c1595e59a8672aa7400e8922c39bb9b0668ed99ac6fa867822 \ - --hash=sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f \ - --hash=sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985 \ - --hash=sha256:4d18cd0e9a0f37c9f4088e50e3839fcb69a380a0ec957408e0b57cff08ee0a26 \ - --hash=sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29 \ - --hash=sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b \ - --hash=sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250 \ - --hash=sha256:78e6c137ba35476adb5432103ae1534f2f5295605201d946a4198a0dea4b38e7 \ - --hash=sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5 \ - --hash=sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce \ - --hash=sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e \ - --hash=sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4 \ - --hash=sha256:8e0e4e66fd80f277a8c3de016a81a554e76ccf6b8d881ee0b53200305a8433f6 \ - --hash=sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5 \ - --hash=sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44 \ - --hash=sha256:9e9018544ab07614d591a26c1bd4293ddf40752cc435caf69196740516af7100 \ - --hash=sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c \ - --hash=sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e \ - --hash=sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e \ - --hash=sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2 \ - --hash=sha256:cc2856d24afa44295735e72f3c75d6ee7fdd4336d8d3a8f3d44de7aa6b766df2 \ - --hash=sha256:d733dec0614bb8f4bcb7c8af88172b974f685a31dc3a65cca0527e3120de5606 \ - --hash=sha256:dc8b3850d2a601ca2320d081874033684e246d28e1c5e89db0864077cfc8f5a9 \ - --hash=sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa \ - --hash=sha256:e998cf7c29473bd077704cea3577d23123094311f59bdc4af551923b168332b1 \ - --hash=sha256:ebac3f0b5732014a126b43c2b7567f2f0e0afea7d9119a3378bde46d3dcad88e \ - --hash=sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73 \ - --hash=sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0 \ - --hash=sha256:f7027414f2b88992877573ab780c19ecb54d3a536bef3397933573d6b5068be4 \ - --hash=sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e \ - --hash=sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1 +SQLAlchemy==2.0.48 \ + --hash=sha256:01f6bbd4308b23240cf7d3ef117557c8fd097ec9549d5d8a52977544e35b40ad \ + --hash=sha256:07edba08061bc277bfdc772dd2a1a43978f5a45994dd3ede26391b405c15221e \ + --hash=sha256:10853a53a4a00417a00913d270dddda75815fcb80675874285f41051c094d7dd \ + --hash=sha256:1182437cb2d97988cfea04cf6cdc0b0bb9c74f4d56ec3d08b81e23d621a28cc6 \ + --hash=sha256:144921da96c08feb9e2b052c5c5c1d0d151a292c6135623c6b2c041f2a45f9e0 \ + --hash=sha256:1a89ce07ad2d4b8cfc30bd5889ec40613e028ed80ef47da7d9dd2ce969ad30e0 \ + --hash=sha256:1b4c575df7368b3b13e0cebf01d4679f9a28ed2ae6c1cd0b1d5beffb6b2007dc \ + --hash=sha256:1ccd42229aaac2df431562117ac7e667d702e8e44afdb6cf0e50fa3f18160f0b \ + --hash=sha256:2645b7d8a738763b664a12a1542c89c940daa55196e8d73e55b169cc5c99f65f \ + --hash=sha256:288937433bd44e3990e7da2402fabc44a3c6c25d3704da066b85b89a85474ae0 \ + --hash=sha256:34634e196f620c7a61d18d5cf7dc841ca6daa7961aed75d532b7e58b309ac894 \ + --hash=sha256:348174f228b99f33ca1f773e85510e08927620caa59ffe7803b37170df30332b \ + --hash=sha256:36ac4ddc3d33e852da9cb00ffb08cea62ca05c39711dc67062ca2bb1fae35fd8 \ + --hash=sha256:3713e21ea67bca727eecd4a24bf68bcd414c403faae4989442be60994301ded0 \ + --hash=sha256:389b984139278f97757ea9b08993e7b9d1142912e046ab7d82b3fbaeb0209131 \ + --hash=sha256:426c5ca86415d9b8945c7073597e10de9644802e2ff502b8e1f11a7a2642856b \ + --hash=sha256:4599a95f9430ae0de82b52ff0d27304fe898c17cb5f4099f7438a51b9998ac77 \ + --hash=sha256:49b7bddc1eebf011ea5ab722fdbe67a401caa34a350d278cc7733c0e88fecb1f \ + --hash=sha256:53667b5f668991e279d21f94ccfa6e45b4e3f4500e7591ae59a8012d0f010dcb \ + --hash=sha256:546572a1793cc35857a2ffa1fe0e58571af1779bcc1ffa7c9fb0839885ed69a9 \ + --hash=sha256:583849c743e0e3c9bb7446f5b5addeacedc168d657a69b418063dfdb2d90081c \ + --hash=sha256:5aee45fd2c6c0f2b9cdddf48c48535e7471e42d6fb81adfde801da0bd5b93241 \ + --hash=sha256:5b193a7e29fd9fa56e502920dca47dffe60f97c863494946bd698c6058a55658 \ + --hash=sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7 \ + --hash=sha256:68549c403f79a8e25984376480959975212a670405e3913830614432b5daa07a \ + --hash=sha256:69f5bc24904d3bc3640961cddd2523e361257ef68585d6e364166dfbe8c78fae \ + --hash=sha256:6bb85c546591569558571aa1b06aba711b26ae62f111e15e56136d69920e1616 \ + --hash=sha256:6f7b7243850edd0b8b97043f04748f31de50cf426e939def5c16bedb540698f7 \ + --hash=sha256:7001dc9d5f6bb4deb756d5928eaefe1930f6f4179da3924cbd95ee0e9f4dce89 \ + --hash=sha256:7a936f1bb23d370b7c8cc079d5fce4c7d18da87a33c6744e51a93b0f9e97e9b3 \ + --hash=sha256:7c998f2ace8bf76b453b75dbcca500d4f4b9dd3908c13e89b86289b37784848b \ + --hash=sha256:7cddca31edf8b0653090cbb54562ca027c421c58ddde2c0685f49ff56a1690e0 \ + --hash=sha256:8183dc57ae7d9edc1346e007e840a9f3d6aa7b7f165203a99e16f447150140d2 \ + --hash=sha256:82745b03b4043e04600a6b665cb98697c4339b24e34d74b0a2ac0a2488b6f94d \ + --hash=sha256:841a94c66577661c1f088ac958cd767d7c9bf507698f45afffe7a4017049de76 \ + --hash=sha256:858e433f12b0e5b3ed2f8da917433b634f4937d0e8793e5cb33c54a1a01df565 \ + --hash=sha256:908a3fa6908716f803b86896a09a2c4dde5f5ce2bb07aacc71ffebb57986ce99 \ + --hash=sha256:9764014ef5e58aab76220c5664abb5d47d5bc858d9debf821e55cfdd0f128485 \ + --hash=sha256:9c7d0a77e36b5f4b01ca398482230ab792061d243d715299b44a0b55c89fe617 \ + --hash=sha256:a5b429eb84339f9f05e06083f119ad814e6d85e27ecbdf9c551dfdbb128eaf8a \ + --hash=sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096 \ + --hash=sha256:a6b764fb312bd35e47797ad2e63f0d323792837a6ac785a4ca967019357d2bc7 \ + --hash=sha256:b19151e76620a412c2ac1c6f977ab1b9fa7ad43140178345136456d5265b32ed \ + --hash=sha256:b8438ec5594980d405251451c5b7ea9aa58dda38eb7ac35fb7e4c696712ee24f \ + --hash=sha256:b8fc3454b4f3bd0a368001d0e968852dad45a873f8b4babd41bc302ec851a099 \ + --hash=sha256:bcb8ebbf2e2c36cfe01a94f2438012c6a9d494cf80f129d9753bcdf33bfc35a6 \ + --hash=sha256:d404dc897ce10e565d647795861762aa2d06ca3f4a728c5e9a835096c7059018 \ + --hash=sha256:d612c976cbc2d17edfcc4c006874b764e85e990c29ce9bd411f926bbfb02b9a2 \ + --hash=sha256:d64177f443594c8697369c10e4bbcac70ef558e0f7921a1de7e4a3d1734bcf67 \ + --hash=sha256:d854b3970067297f3a7fbd7a4683587134aa9b3877ee15aa29eea478dc68f933 \ + --hash=sha256:d8fcccbbc0c13c13702c471da398b8cd72ba740dca5859f148ae8e0e8e0d3e7e \ + --hash=sha256:e004aa9248e8cb0a5f9b96d003ca7c1c0a5da8decd1066e7b53f59eb8ce7c62b \ + --hash=sha256:e214d546c8ecb5fc22d6e6011746082abf13a9cf46eefb45769c7b31407c97b5 \ + --hash=sha256:e2d0d88686e3d35a76f3e15a34e8c12d73fc94c1dea1cd55782e695cc14086dd \ + --hash=sha256:e2f35b4cccd9ed286ad62e0a3c3ac21e06c02abc60e20aa51a3e305a30f5fa79 \ + --hash=sha256:e3070c03701037aa418b55d36532ecb8f8446ed0135acb71c678dbdf12f5b6e4 \ + --hash=sha256:e5e088bf43f6ee6fec7dbf1ef7ff7774a616c236b5c0cb3e00662dd71a56b571 \ + --hash=sha256:e83e3f959aaa1c9df95c22c528096d94848a1bc819f5d0ebf7ee3df0ca63db6c \ + --hash=sha256:f0dcbc588cd5b725162c076eb9119342f6579c7f7f55057bb7e3c6ff27e13121 \ + --hash=sha256:f27f9da0a7d22b9f981108fd4b62f8b5743423388915a563e651c20d06c1f457 \ + --hash=sha256:f8649a14caa5f8a243628b1d61cf530ad9ae4578814ba726816adb1121fc493e \ + --hash=sha256:fac0fa4e4f55f118fd87177dacb1c6522fe39c28d498d259014020fec9164c29 \ + --hash=sha256:fd08b90d211c086181caed76931ecfa2bdfc83eea3cfccdb0f82abc6c4b876cb # via # -r requirements.in # alembic From 1f9e99b0b4852a59de5a19475428790464accb05 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 16:09:12 +0000 Subject: [PATCH 567/582] chore(deps): update dependency build to v1.4.0 (#830) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [build](https://redirect.github.com/pypa/build) ([changelog](https://build.pypa.io/en/stable/changelog.html)) | `==1.3.0` β†’ `==1.4.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/build/1.4.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/build/1.3.0/1.4.0?slim=true) | --- ### Release Notes
pypa/build (build) ### [`v1.4.0`](https://redirect.github.com/pypa/build/blob/HEAD/CHANGELOG.rst#140-2026-01-08) [Compare Source](https://redirect.github.com/pypa/build/compare/1.3.0...1.4.0) \================== - Add `--quiet` flag (:pr:`947`) - Add option to dump PEP 517 metadata with `--metadata` (:pr:`940`, :pr:`943`) - Support `UV` environment variable (:pr:`971`) - Remove a workaround for 3.14b1 (:pr:`960`) - In 3.14 final release, `color` defaults to `True` already (:pr:`962`) - Pass sp-repo-review (:pr:`942`) - In pytest configuration, `log_level` is better than `log_cli_level` (:pr:`950`) - Split up typing and mypy (:pr:`944`) - Use `types-colorama` (:pr:`945`) - In docs, first argument for `_has_dependency` is a name (PR :pr:`970`) - Fix test failure when `flit-core` is installed (PR :pr:`921`)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 1029c3108797..154e8ae1ff65 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -8,9 +8,9 @@ alembic==1.17.0 \ --hash=sha256:4652a0b3e19616b57d652b82bfa5e38bf5dbea0813eed971612671cb9e90c0fe \ --hash=sha256:80523bc437d41b35c5db7e525ad9d908f79de65c27d6a5a5eab6df348a352d99 # via -r requirements.in -build==1.3.0 \ - --hash=sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397 \ - --hash=sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4 +build==1.4.0 \ + --hash=sha256:6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596 \ + --hash=sha256:f1b91b925aa322be454f8330c6fb48b465da993d1e7e7e6fa35027ec49f3c936 # via # -r requirements.in # pip-tools From 306372e8bb292dbb18f4e68f8e644424dc1f7a96 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 16:12:13 +0000 Subject: [PATCH 568/582] chore(deps): update dependency certifi to v2025.11.12 (#831) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [certifi](https://redirect.github.com/certifi/python-certifi) | `==2025.10.5` β†’ `==2025.11.12` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/certifi/2025.11.12?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/certifi/2025.10.5/2025.11.12?slim=true) | --- ### Release Notes
certifi/python-certifi (certifi) ### [`v2025.11.12`](https://redirect.github.com/certifi/python-certifi/compare/2025.10.05...2025.11.12) [Compare Source](https://redirect.github.com/certifi/python-certifi/compare/2025.10.05...2025.11.12)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 154e8ae1ff65..2ed753e64e67 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==6.2.6 \ --hash=sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6 \ --hash=sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda # via google-auth -certifi==2025.10.5 \ - --hash=sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de \ - --hash=sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43 +certifi==2025.11.12 \ + --hash=sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b \ + --hash=sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316 # via requests charset-normalizer==3.4.4 \ --hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \ From 6eee2f7c4b465f6eb69c7a176c34196f6af40f7c Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 4 Mar 2026 17:06:32 +0000 Subject: [PATCH 569/582] chore(deps): update dependency greenlet to v3.3.2 (#832) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [greenlet](https://redirect.github.com/python-greenlet/greenlet) ([changelog](https://greenlet.readthedocs.io/en/latest/changes.html)) | `==3.2.4` β†’ `==3.3.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/greenlet/3.3.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/greenlet/3.2.4/3.3.2?slim=true) | --- ### Release Notes
python-greenlet/greenlet (greenlet) ### [`v3.3.2`](https://redirect.github.com/python-greenlet/greenlet/blob/HEAD/CHANGES.rst#332-2026-02-20) [Compare Source](https://redirect.github.com/python-greenlet/greenlet/compare/3.3.1...3.3.2) \================== - Fix a crash on Python 3.10 if there are active greenlets during interpreter shutdown. See `PR 495 `\_ by Nicolas Bouvrette. ### [`v3.3.1`](https://redirect.github.com/python-greenlet/greenlet/blob/HEAD/CHANGES.rst#331-2026-01-23) [Compare Source](https://redirect.github.com/python-greenlet/greenlet/compare/3.3.0...3.3.1) \================== - Publish Windows ARM binary wheels, where available. - Fix compilation for 3.14t on Windows. - Publish Windows 3.14t binary wheels for Intel. - Switch from Appveyor for Windows to Github Actions. - Fix compilation on MIPS with GCC 15 and binutils 2.45. See `PR 487 by Rosen Penev `\_. Note that this is not a platform tested by this project's CI. - Move most project metadata into the static `pyproject.toml` file. This updates licensing information to use the modern `License-Expression` field. See `PR 480 by mrbean-bremen `\_. ### [`v3.3.0`](https://redirect.github.com/python-greenlet/greenlet/blob/HEAD/CHANGES.rst#330-2025-12-04) [Compare Source](https://redirect.github.com/python-greenlet/greenlet/compare/3.2.5...3.3.0) \================== - Drop support for Python 3.9. - Switch to distributing manylinux\_2\_28 wheels instead of manylinux2014 wheels. Likewise, switch from musllinux\_1\_1 to 1\_2. - Add initial support for free-threaded builds of CPython 3.14. Due to limitations, we do not distribute binary wheels for free-threaded CPython on Windows. (Free-threaded CPython 3.13 may work, but is untested and unsupported.) .. caution:: Under some rare scenarios with free-threaded 3.14, the interpreter may crash on accessing a variable or attribute or when shutting down. If this happens, try disabling the thread-local bytecode cache. See the greenlet documentation for more details. See `PR 472 by T. Wouters `\_ for the initial free-threaded support and a discussion of the current known issues. ### [`v3.2.5`](https://redirect.github.com/python-greenlet/greenlet/blob/HEAD/CHANGES.rst#325-2026-02-20) [Compare Source](https://redirect.github.com/python-greenlet/greenlet/compare/3.2.4...3.2.5) \================== .. note:: The 3.2.x series will be the last to support Python 3.9. - Backport the changes from PR 495 in release 3.3.2 for Python 3.9. .. note:: No Windows wheels will be published for this version.
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 109 +++++++++---------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 2ed753e64e67..03bfff300391 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -176,61 +176,60 @@ googleapis-common-protos[grpc]==1.71.0 \ # google-api-core # grpc-google-iam-v1 # grpcio-status -greenlet==3.2.4 \ - --hash=sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b \ - --hash=sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735 \ - --hash=sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079 \ - --hash=sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d \ - --hash=sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433 \ - --hash=sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58 \ - --hash=sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52 \ - --hash=sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31 \ - --hash=sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246 \ - --hash=sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f \ - --hash=sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671 \ - --hash=sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8 \ - --hash=sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d \ - --hash=sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f \ - --hash=sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0 \ - --hash=sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd \ - --hash=sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337 \ - --hash=sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0 \ - --hash=sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633 \ - --hash=sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b \ - --hash=sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa \ - --hash=sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31 \ - --hash=sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9 \ - --hash=sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b \ - --hash=sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4 \ - --hash=sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc \ - --hash=sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c \ - --hash=sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98 \ - --hash=sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f \ - --hash=sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c \ - --hash=sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590 \ - --hash=sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3 \ - --hash=sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2 \ - --hash=sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9 \ - --hash=sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5 \ - --hash=sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02 \ - --hash=sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0 \ - --hash=sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1 \ - --hash=sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c \ - --hash=sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594 \ - --hash=sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5 \ - --hash=sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d \ - --hash=sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a \ - --hash=sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6 \ - --hash=sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b \ - --hash=sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df \ - --hash=sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945 \ - --hash=sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae \ - --hash=sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb \ - --hash=sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504 \ - --hash=sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb \ - --hash=sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01 \ - --hash=sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c \ - --hash=sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968 +greenlet==3.3.2 \ + --hash=sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd \ + --hash=sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082 \ + --hash=sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b \ + --hash=sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5 \ + --hash=sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f \ + --hash=sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727 \ + --hash=sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e \ + --hash=sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2 \ + --hash=sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f \ + --hash=sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327 \ + --hash=sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd \ + --hash=sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2 \ + --hash=sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070 \ + --hash=sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99 \ + --hash=sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be \ + --hash=sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79 \ + --hash=sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7 \ + --hash=sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e \ + --hash=sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf \ + --hash=sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f \ + --hash=sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506 \ + --hash=sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a \ + --hash=sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395 \ + --hash=sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4 \ + --hash=sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca \ + --hash=sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492 \ + --hash=sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab \ + --hash=sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358 \ + --hash=sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce \ + --hash=sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5 \ + --hash=sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef \ + --hash=sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d \ + --hash=sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac \ + --hash=sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55 \ + --hash=sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124 \ + --hash=sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4 \ + --hash=sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986 \ + --hash=sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd \ + --hash=sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f \ + --hash=sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb \ + --hash=sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4 \ + --hash=sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13 \ + --hash=sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab \ + --hash=sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff \ + --hash=sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a \ + --hash=sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9 \ + --hash=sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86 \ + --hash=sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd \ + --hash=sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71 \ + --hash=sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92 \ + --hash=sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643 \ + --hash=sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54 \ + --hash=sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9 # via sqlalchemy grpc-google-iam-v1==0.14.3 \ --hash=sha256:7a7f697e017a067206a3dfef44e4c634a34d3dee135fe7d7a4613fe3e59217e6 \ From 630043de4179865429d810c983694d9de2d4de7b Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:12:16 +0000 Subject: [PATCH 570/582] chore(deps): update dependency proto-plus to v1.27.1 (#833) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [proto-plus](https://redirect.github.com/googleapis/proto-plus-python) | `==1.26.1` β†’ `==1.27.1` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/proto-plus/1.27.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/proto-plus/1.26.1/1.27.1?slim=true) | --- ### Release Notes
googleapis/proto-plus-python (proto-plus) ### [`v1.27.1`](https://redirect.github.com/googleapis/proto-plus-python/blob/HEAD/CHANGELOG.md#1271-2026-01-30) [Compare Source](https://redirect.github.com/googleapis/proto-plus-python/compare/v1.27.0...v1.27.1) ##### Bug Fixes - remove float\_precision for protobuf 7 ([#​559](https://redirect.github.com/googleapis/proto-plus-python/issues/559)) ([390b9d571bb5e58879137d5ac7c4cea1978e0024](https://redirect.github.com/googleapis/proto-plus-python/commit/390b9d571bb5e58879137d5ac7c4cea1978e0024)) ### [`v1.27.0`](https://redirect.github.com/googleapis/proto-plus-python/blob/HEAD/CHANGELOG.md#1270-2025-12-12) [Compare Source](https://redirect.github.com/googleapis/proto-plus-python/compare/v1.26.1...v1.27.0) ##### Features - Add classifier for Python 3.14 ([#​544](https://redirect.github.com/googleapis/proto-plus-python/issues/544)) ([d9f41512648c4551fc3e926649864c5dfe3964b2](https://redirect.github.com/googleapis/proto-plus-python/commit/d9f41512648c4551fc3e926649864c5dfe3964b2))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 03bfff300391..7fd5992e64bb 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -448,9 +448,9 @@ pip-tools==7.5.3 \ --hash=sha256:3aac0c473240ae90db7213c033401f345b05197293ccbdd2704e52e7a783785e \ --hash=sha256:8fa364779ebc010cbfe17cb9de404457ac733e100840423f28f6955de7742d41 # via -r requirements.in -proto-plus==1.26.1 \ - --hash=sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66 \ - --hash=sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012 +proto-plus==1.27.1 \ + --hash=sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147 \ + --hash=sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc # via # google-api-core # google-cloud-spanner From aa8ea85a98373c6af9ba3258ecf829c261fc3509 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:12:48 +0000 Subject: [PATCH 571/582] chore(deps): update dependency pyparsing to v3.3.2 (#834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [pyparsing](https://redirect.github.com/pyparsing/pyparsing) | `==3.2.5` β†’ `==3.3.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/pyparsing/3.3.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pyparsing/3.2.5/3.3.2?slim=true) | --- ### Release Notes
pyparsing/pyparsing (pyparsing) ### [`v3.3.2`](https://redirect.github.com/pyparsing/pyparsing/blob/HEAD/CHANGES#Version-332---January-2026) [Compare Source](https://redirect.github.com/pyparsing/pyparsing/compare/3.3.1...3.3.2) - Defined pyparsing-specific warning classes so that they can be selectively enabled or disabled without affecting warnings raised by other libraries in the same Python app: - `PyparsingWarning` - base warning for all pyparsing-specific warnings (inherits from `UserWarning`) - `PyparsingDeprecationWarning` - warning for using deprecated features (inherits from `PyparsingWarning` and `DeprecationWarning`) - `PyparsingDiagnosticWarning` - warning raised when pyparsing diagnostics are enabled and a diagnostic feature is used (inherits from `PyparsingWarning`) - Added `as_datetime` parse action to `pyparsing.common` - a more generalized version of the `convert_to_datetime` parse action (supports any expression that extracts date/time fields into "year", "month", "day", etc. results names), and validates that the parsed fields represent a valid date and time. - Added `iso8601_date_validated` and `iso8601_datetime_validated` expressions to `pyparsing.common`, which return a Python `datetime.datetime` - Various performance improvements in `ParseResults` class and core functions, with 10-20% performance overall. - Added `regex_inverter` web page (using PyScript) to demonstrate using the `inv_regex.py` example. - Expanded regex forms handled by the `examples/inv_regex.py` example: - named capturing groups (`?P`) - partial repetition (`{m,}` and `{,n}`) - negated character classes (`[^...]`) - Added `SPy` (Simplified Python) parser to examples. ### [`v3.3.1`](https://redirect.github.com/pyparsing/pyparsing/blob/HEAD/CHANGES#Version-331---December-2025) [Compare Source](https://redirect.github.com/pyparsing/pyparsing/compare/3.3.0...3.3.1) - Added license info to metadata, following PEP-639. Thanks to Gedalia Pasternak and Marc Mueller for submitted issue and PR. Fixes [#​626](https://redirect.github.com/pyparsing/pyparsing/issues/626). ### [`v3.3.0`](https://redirect.github.com/pyparsing/pyparsing/blob/HEAD/CHANGES#Version-330---December-2025) [Compare Source](https://redirect.github.com/pyparsing/pyparsing/compare/3.2.5...3.3.0) \=========================================================================================== The version 3.3.0 release will begin emitting `DeprecationWarnings` for pyparsing methods that have been renamed to PEP8-compliant names (introduced in pyparsing 3.0.0, in August, 2021, with legacy names retained as aliases). In preparation, I added in pyparsing 3.2.2 a utility for finding and replacing the legacy method names with the new names. This utility is located at `pyparsing/tools/cvt_pep8_names.py`. This script will scan all Python files specified on the command line, and if the `-u` option is selected, will replace all occurrences of the old method names with the new PEP8-compliant names, updating the files in place. Here is an example that converts all the files in the pyparsing `/examples` directory: ``` python -m pyparsing.tools.cvt_pyparsing_pep8_names -u examples/*.py ```
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 7fd5992e64bb..3f7e4cb449d4 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -482,9 +482,9 @@ pyasn1-modules==0.4.2 \ --hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \ --hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6 # via google-auth -pyparsing==3.2.5 \ - --hash=sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6 \ - --hash=sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e +pyparsing==3.3.2 \ + --hash=sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d \ + --hash=sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc # via -r requirements.in pyproject-hooks==1.2.0 \ --hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \ From 34c2a8f2e6c5b86306de3206ba5f3a0898395a55 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:13:15 +0000 Subject: [PATCH 572/582] chore(deps): update dependency protobuf to v6.33.5 [security] (#836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [protobuf](https://developers.google.com/protocol-buffers/) | `==6.33.0` β†’ `==6.33.5` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/protobuf/6.33.5?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/protobuf/6.33.0/6.33.5?slim=true) | ### GitHub Vulnerability Alerts #### [CVE-2026-0994](https://nvd.nist.gov/vuln/detail/CVE-2026-0994) A denial-of-service (DoS) vulnerability exists in google.protobuf.json_format.ParseDict() in Python, where the max_recursion_depth limit can be bypassed when parsing nested google.protobuf.Any messages. Due to missing recursion depth accounting inside the internal Any-handling logic, an attacker can supply deeply nested Any structures that bypass the intended recursion limit, eventually exhausting Python’s recursion stack and causing a RecursionError. --- ### Configuration πŸ“… **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 3f7e4cb449d4..5de452366094 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -454,17 +454,17 @@ proto-plus==1.27.1 \ # via # google-api-core # google-cloud-spanner -protobuf==6.33.0 \ - --hash=sha256:140303d5c8d2037730c548f8c7b93b20bb1dc301be280c378b82b8894589c954 \ - --hash=sha256:25c9e1963c6734448ea2d308cfa610e692b801304ba0908d7bfa564ac5132995 \ - --hash=sha256:35be49fd3f4fefa4e6e2aacc35e8b837d6703c37a2168a55ac21e9b1bc7559ef \ - --hash=sha256:905b07a65f1a4b72412314082c7dbfae91a9e8b68a0cc1577515f8df58ecf455 \ - --hash=sha256:9a031d10f703f03768f2743a1c403af050b6ae1f3480e9c140f39c45f81b13ee \ - --hash=sha256:c963e86c3655af3a917962c9619e1a6b9670540351d7af9439d06064e3317cc9 \ - --hash=sha256:cd33a8e38ea3e39df66e1bbc462b076d6e5ba3a4ebbde58219d777223a7873d3 \ - --hash=sha256:d6101ded078042a8f17959eccd9236fb7a9ca20d3b0098bbcb91533a5680d035 \ - --hash=sha256:e0697ece353e6239b90ee43a9231318302ad8353c70e6e45499fa52396debf90 \ - --hash=sha256:e0a1715e4f27355afd9570f3ea369735afc853a6c3951a6afe1f80d8569ad298 +protobuf==6.33.5 \ + --hash=sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c \ + --hash=sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02 \ + --hash=sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c \ + --hash=sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd \ + --hash=sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a \ + --hash=sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190 \ + --hash=sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c \ + --hash=sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5 \ + --hash=sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0 \ + --hash=sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b # via # google-api-core # google-cloud-spanner From e00edaf062ee68e4d0f5ca49f7f391ed10b2eb0e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:13:40 +0000 Subject: [PATCH 573/582] chore(deps): update dependency tomli to v2.4.0 (#837) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [tomli](https://redirect.github.com/hukkin/tomli) ([changelog](https://redirect.github.com/hukkin/tomli/blob/master/CHANGELOG.md)) | `==2.3.0` β†’ `==2.4.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/tomli/2.4.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/tomli/2.3.0/2.4.0?slim=true) | --- ### Release Notes
hukkin/tomli (tomli) ### [`v2.4.0`](https://redirect.github.com/hukkin/tomli/blob/HEAD/CHANGELOG.md#240) [Compare Source](https://redirect.github.com/hukkin/tomli/compare/2.3.0...2.4.0) - Added - TOML v1.1.0 compatibility - Binary wheels for Windows arm64
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 91 +++++++++++--------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 5de452366094..35e7a8468a6c 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -571,49 +571,54 @@ sqlparse==0.5.3 \ --hash=sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272 \ --hash=sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca # via google-cloud-spanner -tomli==2.3.0 \ - --hash=sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456 \ - --hash=sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845 \ - --hash=sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999 \ - --hash=sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0 \ - --hash=sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878 \ - --hash=sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf \ - --hash=sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3 \ - --hash=sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be \ - --hash=sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52 \ - --hash=sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b \ - --hash=sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67 \ - --hash=sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549 \ - --hash=sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba \ - --hash=sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22 \ - --hash=sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c \ - --hash=sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f \ - --hash=sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6 \ - --hash=sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba \ - --hash=sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45 \ - --hash=sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f \ - --hash=sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77 \ - --hash=sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606 \ - --hash=sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441 \ - --hash=sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0 \ - --hash=sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f \ - --hash=sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530 \ - --hash=sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05 \ - --hash=sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8 \ - --hash=sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005 \ - --hash=sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879 \ - --hash=sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae \ - --hash=sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc \ - --hash=sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b \ - --hash=sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b \ - --hash=sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e \ - --hash=sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf \ - --hash=sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac \ - --hash=sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8 \ - --hash=sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b \ - --hash=sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf \ - --hash=sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463 \ - --hash=sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876 +tomli==2.4.0 \ + --hash=sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729 \ + --hash=sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b \ + --hash=sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d \ + --hash=sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df \ + --hash=sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576 \ + --hash=sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d \ + --hash=sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1 \ + --hash=sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a \ + --hash=sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e \ + --hash=sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc \ + --hash=sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702 \ + --hash=sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6 \ + --hash=sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd \ + --hash=sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4 \ + --hash=sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776 \ + --hash=sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a \ + --hash=sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66 \ + --hash=sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87 \ + --hash=sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2 \ + --hash=sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f \ + --hash=sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475 \ + --hash=sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f \ + --hash=sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95 \ + --hash=sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9 \ + --hash=sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3 \ + --hash=sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9 \ + --hash=sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76 \ + --hash=sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da \ + --hash=sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8 \ + --hash=sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51 \ + --hash=sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86 \ + --hash=sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8 \ + --hash=sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0 \ + --hash=sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b \ + --hash=sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1 \ + --hash=sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e \ + --hash=sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d \ + --hash=sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c \ + --hash=sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867 \ + --hash=sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a \ + --hash=sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c \ + --hash=sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0 \ + --hash=sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4 \ + --hash=sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614 \ + --hash=sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132 \ + --hash=sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa \ + --hash=sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087 # via -r requirements.in typing-extensions==4.15.0 \ --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ From bfab2486c4601db4329158e185bb151ed9c872be Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:14:17 +0000 Subject: [PATCH 574/582] chore(deps): update actions/checkout action to v6 (#839) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/checkout](https://redirect.github.com/actions/checkout) | action | major | `v5` β†’ `v6` | --- ### Release Notes
actions/checkout (actions/checkout) ### [`v6`](https://redirect.github.com/actions/checkout/compare/v5...v6) [Compare Source](https://redirect.github.com/actions/checkout/compare/v5...v6)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- .../.github/workflows/test_suite.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml index 6059aca5f72d..e118a0bfd691 100644 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: @@ -27,7 +27,7 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: @@ -60,7 +60,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: @@ -82,7 +82,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: @@ -107,7 +107,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: @@ -133,7 +133,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: @@ -157,7 +157,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python uses: actions/setup-python@v6 with: From 448c3710169459e93bd0939d344b15423000266f Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 07:25:36 +0000 Subject: [PATCH 575/582] chore(deps): update dependency protobuf to v7 (#843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [protobuf](https://developers.google.com/protocol-buffers/) | `==6.33.5` β†’ `==7.34.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/protobuf/7.34.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/protobuf/6.33.5/7.34.0?slim=true) | --- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 35e7a8468a6c..4b9c2c27cad8 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -454,17 +454,15 @@ proto-plus==1.27.1 \ # via # google-api-core # google-cloud-spanner -protobuf==6.33.5 \ - --hash=sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c \ - --hash=sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02 \ - --hash=sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c \ - --hash=sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd \ - --hash=sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a \ - --hash=sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190 \ - --hash=sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c \ - --hash=sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5 \ - --hash=sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0 \ - --hash=sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b +protobuf==7.34.0 \ + --hash=sha256:3871a3df67c710aaf7bb8d214cc997342e63ceebd940c8c7fc65c9b3d697591a \ + --hash=sha256:4a72a8ec94e7a9f7ef7fe818ed26d073305f347f8b3b5ba31e22f81fd85fca02 \ + --hash=sha256:8e329966799f2c271d5e05e236459fe1cbfdb8755aaa3b0914fa60947ddea408 \ + --hash=sha256:964cf977e07f479c0697964e83deda72bcbc75c3badab506fb061b352d991b01 \ + --hash=sha256:9d7a5005fb96f3c1e64f397f91500b0eb371b28da81296ae73a6b08a5b76cdd6 \ + --hash=sha256:9f9079f1dde4e32342ecbd1c118d76367090d4aaa19da78230c38101c5b3dd40 \ + --hash=sha256:e3b914dd77fa33fa06ab2baa97937746ab25695f389869afdf03e81f34e45dc7 \ + --hash=sha256:f791ec509707a1d91bd02e07df157e75e4fb9fbdad12a81b7396201ec244e2e3 # via # google-api-core # google-cloud-spanner From 0c41418096c9944498b6568202f548e0cfa1e8c1 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 09:18:01 +0000 Subject: [PATCH 576/582] chore(deps): update dependency cachetools to v7 (#840) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | cachetools | `==6.2.6` β†’ `==7.0.2` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/cachetools/7.0.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/cachetools/6.2.6/7.0.2?slim=true) | --- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 4b9c2c27cad8..276de8a521c9 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -14,9 +14,9 @@ build==1.4.0 \ # via # -r requirements.in # pip-tools -cachetools==6.2.6 \ - --hash=sha256:16c33e1f276b9a9c0b49ab5782d901e3ad3de0dd6da9bf9bcd29ac5672f2f9e6 \ - --hash=sha256:8c9717235b3c651603fff0076db52d6acbfd1b338b8ed50256092f7ce9c85bda +cachetools==7.0.2 \ + --hash=sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0 \ + --hash=sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c # via google-auth certifi==2025.11.12 \ --hash=sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b \ From d99adf9ff17ad5cddd378850eb188e5b17dd6f15 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 09:18:41 +0000 Subject: [PATCH 577/582] chore(deps): update dependency certifi to v2026 (#841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [certifi](https://redirect.github.com/certifi/python-certifi) | `==2025.11.12` β†’ `==2026.2.25` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/certifi/2026.2.25?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/certifi/2025.11.12/2026.2.25?slim=true) | --- ### Release Notes
certifi/python-certifi (certifi) ### [`v2026.2.25`](https://redirect.github.com/certifi/python-certifi/compare/2026.01.04...2026.02.25) [Compare Source](https://redirect.github.com/certifi/python-certifi/compare/2026.01.04...2026.02.25) ### [`v2026.1.4`](https://redirect.github.com/certifi/python-certifi/compare/2025.11.12...2026.01.04) [Compare Source](https://redirect.github.com/certifi/python-certifi/compare/2025.11.12...2026.01.04)
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 276de8a521c9..8600ecc9319a 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -18,9 +18,9 @@ cachetools==7.0.2 \ --hash=sha256:7e7f09a4ca8b791d8bb4864afc71e9c17e607a28e6839ca1a644253c97dbeae0 \ --hash=sha256:938dcad184827c5e94928c4fd5526e2b46692b7fb1ae94472da9131d0299343c # via google-auth -certifi==2025.11.12 \ - --hash=sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b \ - --hash=sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316 +certifi==2026.2.25 \ + --hash=sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa \ + --hash=sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7 # via requests charset-normalizer==3.4.4 \ --hash=sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad \ From 055a8fe083bac9fcbc768478b8bdaee2757a00e6 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 09:19:06 +0000 Subject: [PATCH 578/582] chore(deps): update dependency packaging to v26 (#842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [packaging](https://redirect.github.com/pypa/packaging) | `==25.0` β†’ `==26.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/packaging/26.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/packaging/25.0/26.0?slim=true) | --- ### Release Notes
pypa/packaging (packaging) ### [`v26.0`](https://redirect.github.com/pypa/packaging/releases/tag/26.0) [Compare Source](https://redirect.github.com/pypa/packaging/compare/25.0...26.0) Read about the performance improvements here: . #### What's Changed Features: - PEP 751: support pylock by [@​sbidoul](https://redirect.github.com/sbidoul) in [#​900](https://redirect.github.com/pypa/packaging/pull/900) - PEP 794: import name metadata by [@​brettcannon](https://redirect.github.com/brettcannon) in [#​948](https://redirect.github.com/pypa/packaging/pull/948) - Support writing metadata by [@​henryiii](https://redirect.github.com/henryiii) in [#​846](https://redirect.github.com/pypa/packaging/pull/846) - Support `__replace__` for `Version` by [@​henryiii](https://redirect.github.com/henryiii) in [#​1003](https://redirect.github.com/pypa/packaging/pull/1003) - Support positional pattern matching for `Version` and `Specifier` by [@​henryiii](https://redirect.github.com/henryiii) in [#​1004](https://redirect.github.com/pypa/packaging/pull/1004) Behavior adaptations: - PEP 440 handling of prereleases for `Specifier.contains`, `SpecifierSet.contains`, and `SpecifierSet.filter` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​897](https://redirect.github.com/pypa/packaging/pull/897) - Handle PEP 440 edge case in `SpecifierSet.filter` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​942](https://redirect.github.com/pypa/packaging/pull/942) - Adjust arbitrary equality intersection preservation in `SpecifierSet` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​951](https://redirect.github.com/pypa/packaging/pull/951) - Return `False` instead of raising for `.contains` with invalid version by [@​Liam-DeVoe](https://redirect.github.com/Liam-DeVoe) in [#​932](https://redirect.github.com/pypa/packaging/pull/932) - Support arbitrary equality on arbitrary strings for `Specifier` and `SpecifierSet`'s `filter` and `contains` method. by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​954](https://redirect.github.com/pypa/packaging/pull/954) - Only try to parse as `Version` on certain marker keys, return `False` on unequal ordered comparsions by [@​JP-Ellis](https://redirect.github.com/JP-Ellis) in [#​939](https://redirect.github.com/pypa/packaging/pull/939) Fixes: - Update `_hash` when unpickling `Tag()` by [@​dholth](https://redirect.github.com/dholth) in [#​860](https://redirect.github.com/pypa/packaging/pull/860) - Correct comment and simplify implicit prerelease handling in `Specifier.prereleases` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​896](https://redirect.github.com/pypa/packaging/pull/896) - Use explicit `_GLibCVersion` `NamedTuple` in `_manylinux` by [@​cthoyt](https://redirect.github.com/cthoyt) in [#​868](https://redirect.github.com/pypa/packaging/pull/868) - Detect invalid license expressions containing `()` by [@​bwoodsend](https://redirect.github.com/bwoodsend) in [#​879](https://redirect.github.com/pypa/packaging/pull/879) - Correct regex for metadata `'name'` format by [@​di](https://redirect.github.com/di) in [#​925](https://redirect.github.com/pypa/packaging/pull/925) - Improve the message around expecting a semicolon by [@​pradyunsg](https://redirect.github.com/pradyunsg) in [#​833](https://redirect.github.com/pypa/packaging/pull/833) - Support nested parens in license expressions by [@​Liam-DeVoe](https://redirect.github.com/Liam-DeVoe) in [#​931](https://redirect.github.com/pypa/packaging/pull/931) - Add space before at symbol in `Requirements` string by [@​henryiii](https://redirect.github.com/henryiii) in [#​953](https://redirect.github.com/pypa/packaging/pull/953) - A root logger use found by ruff LOG, use `packaging` logger instead by [@​henryiii](https://redirect.github.com/henryiii) in [#​965](https://redirect.github.com/pypa/packaging/pull/965) - Better support for subclassing `Marker` and `Requirement` by [@​henryiii](https://redirect.github.com/henryiii) in [#​1022](https://redirect.github.com/pypa/packaging/pull/1022) - Normalize all extras, not just if it comes first by [@​henryiii](https://redirect.github.com/henryiii) in [#​1024](https://redirect.github.com/pypa/packaging/pull/1024) - Don't produce a broken repr if `Marker` fails to construct by [@​henryiii](https://redirect.github.com/henryiii) in [#​1033](https://redirect.github.com/pypa/packaging/pull/1033) Performance: - Avoid recompiling regexes in the tokenizer for a 3x speedup by [@​hauntsaninja](https://redirect.github.com/hauntsaninja) in [#​1019](https://redirect.github.com/pypa/packaging/pull/1019) - Improve performance in `_manylinux.py` by [@​cthoyt](https://redirect.github.com/cthoyt) in [#​869](https://redirect.github.com/pypa/packaging/pull/869) - Minor cleanups to `Version` by [@​bearomorphism](https://redirect.github.com/bearomorphism) in [#​913](https://redirect.github.com/pypa/packaging/pull/913) - Skip redundant creation of `Version`s in specifier comparison by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​986](https://redirect.github.com/pypa/packaging/pull/986) - Cache `Specifier`'s Version by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​985](https://redirect.github.com/pypa/packaging/pull/985) - Make `Version` a little faster by [@​henryiii](https://redirect.github.com/henryiii) in [#​987](https://redirect.github.com/pypa/packaging/pull/987) - Minor `Version` regex cleanup by [@​henryiii](https://redirect.github.com/henryiii) in [#​990](https://redirect.github.com/pypa/packaging/pull/990) - Faster regex on Python 3.11.5+ by [@​henryiii](https://redirect.github.com/henryiii) in [#​988](https://redirect.github.com/pypa/packaging/pull/988) and [#​1055](https://redirect.github.com/pypa/packaging/pull/1055) - Lazily calculate `_key` in `Version` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​989](https://redirect.github.com/pypa/packaging/pull/989) and regression for `packaging_legacy` fixed by [@​henryiii](https://redirect.github.com/henryiii) in [#​1048](https://redirect.github.com/pypa/packaging/pull/1048) - Faster `canonicalize_version` by [@​henryiii](https://redirect.github.com/henryiii) in [#​993](https://redirect.github.com/pypa/packaging/pull/993) - Use `fullmatch` in a couple more places by [@​henryiii](https://redirect.github.com/henryiii) in [#​992](https://redirect.github.com/pypa/packaging/pull/992) - Use `fullmatch` for markers too by [@​henryiii](https://redirect.github.com/henryiii) in [#​1029](https://redirect.github.com/pypa/packaging/pull/1029) - Use `map` instead of generator by [@​henryiii](https://redirect.github.com/henryiii) in [#​996](https://redirect.github.com/pypa/packaging/pull/996) - Deprecate `._version` (`_Version`, a `NamedTuple`) by [@​henryiii](https://redirect.github.com/henryiii) in [#​995](https://redirect.github.com/pypa/packaging/pull/995) and [#​1062](https://redirect.github.com/pypa/packaging/pull/1062) - Avoid duplicate `Version` creation in `canonicalize_version` by [@​henryiii](https://redirect.github.com/henryiii) in [#​994](https://redirect.github.com/pypa/packaging/pull/994) - Add `__slots__` to `Version` by [@​henryiii](https://redirect.github.com/henryiii) in [#​1001](https://redirect.github.com/pypa/packaging/pull/1001) - Add `__slots__` to `Specifier`s by [@​henryiii](https://redirect.github.com/henryiii) in [#​1002](https://redirect.github.com/pypa/packaging/pull/1002) - Add `__slots__` to `Node`s by [@​henryiii](https://redirect.github.com/henryiii) in [#​1032](https://redirect.github.com/pypa/packaging/pull/1032) - Use `version.__replace__` in specifier comparison by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​999](https://redirect.github.com/pypa/packaging/pull/999) - Use `_get_spec_version` in more places in `Specifier` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​1005](https://redirect.github.com/pypa/packaging/pull/1005) - Pull `set` construction out of function by [@​henryiii](https://redirect.github.com/henryiii) in [#​1012](https://redirect.github.com/pypa/packaging/pull/1012) - Letter normalization dict for prereleases and the like by [@​henryiii](https://redirect.github.com/henryiii) in [#​1014](https://redirect.github.com/pypa/packaging/pull/1014) - Avoid normalizing extras again when comparing by [@​henryiii](https://redirect.github.com/henryiii) in [#​1028](https://redirect.github.com/pypa/packaging/pull/1028) - Speed up `Version.__str__` by about 10% by [@​henryiii](https://redirect.github.com/henryiii) in [#​997](https://redirect.github.com/pypa/packaging/pull/997) - Increase the performance of `canonicalize_name` by avoiding a regex by [@​henryiii](https://redirect.github.com/henryiii) in [#​1030](https://redirect.github.com/pypa/packaging/pull/1030), [#​1047](https://redirect.github.com/pypa/packaging/pull/1047), and [#​1064](https://redirect.github.com/pypa/packaging/pull/1064) - Faster zero stripping by [@​henryiii](https://redirect.github.com/henryiii) in [#​1058](https://redirect.github.com/pypa/packaging/pull/1058) Type annotations: - Fix a type annotation by [@​brettcannon](https://redirect.github.com/brettcannon) in [#​907](https://redirect.github.com/pypa/packaging/pull/907) - Fix tags return type in `parse_wheel_filename` docs by [@​ncoghlan](https://redirect.github.com/ncoghlan) in [#​973](https://redirect.github.com/pypa/packaging/pull/973) - Add type hint for `_version` in `.version.Version` by [@​brettcannon](https://redirect.github.com/brettcannon) in [#​927](https://redirect.github.com/pypa/packaging/pull/927) - Changed static type annotations in prereleases setter method in `specifier.py` by [@​subhajitsaha01](https://redirect.github.com/subhajitsaha01) in [#​930](https://redirect.github.com/pypa/packaging/pull/930) - Statically type the tests by [@​henryiii](https://redirect.github.com/henryiii) in [#​982](https://redirect.github.com/pypa/packaging/pull/982) Internal: - Test and declare support Python 3.14 by [@​henryiii](https://redirect.github.com/henryiii) in [#​901](https://redirect.github.com/pypa/packaging/pull/901) - Modernize and speed up tests on Python 3.14 by [@​henryiii](https://redirect.github.com/henryiii) in [#​903](https://redirect.github.com/pypa/packaging/pull/903) - Change our license metadata to use an SPDX license expression by [@​cdce8p](https://redirect.github.com/cdce8p) in [#​881](https://redirect.github.com/pypa/packaging/pull/881) - No need for `license-files` by [@​DimitriPapadopoulos](https://redirect.github.com/DimitriPapadopoulos) in [#​924](https://redirect.github.com/pypa/packaging/pull/924) - Update mypy by [@​hauntsaninja](https://redirect.github.com/hauntsaninja) in [#​891](https://redirect.github.com/pypa/packaging/pull/891) - Some config updates by [@​henryiii](https://redirect.github.com/henryiii) in [#​902](https://redirect.github.com/pypa/packaging/pull/902) - Add spell check and rst check by [@​henryiii](https://redirect.github.com/henryiii) in [#​904](https://redirect.github.com/pypa/packaging/pull/904) - Clean up ruff ignores by [@​henryiii](https://redirect.github.com/henryiii) in [#​905](https://redirect.github.com/pypa/packaging/pull/905) - Update example for env marker `python_version` by [@​trim21](https://redirect.github.com/trim21) in [#​908](https://redirect.github.com/pypa/packaging/pull/908) - Move codespell configuration into pyproject.toml by [@​yarikoptic](https://redirect.github.com/yarikoptic) in [#​910](https://redirect.github.com/pypa/packaging/pull/910) - Check warning a little more precisely by [@​henryiii](https://redirect.github.com/henryiii) in [#​837](https://redirect.github.com/pypa/packaging/pull/837) - Speed up mypy a little by [@​henryiii](https://redirect.github.com/henryiii) in [#​836](https://redirect.github.com/pypa/packaging/pull/836) - Apply ruff/flake8-pyi rules (PYI) by [@​DimitriPapadopoulos](https://redirect.github.com/DimitriPapadopoulos) in [#​835](https://redirect.github.com/pypa/packaging/pull/835) - Better local runs for codespell by [@​henryiii](https://redirect.github.com/henryiii) in [#​911](https://redirect.github.com/pypa/packaging/pull/911) - Remove outdated/confusing Gist link by [@​stefan6419846](https://redirect.github.com/stefan6419846) in [#​921](https://redirect.github.com/pypa/packaging/pull/921) - Fix docs and docs ci after [#​897](https://redirect.github.com/pypa/packaging/issues/897) landed by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​926](https://redirect.github.com/pypa/packaging/pull/926) - Run twine-check on push in CI by [@​EpicWink](https://redirect.github.com/EpicWink) in [#​922](https://redirect.github.com/pypa/packaging/pull/922) - `ruff` was renamed `ruff-check` in pre-commit by [@​henryiii](https://redirect.github.com/henryiii) in [#​933](https://redirect.github.com/pypa/packaging/pull/933) - Fix incorrectly implicitly concatenated string in specifiers test by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​946](https://redirect.github.com/pypa/packaging/pull/946) - Simplify conditional by [@​ofek](https://redirect.github.com/ofek) in [#​949](https://redirect.github.com/pypa/packaging/pull/949) - Modernize nox, use dependency-groups for tests by [@​henryiii](https://redirect.github.com/henryiii) in [#​952](https://redirect.github.com/pypa/packaging/pull/952) - Add more checks that don't affect anything by [@​henryiii](https://redirect.github.com/henryiii) in [#​957](https://redirect.github.com/pypa/packaging/pull/957) - Enable Ruff ISC rule by [@​henryiii](https://redirect.github.com/henryiii) in [#​959](https://redirect.github.com/pypa/packaging/pull/959) - Ruff code FLY by [@​henryiii](https://redirect.github.com/henryiii) in [#​963](https://redirect.github.com/pypa/packaging/pull/963) - pytest `log_level` is better than `log_cli_level` by [@​henryiii](https://redirect.github.com/henryiii) in [#​956](https://redirect.github.com/pypa/packaging/pull/956) - Ruff code TRY by [@​henryiii](https://redirect.github.com/henryiii) in [#​961](https://redirect.github.com/pypa/packaging/pull/961) - Add the ruff PL checks by [@​henryiii](https://redirect.github.com/henryiii) in [#​964](https://redirect.github.com/pypa/packaging/pull/964) - Enable Ruff ARG rules by [@​henryiii](https://redirect.github.com/henryiii) in [#​958](https://redirect.github.com/pypa/packaging/pull/958) - Ruff PT code (pytest) by [@​henryiii](https://redirect.github.com/henryiii) in [#​960](https://redirect.github.com/pypa/packaging/pull/960) - Add ruff DTZ by [@​henryiii](https://redirect.github.com/henryiii) in [#​968](https://redirect.github.com/pypa/packaging/pull/968) - Add ruff BLE by [@​henryiii](https://redirect.github.com/henryiii) in [#​967](https://redirect.github.com/pypa/packaging/pull/967) - Add the ruff SIM checks by [@​henryiii](https://redirect.github.com/henryiii) in [#​966](https://redirect.github.com/pypa/packaging/pull/966) - Adding ruff PERF by [@​henryiii](https://redirect.github.com/henryiii) in [#​969](https://redirect.github.com/pypa/packaging/pull/969) - Move some config into coverage config by [@​henryiii](https://redirect.github.com/henryiii) in [#​971](https://redirect.github.com/pypa/packaging/pull/971) - Check ruff C4 by [@​henryiii](https://redirect.github.com/henryiii) in [#​962](https://redirect.github.com/pypa/packaging/pull/962) - Adding ruff T20 by [@​henryiii](https://redirect.github.com/henryiii) in [#​972](https://redirect.github.com/pypa/packaging/pull/972) - Add a tests pass job by [@​henryiii](https://redirect.github.com/henryiii) in [#​977](https://redirect.github.com/pypa/packaging/pull/977) - Add ruff TC by [@​henryiii](https://redirect.github.com/henryiii) in [#​980](https://redirect.github.com/pypa/packaging/pull/980) - Adding part of ruff RET by [@​henryiii](https://redirect.github.com/henryiii) in [#​979](https://redirect.github.com/pypa/packaging/pull/979) - Reorder mypy check by [@​henryiii](https://redirect.github.com/henryiii) in [#​983](https://redirect.github.com/pypa/packaging/pull/983) - Enable ruff ALL by [@​henryiii](https://redirect.github.com/henryiii) in [#​984](https://redirect.github.com/pypa/packaging/pull/984) - Link back to repo/source in furo by [@​henryiii](https://redirect.github.com/henryiii) in [#​991](https://redirect.github.com/pypa/packaging/pull/991) - Add case insensitivity tests for arbitrary equality by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​975](https://redirect.github.com/pypa/packaging/pull/975) - Synchronize documentation and code for markers by [@​zahlman](https://redirect.github.com/zahlman) in [#​1008](https://redirect.github.com/pypa/packaging/pull/1008) - Use `partition` in `_parse_project_urls` by [@​henryiii](https://redirect.github.com/henryiii) in [#​1013](https://redirect.github.com/pypa/packaging/pull/1013) - auto-skip the dependabot PRs in the release changelog generation by [@​henryiii](https://redirect.github.com/henryiii) in [#​1016](https://redirect.github.com/pypa/packaging/pull/1016) - Update unreleased section in changelog by [@​henryiii](https://redirect.github.com/henryiii) in [#​1017](https://redirect.github.com/pypa/packaging/pull/1017) - Fix PR role to match extlinks by [@​hugovk](https://redirect.github.com/hugovk) in [#​1020](https://redirect.github.com/pypa/packaging/pull/1020) - Mention new parts in README by [@​henryiii](https://redirect.github.com/henryiii) in [#​1023](https://redirect.github.com/pypa/packaging/pull/1023) - Replace a couple of asserts with else by [@​henryiii](https://redirect.github.com/henryiii) in [#​1027](https://redirect.github.com/pypa/packaging/pull/1027) - Simplify and/or check a little more by [@​henryiii](https://redirect.github.com/henryiii) in [#​1031](https://redirect.github.com/pypa/packaging/pull/1031) - Use slim runner for all check by [@​henryiii](https://redirect.github.com/henryiii) in [#​1021](https://redirect.github.com/pypa/packaging/pull/1021) - Use typos instead of codespell by [@​henryiii](https://redirect.github.com/henryiii) in [#​1015](https://redirect.github.com/pypa/packaging/pull/1015) - Update changelog with recent additions by [@​henryiii](https://redirect.github.com/henryiii) in [#​1034](https://redirect.github.com/pypa/packaging/pull/1034) - Publish to PyPI via GitHub CI by [@​EpicWink](https://redirect.github.com/EpicWink) in [#​893](https://redirect.github.com/pypa/packaging/pull/893) - Use prek for faster pre-commit lint step by [@​henryiii](https://redirect.github.com/henryiii) in [#​1037](https://redirect.github.com/pypa/packaging/pull/1037) - Add help text to noxfile by [@​henryiii](https://redirect.github.com/henryiii) in [#​1038](https://redirect.github.com/pypa/packaging/pull/1038) - Update licenses to 3.27 by [@​henryiii](https://redirect.github.com/henryiii) in [#​1036](https://redirect.github.com/pypa/packaging/pull/1036) - Use relative import in `packaging.licenses` by [@​notatallshaw](https://redirect.github.com/notatallshaw) in [#​1039](https://redirect.github.com/pypa/packaging/pull/1039) - Add zizmor and tighten up CI by [@​henryiii](https://redirect.github.com/henryiii) in [#​1035](https://redirect.github.com/pypa/packaging/pull/1035) - Fix release script by [@​henryiii](https://redirect.github.com/henryiii) in [#​1040](https://redirect.github.com/pypa/packaging/pull/1040) - Fix using a dev version (again) by [@​henryiii](https://redirect.github.com/henryiii) in [#​1041](https://redirect.github.com/pypa/packaging/pull/1041) - Fix type hint of function used with `contextlib.contextmanager` by [@​SpecLad](https://redirect.github.com/SpecLad) in [#​1046](https://redirect.github.com/pypa/packaging/pull/1046) - Always run tests by [@​henryiii](https://redirect.github.com/henryiii) in [#​1044](https://redirect.github.com/pypa/packaging/pull/1044) - Fix a changelog number by [@​henryiii](https://redirect.github.com/henryiii) in [#​1042](https://redirect.github.com/pypa/packaging/pull/1042) - Fix the publish job by [@​henryiii](https://redirect.github.com/henryiii) in [#​1043](https://redirect.github.com/pypa/packaging/pull/1043) - Get the correct tag on publish by [@​henryiii](https://redirect.github.com/henryiii) in [#​1045](https://redirect.github.com/pypa/packaging/pull/1045) - Test on first public release of CPython 3.11 and newer by [@​henryiii](https://redirect.github.com/henryiii) in [#​1056](https://redirect.github.com/pypa/packaging/pull/1056) - Fix publication job (again) by [@​henryiii](https://redirect.github.com/henryiii) in [#​1051](https://redirect.github.com/pypa/packaging/pull/1051) - Use `actionlint` to check CI workflows by [@​miketheman](https://redirect.github.com/miketheman) in [#​1052](https://redirect.github.com/pypa/packaging/pull/1052) - Fix formatting of distribution types in metadata.rst by [@​brettcannon](https://redirect.github.com/brettcannon) in [#​1053](https://redirect.github.com/pypa/packaging/pull/1053) #### New Contributors - [@​cdce8p](https://redirect.github.com/cdce8p) made their first contribution in [#​881](https://redirect.github.com/pypa/packaging/pull/881) - [@​dholth](https://redirect.github.com/dholth) made their first contribution in [#​860](https://redirect.github.com/pypa/packaging/pull/860) - [@​trim21](https://redirect.github.com/trim21) made their first contribution in [#​908](https://redirect.github.com/pypa/packaging/pull/908) - [@​yarikoptic](https://redirect.github.com/yarikoptic) made their first contribution in [#​910](https://redirect.github.com/pypa/packaging/pull/910) - [@​cthoyt](https://redirect.github.com/cthoyt) made their first contribution in [#​868](https://redirect.github.com/pypa/packaging/pull/868) - [@​bwoodsend](https://redirect.github.com/bwoodsend) made their first contribution in [#​879](https://redirect.github.com/pypa/packaging/pull/879) - [@​stefan6419846](https://redirect.github.com/stefan6419846) made their first contribution in [#​921](https://redirect.github.com/pypa/packaging/pull/921) - [@​bearomorphism](https://redirect.github.com/bearomorphism) made their first contribution in [#​913](https://redirect.github.com/pypa/packaging/pull/913) - [@​EpicWink](https://redirect.github.com/EpicWink) made their first contribution in [#​922](https://redirect.github.com/pypa/packaging/pull/922) - [@​Liam-DeVoe](https://redirect.github.com/Liam-DeVoe) made their first contribution in [#​932](https://redirect.github.com/pypa/packaging/pull/932) - [@​subhajitsaha01](https://redirect.github.com/subhajitsaha01) made their first contribution in [#​930](https://redirect.github.com/pypa/packaging/pull/930) - [@​ncoghlan](https://redirect.github.com/ncoghlan) made their first contribution in [#​973](https://redirect.github.com/pypa/packaging/pull/973) - [@​zahlman](https://redirect.github.com/zahlman) made their first contribution in [#​1008](https://redirect.github.com/pypa/packaging/pull/1008) - [@​JP-Ellis](https://redirect.github.com/JP-Ellis) made their first contribution in [#​939](https://redirect.github.com/pypa/packaging/pull/939) #### Since last RC Fixes: - Restore `._version` as a compat shim by [@​henryiii](https://redirect.github.com/henryiii) in [#​1062](https://redirect.github.com/pypa/packaging/pull/1062) Performance: - Dual replace by [@​henryiii](https://redirect.github.com/henryiii) in [#​1064](https://redirect.github.com/pypa/packaging/pull/1064) Documentaiton: - Prepare for 26.0 final by [@​henryiii](https://redirect.github.com/henryiii) in [#​1063](https://redirect.github.com/pypa/packaging/pull/1063) **Full Changelog**:
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --- packages/sqlalchemy-spanner/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 8600ecc9319a..95004f940f29 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -434,9 +434,9 @@ opentelemetry-semantic-conventions==0.55b1 \ --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ --hash=sha256:ef95b1f009159c28d7a7849f5cbc71c4c34c845bb514d66adfdf1b3fff3598b3 # via opentelemetry-sdk -packaging==25.0 \ - --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ - --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f +packaging==26.0 \ + --hash=sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4 \ + --hash=sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529 # via # -r requirements.in # build From 7365312d72dc41332bd87b16d0df09dee57f9716 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Thu, 5 Mar 2026 09:25:18 +0000 Subject: [PATCH 579/582] chore(deps): update opentelemetry-python monorepo to v1.40.0 (#838) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [opentelemetry-api](https://redirect.github.com/open-telemetry/opentelemetry-python) | `==1.38.0` β†’ `==1.40.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/opentelemetry-api/1.40.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/opentelemetry-api/1.38.0/1.40.0?slim=true) | | [opentelemetry-sdk](https://redirect.github.com/open-telemetry/opentelemetry-python) | `==1.38.0` β†’ `==1.40.0` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/opentelemetry-sdk/1.40.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/opentelemetry-sdk/1.38.0/1.40.0?slim=true) | --- ### Release Notes
open-telemetry/opentelemetry-python (opentelemetry-api) ### [`v1.40.0`](https://redirect.github.com/open-telemetry/opentelemetry-python/blob/HEAD/CHANGELOG.md#Version-1400061b0-2026-03-04) [Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-python/compare/v1.39.1...v1.40.0) - `opentelemetry-sdk`: deprecate `LoggingHandler` in favor of `opentelemetry-instrumentation-logging`, see `opentelemetry-instrumentation-logging` documentation ([#​4919](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4919)) - `opentelemetry-sdk`: Clarify log processor error handling expectations in documentation ([#​4915](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4915)) - bump semantic-conventions to v1.40.0 ([#​4941](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4941)) - Add stale PR GitHub Action ([#​4926](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4926)) - `opentelemetry-sdk`: Drop unused Jaeger exporter environment variables (exporter removed in 1.22.0) ([#​4918](https://redirect.github.com/open-telemetry/opentelemetry-python/issues/4918)) - `opentelemetry-sdk`: Clarify timeout units in environment variable documentation ([#​4906](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4906)) - `opentelemetry-exporter-otlp-proto-grpc`: Fix re-initialization of gRPC channel on UNAVAILABLE error ([#​4825](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4825)) - `opentelemetry-exporter-prometheus`: Fix duplicate HELP/TYPE declarations for metrics with different label sets ([#​4868](https://redirect.github.com/open-telemetry/opentelemetry-python/issues/4868)) - Allow loading all resource detectors by setting `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` to `*` ([#​4819](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4819)) - `opentelemetry-sdk`: Fix the type hint of the `_metrics_data` property to allow `None` ([#​4837](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4837)). - Regenerate opentelemetry-proto code with v1.9.0 release ([#​4840](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4840)) - Add python 3.14 support ([#​4798](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4798)) - Silence events API warnings for internal users ([#​4847](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4847)) - opentelemetry-sdk: make it possible to override the default processors in the SDK configurator ([#​4806](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4806)) - Prevent possible endless recursion from happening in `SimpleLogRecordProcessor.on_emit`, ([#​4799](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4799)) and ([#​4867](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4867)). - Implement span start/end metrics ([#​4880](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4880)) - Add environment variable carriers to API ([#​4609](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4609)) - Add experimental composable rule based sampler ([#​4882](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4882)) - Make ConcurrentMultiSpanProcessor fork safe ([#​4862](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4862)) - `opentelemetry-exporter-otlp-proto-http`: fix retry logic and error handling for connection failures in trace, metric, and log exporters ([#​4709](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4709)) - `opentelemetry-sdk`: avoid RuntimeError during iteration of view instrument match dictionary in MetricReaderStorage.collect() ([#​4891](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4891)) - Implement experimental TracerConfigurator ([#​4861](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4861)) - `opentelemetry-sdk`: Fix instrument creation race condition ([#​4913](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4913)) - bump semantic-conventions to v1.39.0 ([#​4914](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4914)) - `opentelemetry-sdk`: automatically generate configuration models using OTel config JSON schema ([#​4879](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4879)) ### [`v1.39.1`](https://redirect.github.com/open-telemetry/opentelemetry-python/releases/tag/v1.39.1): Version 1.39.1/0.60b1 [Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-python/compare/v1.39.0...v1.39.1) This is a patch release on the previous 1.39.0/0.60b0 release, fixing the issue(s) below. - Silence events API warnings for internal users ([#​4847](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4847)) ### [`v1.39.0`](https://redirect.github.com/open-telemetry/opentelemetry-python/blob/HEAD/CHANGELOG.md#Version-1390060b0-2025-12-03) [Compare Source](https://redirect.github.com/open-telemetry/opentelemetry-python/compare/v1.38.0...v1.39.0) - `opentelemetry-api`: Convert objects of any type other than AnyValue in attributes to string to be exportable ([#​4808](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4808)) - docs: Added sqlcommenter example ([#​4734](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4734)) - build: bump ruff to 0.14.1 ([#​4782](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4782)) - Add `opentelemetry-exporter-credential-provider-gcp` as an optional dependency to `opentelemetry-exporter-otlp-proto-grpc` and `opentelemetry-exporter-otlp-proto-http` ([#​4760](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4760)) - feat: implement on ending in span processor ([#​4775](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4775)) - semantic-conventions: Bump to 1.38.0 ([#​4791](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4791)) - \[BREAKING] Remove LogData and extend SDK LogRecord to have instrumentation scope ([#​4676](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4676)) - \[BREAKING] Rename several classes from Log to LogRecord ([#​4647](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4647)) **Migration Guide:** `LogData` has been removed. Users should update their code as follows: - **For Log Exporters:** Change from `Sequence[LogData]` to `Sequence[ReadableLogRecord]` ```python # Before from opentelemetry.sdk._logs import LogData def export(self, batch: Sequence[LogData]) -> LogRecordExportResult: ... # After from opentelemetry.sdk._logs import ReadableLogRecord def export(self, batch: Sequence[ReadableLogRecord]) -> LogRecordExportResult: ... ``` - **For Log Processors:** Use `ReadWriteLogRecord` for processing, `ReadableLogRecord` for exporting ```python # Before from opentelemetry.sdk._logs import LogData def on_emit(self, log_data: LogData): ... # After from opentelemetry.sdk._logs import ReadWriteLogRecord, ReadableLogRecord def on_emit(self, log_record: ReadWriteLogRecord): # Convert to ReadableLogRecord before exporting readable = ReadableLogRecord( log_record=log_record.log_record, resource=log_record.resource or Resource.create({}), instrumentation_scope=log_record.instrumentation_scope, limits=log_record.limits, ) ... ``` - **Accessing log data:** Use the same attributes on `ReadableLogRecord`/`ReadWriteLogRecord` - `log_record.log_record` - The API LogRecord (contains body, severity, attributes, etc.) - `log_record.resource` - The Resource - `log_record.instrumentation_scope` - The InstrumentationScope (now included, was in LogData before) - `log_record.limits` - The LogRecordLimits - Mark the Events API/SDK as deprecated. The Logs API/SDK should be used instead, an event is now a `LogRecord` with the `event_name` field set ([#​4654](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4654)). - Fix type checking for built-in metric exporters ([#​4820](https://redirect.github.com/open-telemetry/opentelemetry-python/pull/4820))
--- ### Configuration πŸ“… **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. πŸ”• **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/python-spanner-sqlalchemy). --------- Co-authored-by: Knut Olav LΓΈite --- packages/sqlalchemy-spanner/noxfile.py | 12 ++++++------ packages/sqlalchemy-spanner/requirements.txt | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/sqlalchemy-spanner/noxfile.py b/packages/sqlalchemy-spanner/noxfile.py index 77d127be013a..b7045dee568f 100644 --- a/packages/sqlalchemy-spanner/noxfile.py +++ b/packages/sqlalchemy-spanner/noxfile.py @@ -234,9 +234,9 @@ def system(session): session.install("mock") session.install(".[tracing]") - session.install("opentelemetry-api==1.27.0") - session.install("opentelemetry-sdk==1.27.0") - session.install("opentelemetry-instrumentation==0.48b0") + session.install("opentelemetry-api") + session.install("opentelemetry-sdk") + session.install("opentelemetry-instrumentation") session.run("python", "create_test_database.py") session.install("sqlalchemy>=2.0") @@ -254,9 +254,9 @@ def unit(session): session.install("pytest") session.install("mock") session.install(".") - session.install("opentelemetry-api==1.27.0") - session.install("opentelemetry-sdk==1.27.0") - session.install("opentelemetry-instrumentation==0.48b0") + session.install("opentelemetry-api") + session.install("opentelemetry-sdk") + session.install("opentelemetry-instrumentation") session.run( "python", "create_test_config.py", "my-project", "my-instance", "my-database" ) diff --git a/packages/sqlalchemy-spanner/requirements.txt b/packages/sqlalchemy-spanner/requirements.txt index 95004f940f29..1378b63a8fd7 100644 --- a/packages/sqlalchemy-spanner/requirements.txt +++ b/packages/sqlalchemy-spanner/requirements.txt @@ -414,9 +414,9 @@ MarkupSafe==3.0.3 \ --hash=sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a \ --hash=sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50 # via mako -opentelemetry-api==1.38.0 \ - --hash=sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582 \ - --hash=sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12 +opentelemetry-api==1.40.0 \ + --hash=sha256:159be641c0b04d11e9ecd576906462773eb97ae1b657730f0ecf64d32071569f \ + --hash=sha256:82dd69331ae74b06f6a874704be0cfaa49a1650e1537d4a813b86ecef7d0ecf9 # via # -r requirements.in # opentelemetry-instrumentation @@ -426,9 +426,9 @@ opentelemetry-instrumentation==0.48b0 \ --hash=sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35 \ --hash=sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44 # via -r requirements.in -opentelemetry-sdk==1.38.0 \ - --hash=sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b \ - --hash=sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe +opentelemetry-sdk==1.40.0 \ + --hash=sha256:18e9f5ec20d859d268c7cb3c5198c8d105d073714db3de50b593b8c1345a48f2 \ + --hash=sha256:787d2154a71f4b3d81f20524a8ce061b7db667d24e46753f32a7bc48f1c1f3f1 # via -r requirements.in opentelemetry-semantic-conventions==0.55b1 \ --hash=sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed \ From 588ff02fd51b8d6b624a80b1bd20dca509acc222 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Mon, 9 Mar 2026 15:04:22 -0400 Subject: [PATCH 580/582] chore: add repo-metadata.json (#849) --- packages/sqlalchemy-spanner/.repo-metadata.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/sqlalchemy-spanner/.repo-metadata.json diff --git a/packages/sqlalchemy-spanner/.repo-metadata.json b/packages/sqlalchemy-spanner/.repo-metadata.json new file mode 100644 index 000000000000..b9fa24ab88d4 --- /dev/null +++ b/packages/sqlalchemy-spanner/.repo-metadata.json @@ -0,0 +1,14 @@ +{ + "name": "sqlalchemy-spanner", + "name_pretty": "Spanner dialect for SQLAlchemy", + "product_documentation": "https://cloud.google.com/spanner/docs", + "client_documentation": "https://github.com/googleapis/python-spanner-sqlalchemy", + "issue_tracker": "https://issuetracker.google.com/issues?q=componentid:190851%2B%20status:open", + "release_level": "stable", + "language": "python", + "library_type": "INTEGRATION", + "repo": "googleapis/python-spanner-sqlalchemy", + "distribution_name": "sqlalchemy-spanner", + "requires_billing": true, + "api_shortname": "sqlalchemy-spanner" +} From bf047e7ca20ae2075cc55a063d41a833221e1bed Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Mon, 9 Mar 2026 19:13:56 +0000 Subject: [PATCH 581/582] Trigger owlbot post-processor --- .../sqlalchemy-spanner/sqlalchemy-spanner/sqlalchemy-spanner.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 owl-bot-staging/sqlalchemy-spanner/sqlalchemy-spanner/sqlalchemy-spanner.txt diff --git a/owl-bot-staging/sqlalchemy-spanner/sqlalchemy-spanner/sqlalchemy-spanner.txt b/owl-bot-staging/sqlalchemy-spanner/sqlalchemy-spanner/sqlalchemy-spanner.txt new file mode 100644 index 000000000000..e69de29bb2d1 From 90f67ece4710775f12a3239be61aacf8061ed43a Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Mon, 9 Mar 2026 19:14:05 +0000 Subject: [PATCH 582/582] build: sqlalchemy-spanner migration: adjust owlbot-related files --- .../sqlalchemy-spanner/.github/CODEOWNERS | 8 - .../.github/ISSUE_TEMPLATE.md | 16 - .../.github/PULL_REQUEST_TEMPLATE.md | 6 - .../.github/blunderbuss.yml | 2 - .../.github/workflows/test_suite.yml | 171 ------- packages/sqlalchemy-spanner/.kokoro/build.sh | 43 -- .../.kokoro/continuous/common.cfg | 27 - .../.kokoro/continuous/continuous.cfg | 1 - .../.kokoro/populate-secrets.sh | 35 -- .../.kokoro/presubmit/common.cfg | 27 - .../.kokoro/presubmit/compliance.cfg | 7 - .../.kokoro/presubmit/presubmit.cfg | 1 - .../sqlalchemy-spanner/.kokoro/trampoline.sh | 20 - .../.kokoro/trampoline_v2.sh | 479 ------------------ .../single-library.git-migrate-history.sh | 6 +- 15 files changed, 3 insertions(+), 846 deletions(-) delete mode 100644 packages/sqlalchemy-spanner/.github/CODEOWNERS delete mode 100644 packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md delete mode 100644 packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 packages/sqlalchemy-spanner/.github/blunderbuss.yml delete mode 100644 packages/sqlalchemy-spanner/.github/workflows/test_suite.yml delete mode 100755 packages/sqlalchemy-spanner/.kokoro/build.sh delete mode 100644 packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg delete mode 100755 packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh delete mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg delete mode 100644 packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg delete mode 100755 packages/sqlalchemy-spanner/.kokoro/trampoline.sh delete mode 100755 packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh diff --git a/packages/sqlalchemy-spanner/.github/CODEOWNERS b/packages/sqlalchemy-spanner/.github/CODEOWNERS deleted file mode 100644 index 24e3ccd88d41..000000000000 --- a/packages/sqlalchemy-spanner/.github/CODEOWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# Code owners file. -# This file controls who is tagged for review for any given pull request. -# -# For syntax help see: -# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax - -# The @googleapis/spanner-team is the default owner for changes in this repo -* @googleapis/spanner-team diff --git a/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md b/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 3c52212facc1..000000000000 --- a/packages/sqlalchemy-spanner/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,16 +0,0 @@ -## Expected Behavior - - -## Actual Behavior - - -## Steps to Reproduce the Problem - -1. -1. -1. - -## Specifications - -- Version: -- Platform: \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md b/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 0787bd9431fa..000000000000 --- a/packages/sqlalchemy-spanner/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,6 +0,0 @@ -Fixes # - -> It's a good idea to open an issue first for discussion. - -- [ ] Tests pass -- [ ] Appropriate changes to README are included in PR \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.github/blunderbuss.yml b/packages/sqlalchemy-spanner/.github/blunderbuss.yml deleted file mode 100644 index 479642220940..000000000000 --- a/packages/sqlalchemy-spanner/.github/blunderbuss.yml +++ /dev/null @@ -1,2 +0,0 @@ -assign_issues: - - olavloite diff --git a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml b/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml deleted file mode 100644 index e118a0bfd691..000000000000 --- a/packages/sqlalchemy-spanner/.github/workflows/test_suite.yml +++ /dev/null @@ -1,171 +0,0 @@ -on: - push: - branches: - - main - pull_request: -name: SQLAlchemy Spanner dialect -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.14 - - name: Install nox - run: python -m pip install nox - - name: Run Lint - run: nox -s lint_setup_py lint blacken - - unit: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - - name: Install nox - run: python -m pip install nox - - name: Run Unit Tests - run: nox -s unit-${{ matrix.python-version }} - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - - mockserver: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.14 - - name: Install nox - run: python -m pip install nox - - name: Run mockserver tests - run: nox -s mockserver - - samples: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.14 - - name: Install nox - run: python -m pip install nox - - name: Run samples - run: nox -s _all_samples - working-directory: samples - - compliance_tests_14: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.9 - - name: Install nox - run: python -m pip install nox - - name: Run Compliance Tests - run: nox -s compliance_test_14 - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - SQLALCHEMY_SILENCE_UBER_WARNING: 1 - - compliance_tests_20: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.14 - - name: Install nox - run: python -m pip install nox - - name: Run Compliance Tests - run: nox -s compliance_test_20 - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - - system: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.14"] - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - - name: Install nox - run: python -m pip install nox - - name: Run System Tests - run: nox -s system-${{ matrix.python-version }} - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging - - migration_tests: - runs-on: ubuntu-latest - - services: - emulator-0: - image: gcr.io/cloud-spanner-emulator/emulator:latest - ports: - - 9010:9010 - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: 3.9 - - name: Install nox - run: python -m pip install nox - - name: Run Migration Tests - run: nox -s migration_test - env: - SPANNER_EMULATOR_HOST: localhost:9010 - GOOGLE_CLOUD_PROJECT: appdev-soda-spanner-staging \ No newline at end of file diff --git a/packages/sqlalchemy-spanner/.kokoro/build.sh b/packages/sqlalchemy-spanner/.kokoro/build.sh deleted file mode 100755 index 072d854fde5d..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/build.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -set -eo pipefail - -if [[ -z "${PROJECT_ROOT:-}" ]]; then - PROJECT_ROOT="github/python-spanner-sqlalchemy" -fi - -cd "${PROJECT_ROOT}" - -# Disable buffering, so that the logs stream through. -export PYTHONUNBUFFERED=1 - -# Setup service account credentials. -export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/service-account.json -export PROJECT_ID=$(cat "${KOKORO_GFILE_DIR}/project-id.json") -export GOOGLE_CLOUD_PROJECT=$(cat "${KOKORO_GFILE_DIR}/project-id.json") - -python3 -m nox --version - -# If this is a continuous build, send the test log to the FlakyBot. -# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/flakybot. -if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]]; then - cleanup() { - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot - } - trap cleanup EXIT HUP -fi - -# If NOX_SESSION is set, it only runs the specified session, -# otherwise run all the sessions. -if [[ -n "${NOX_SESSION:-}" ]]; then - python3 -m nox -s ${NOX_SESSION:-} -else - python3 -m nox -s unit - python3 -m nox -s system -fi diff --git a/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg b/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg deleted file mode 100644 index 3af6b61876e7..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/continuous/common.cfg +++ /dev/null @@ -1,27 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Download resources for system tests (service account key, etc.) -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" - -# Use the trampoline script to run in docker. -build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" -} diff --git a/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg b/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg deleted file mode 100644 index 18a4c35325b8..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/continuous/continuous.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto diff --git a/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh b/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh deleted file mode 100755 index bf0be603a62b..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/populate-secrets.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -set -eo pipefail - -function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} -function msg { println "$*" >&2 ;} -function println { printf '%s\n' "$(now) $*" ;} - - -# Populates requested secrets set in SECRET_MANAGER_KEYS from service account: -# kokoro-trampoline@cloud-devrel-kokoro-resources.iam.gserviceaccount.com -SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" -msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" -mkdir -p ${SECRET_LOCATION} -for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") -do - msg "Retrieving secret ${key}" - docker run --entrypoint=gcloud \ - --volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR} \ - gcr.io/google.com/cloudsdktool/cloud-sdk \ - secrets versions access latest \ - --project cloud-devrel-kokoro-resources \ - --secret ${key} > \ - "${SECRET_LOCATION}/${key}" - if [[ $? == 0 ]]; then - msg "Secret written to ${SECRET_LOCATION}/${key}" - else - msg "Error retrieving secret ${key}" - fi -done diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg deleted file mode 100644 index 3af6b61876e7..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/common.cfg +++ /dev/null @@ -1,27 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Download resources for system tests (service account key, etc.) -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-python" - -# Use the trampoline script to run in docker. -build_file: "python-spanner-sqlalchemy/.kokoro/trampoline.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-multi" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/python-spanner-sqlalchemy/.kokoro/build.sh" -} diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg deleted file mode 100644 index 1261d8a02f7d..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/compliance.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Only run this nox session. -env_vars: { - key: "NOX_SESSION" - value: "unit" -} diff --git a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg b/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg deleted file mode 100644 index 18a4c35325b8..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/presubmit/presubmit.cfg +++ /dev/null @@ -1 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto diff --git a/packages/sqlalchemy-spanner/.kokoro/trampoline.sh b/packages/sqlalchemy-spanner/.kokoro/trampoline.sh deleted file mode 100755 index 427c287ff2c8..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/trampoline.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -set -eo pipefail - -# Always run the cleanup script, regardless of the success of bouncing into -# the container. -function cleanup() { - chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh - ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh - echo "cleanup"; -} -trap cleanup EXIT - -$(dirname $0)/populate-secrets.sh # Secret Manager secrets. -python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" diff --git a/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh b/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh deleted file mode 100755 index 957848c45353..000000000000 --- a/packages/sqlalchemy-spanner/.kokoro/trampoline_v2.sh +++ /dev/null @@ -1,479 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2021 Google LLC -# -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file or at -# https://developers.google.com/open-source/licenses/bsd - -# trampoline_v2.sh -# -# This script does 3 things. -# -# 1. Prepare the Docker image for the test -# 2. Run the Docker with appropriate flags to run the test -# 3. Upload the newly built Docker image -# -# in a way that is somewhat compatible with trampoline_v1. -# -# To run this script, first download few files from gcs to /dev/shm. -# (/dev/shm is passed into the container as KOKORO_GFILE_DIR). -# -# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/secrets_viewer_service_account.json /dev/shm -# gsutil cp gs://cloud-devrel-kokoro-resources/python-docs-samples/automl_secrets.txt /dev/shm -# -# Then run the script. -# .kokoro/trampoline_v2.sh -# -# These environment variables are required: -# TRAMPOLINE_IMAGE: The docker image to use. -# TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. -# -# You can optionally change these environment variables: -# TRAMPOLINE_IMAGE_UPLOAD: -# (true|false): Whether to upload the Docker image after the -# successful builds. -# TRAMPOLINE_BUILD_FILE: The script to run in the docker container. -# TRAMPOLINE_WORKSPACE: The workspace path in the docker container. -# Defaults to /workspace. -# Potentially there are some repo specific envvars in .trampolinerc in -# the project root. - - -set -euo pipefail - -TRAMPOLINE_VERSION="2.0.5" - -if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then - readonly IO_COLOR_RED="$(tput setaf 1)" - readonly IO_COLOR_GREEN="$(tput setaf 2)" - readonly IO_COLOR_YELLOW="$(tput setaf 3)" - readonly IO_COLOR_RESET="$(tput sgr0)" -else - readonly IO_COLOR_RED="" - readonly IO_COLOR_GREEN="" - readonly IO_COLOR_YELLOW="" - readonly IO_COLOR_RESET="" -fi - -function function_exists { - [ $(LC_ALL=C type -t $1)"" == "function" ] -} - -# Logs a message using the given color. The first argument must be one -# of the IO_COLOR_* variables defined above, such as -# "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the -# given color. The log message will also have an RFC-3339 timestamp -# prepended (in UTC). You can disable the color output by setting -# TERM=vt100. -function log_impl() { - local color="$1" - shift - local timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" - echo "================================================================" - echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" - echo "================================================================" -} - -# Logs the given message with normal coloring and a timestamp. -function log() { - log_impl "${IO_COLOR_RESET}" "$@" -} - -# Logs the given message in green with a timestamp. -function log_green() { - log_impl "${IO_COLOR_GREEN}" "$@" -} - -# Logs the given message in yellow with a timestamp. -function log_yellow() { - log_impl "${IO_COLOR_YELLOW}" "$@" -} - -# Logs the given message in red with a timestamp. -function log_red() { - log_impl "${IO_COLOR_RED}" "$@" -} - -readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) -readonly tmphome="${tmpdir}/h" -mkdir -p "${tmphome}" - -function cleanup() { - rm -rf "${tmpdir}" -} -trap cleanup EXIT - -RUNNING_IN_CI="${RUNNING_IN_CI:-false}" - -# The workspace in the container, defaults to /workspace. -TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" - -pass_down_envvars=( - # TRAMPOLINE_V2 variables. - # Tells scripts whether they are running as part of CI or not. - "RUNNING_IN_CI" - # Indicates which CI system we're in. - "TRAMPOLINE_CI" - # Indicates the version of the script. - "TRAMPOLINE_VERSION" -) - -log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" - -# Detect which CI systems we're in. If we're in any of the CI systems -# we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be -# the name of the CI system. Both envvars will be passing down to the -# container for telling which CI system we're in. -if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then - # descriptive env var for indicating it's on CI. - RUNNING_IN_CI="true" - TRAMPOLINE_CI="kokoro" - if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then - if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then - log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." - exit 1 - fi - # This service account will be activated later. - TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" - else - if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then - gcloud auth list - fi - log_yellow "Configuring Container Registry access" - gcloud auth configure-docker --quiet - fi - pass_down_envvars+=( - # KOKORO dynamic variables. - "KOKORO_BUILD_NUMBER" - "KOKORO_BUILD_ID" - "KOKORO_JOB_NAME" - "KOKORO_GIT_COMMIT" - "KOKORO_GITHUB_COMMIT" - "KOKORO_GITHUB_PULL_REQUEST_NUMBER" - "KOKORO_GITHUB_PULL_REQUEST_COMMIT" - # For FlakyBot - "KOKORO_GITHUB_COMMIT_URL" - "KOKORO_GITHUB_PULL_REQUEST_URL" - ) -elif [[ "${TRAVIS:-}" == "true" ]]; then - RUNNING_IN_CI="true" - TRAMPOLINE_CI="travis" - pass_down_envvars+=( - "TRAVIS_BRANCH" - "TRAVIS_BUILD_ID" - "TRAVIS_BUILD_NUMBER" - "TRAVIS_BUILD_WEB_URL" - "TRAVIS_COMMIT" - "TRAVIS_COMMIT_MESSAGE" - "TRAVIS_COMMIT_RANGE" - "TRAVIS_JOB_NAME" - "TRAVIS_JOB_NUMBER" - "TRAVIS_JOB_WEB_URL" - "TRAVIS_PULL_REQUEST" - "TRAVIS_PULL_REQUEST_BRANCH" - "TRAVIS_PULL_REQUEST_SHA" - "TRAVIS_PULL_REQUEST_SLUG" - "TRAVIS_REPO_SLUG" - "TRAVIS_SECURE_ENV_VARS" - "TRAVIS_TAG" - ) -elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then - RUNNING_IN_CI="true" - TRAMPOLINE_CI="github-workflow" - pass_down_envvars+=( - "GITHUB_WORKFLOW" - "GITHUB_RUN_ID" - "GITHUB_RUN_NUMBER" - "GITHUB_ACTION" - "GITHUB_ACTIONS" - "GITHUB_ACTOR" - "GITHUB_REPOSITORY" - "GITHUB_EVENT_NAME" - "GITHUB_EVENT_PATH" - "GITHUB_SHA" - "GITHUB_REF" - "GITHUB_HEAD_REF" - "GITHUB_BASE_REF" - ) -elif [[ "${CIRCLECI:-}" == "true" ]]; then - RUNNING_IN_CI="true" - TRAMPOLINE_CI="circleci" - pass_down_envvars+=( - "CIRCLE_BRANCH" - "CIRCLE_BUILD_NUM" - "CIRCLE_BUILD_URL" - "CIRCLE_COMPARE_URL" - "CIRCLE_JOB" - "CIRCLE_NODE_INDEX" - "CIRCLE_NODE_TOTAL" - "CIRCLE_PREVIOUS_BUILD_NUM" - "CIRCLE_PROJECT_REPONAME" - "CIRCLE_PROJECT_USERNAME" - "CIRCLE_REPOSITORY_URL" - "CIRCLE_SHA1" - "CIRCLE_STAGE" - "CIRCLE_USERNAME" - "CIRCLE_WORKFLOW_ID" - "CIRCLE_WORKFLOW_JOB_ID" - "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" - "CIRCLE_WORKFLOW_WORKSPACE_ID" - ) -fi - -# Configure the service account for pulling the docker image. -function repo_root() { - local dir="$1" - while [[ ! -d "${dir}/.git" ]]; do - dir="$(dirname "$dir")" - done - echo "${dir}" -} - -# Detect the project root. In CI builds, we assume the script is in -# the git tree and traverse from there, otherwise, traverse from `pwd` -# to find `.git` directory. -if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then - PROGRAM_PATH="$(realpath "$0")" - PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" - PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" -else - PROJECT_ROOT="$(repo_root $(pwd))" -fi - -log_yellow "Changing to the project root: ${PROJECT_ROOT}." -cd "${PROJECT_ROOT}" - -# To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need -# to use this environment variable in `PROJECT_ROOT`. -if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then - - mkdir -p "${tmpdir}/gcloud" - gcloud_config_dir="${tmpdir}/gcloud" - - log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." - export CLOUDSDK_CONFIG="${gcloud_config_dir}" - - log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." - gcloud auth activate-service-account \ - --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" - log_yellow "Configuring Container Registry access" - gcloud auth configure-docker --quiet -fi - -required_envvars=( - # The basic trampoline configurations. - "TRAMPOLINE_IMAGE" - "TRAMPOLINE_BUILD_FILE" -) - -if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then - source "${PROJECT_ROOT}/.trampolinerc" -fi - -log_yellow "Checking environment variables." -for e in "${required_envvars[@]}" -do - if [[ -z "${!e:-}" ]]; then - log "Missing ${e} env var. Aborting." - exit 1 - fi -done - -# We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 -# script: e.g. "github/repo-name/.kokoro/run_tests.sh" -TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" -log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" - -# ignore error on docker operations and test execution -set +e - -log_yellow "Preparing Docker image." -# We only download the docker image in CI builds. -if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then - # Download the docker image specified by `TRAMPOLINE_IMAGE` - - # We may want to add --max-concurrent-downloads flag. - - log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." - if docker pull "${TRAMPOLINE_IMAGE}"; then - log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." - has_image="true" - else - log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." - has_image="false" - fi -else - # For local run, check if we have the image. - if docker images "${TRAMPOLINE_IMAGE}:latest" | grep "${TRAMPOLINE_IMAGE}"; then - has_image="true" - else - has_image="false" - fi -fi - - -# The default user for a Docker container has uid 0 (root). To avoid -# creating root-owned files in the build directory we tell docker to -# use the current user ID. -user_uid="$(id -u)" -user_gid="$(id -g)" -user_name="$(id -un)" - -# To allow docker in docker, we add the user to the docker group in -# the host os. -docker_gid=$(cut -d: -f3 < <(getent group docker)) - -update_cache="false" -if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then - # Build the Docker image from the source. - context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") - docker_build_flags=( - "-f" "${TRAMPOLINE_DOCKERFILE}" - "-t" "${TRAMPOLINE_IMAGE}" - "--build-arg" "UID=${user_uid}" - "--build-arg" "USERNAME=${user_name}" - ) - if [[ "${has_image}" == "true" ]]; then - docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") - fi - - log_yellow "Start building the docker image." - if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then - echo "docker build" "${docker_build_flags[@]}" "${context_dir}" - fi - - # ON CI systems, we want to suppress docker build logs, only - # output the logs when it fails. - if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then - if docker build "${docker_build_flags[@]}" "${context_dir}" \ - > "${tmpdir}/docker_build.log" 2>&1; then - if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then - cat "${tmpdir}/docker_build.log" - fi - - log_green "Finished building the docker image." - update_cache="true" - else - log_red "Failed to build the Docker image, aborting." - log_yellow "Dumping the build logs:" - cat "${tmpdir}/docker_build.log" - exit 1 - fi - else - if docker build "${docker_build_flags[@]}" "${context_dir}"; then - log_green "Finished building the docker image." - update_cache="true" - else - log_red "Failed to build the Docker image, aborting." - exit 1 - fi - fi -else - if [[ "${has_image}" != "true" ]]; then - log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." - exit 1 - fi -fi - -# We use an array for the flags so they are easier to document. -docker_flags=( - # Remove the container after it exists. - "--rm" - - # Use the host network. - "--network=host" - - # Run in priviledged mode. We are not using docker for sandboxing or - # isolation, just for packaging our dev tools. - "--privileged" - - # Run the docker script with the user id. Because the docker image gets to - # write in ${PWD} you typically want this to be your user id. - # To allow docker in docker, we need to use docker gid on the host. - "--user" "${user_uid}:${docker_gid}" - - # Pass down the USER. - "--env" "USER=${user_name}" - - # Mount the project directory inside the Docker container. - "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" - "--workdir" "${TRAMPOLINE_WORKSPACE}" - "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" - - # Mount the temporary home directory. - "--volume" "${tmphome}:/h" - "--env" "HOME=/h" - - # Allow docker in docker. - "--volume" "/var/run/docker.sock:/var/run/docker.sock" - - # Mount the /tmp so that docker in docker can mount the files - # there correctly. - "--volume" "/tmp:/tmp" - # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR - # TODO(tmatsuo): This part is not portable. - "--env" "TRAMPOLINE_SECRET_DIR=/secrets" - "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" - "--env" "KOKORO_GFILE_DIR=/secrets/gfile" - "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" - "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" -) - -# Add an option for nicer output if the build gets a tty. -if [[ -t 0 ]]; then - docker_flags+=("-it") -fi - -# Passing down env vars -for e in "${pass_down_envvars[@]}" -do - if [[ -n "${!e:-}" ]]; then - docker_flags+=("--env" "${e}=${!e}") - fi -done - -# If arguments are given, all arguments will become the commands run -# in the container, otherwise run TRAMPOLINE_BUILD_FILE. -if [[ $# -ge 1 ]]; then - log_yellow "Running the given commands '" "${@:1}" "' in the container." - readonly commands=("${@:1}") - if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then - echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" - fi - docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" -else - log_yellow "Running the tests in a Docker container." - docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") - if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then - echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" - fi - docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" -fi - - -test_retval=$? - -if [[ ${test_retval} -eq 0 ]]; then - log_green "Build finished with ${test_retval}" -else - log_red "Build finished with ${test_retval}" -fi - -# Only upload it when the test passes. -if [[ "${update_cache}" == "true" ]] && \ - [[ $test_retval == 0 ]] && \ - [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then - log_yellow "Uploading the Docker image." - if docker push "${TRAMPOLINE_IMAGE}"; then - log_green "Finished uploading the Docker image." - else - log_red "Failed uploading the Docker image." - fi - # Call trampoline_after_upload_hook if it's defined. - if function_exists trampoline_after_upload_hook; then - trampoline_after_upload_hook - fi - -fi - -exit "${test_retval}" diff --git a/scripts/split_repo_migration/single-library.git-migrate-history.sh b/scripts/split_repo_migration/single-library.git-migrate-history.sh index 650abac5ca26..b110af51fe97 100755 --- a/scripts/split_repo_migration/single-library.git-migrate-history.sh +++ b/scripts/split_repo_migration/single-library.git-migrate-history.sh @@ -70,7 +70,7 @@ echo "Created working directory: ${WORKDIR}" pushd "${WORKDIR}" # cd into workdir echo "Cloning source repository: ${SOURCE_REPO}" -git clone --recurse-submodules --recurse-submodules "git@github.com:${SOURCE_REPO}.git" source-repo +git clone --recurse-submodules --recurse-submodules --recurse-submodules "git@github.com:${SOURCE_REPO}.git" source-repo pushd source-repo @@ -124,7 +124,7 @@ git filter-branch \ --force \ --prune-empty \ --tree-filter \ - "git submodule update --init --recursive; find . -mindepth 2 -name .git -exec rm -rf {} +; git submodule update --init --recursive; find . -mindepth 2 -name .git -exec rm -rf {} +; shopt -s dotglob; mkdir -p ${WORKDIR}/migrated-source; mv * ${WORKDIR}/migrated-source; mkdir -p ${TARGET_PATH}; { mv ${WORKDIR}/migrated-source/* ${TARGET_PATH} || echo 'No files to move' ; }" + "git submodule update --init --recursive; find . -mindepth 2 -name .git -exec rm -rf {} +; git submodule update --init --recursive; find . -mindepth 2 -name .git -exec rm -rf {} +; git submodule update --init --recursive; find . -mindepth 2 -name .git -exec rm -rf {} +; shopt -s dotglob; mkdir -p ${WORKDIR}/migrated-source; mv * ${WORKDIR}/migrated-source; mkdir -p ${TARGET_PATH}; { mv ${WORKDIR}/migrated-source/* ${TARGET_PATH} || echo 'No files to move' ; }" # back to workdir popd @@ -142,7 +142,7 @@ echo "Success" popd # back to workdir # Do a diff between source code split repo and migrated code. -git clone --recurse-submodules --recurse-submodules "git@github.com:${SOURCE_REPO}.git" source-repo-validation # Not ideal to clone again. +git clone --recurse-submodules --recurse-submodules --recurse-submodules "git@github.com:${SOURCE_REPO}.git" source-repo-validation # Not ideal to clone again. find source-repo-validation -name .git -exec rm -rf {} + # That folder is not needed for validation. DIFF_FILE="${WORKDIR}/diff.txt"