diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 51b61ba529..757c9dca75 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:266a3407f0bb34374f49b6556ee20ee819374587246dcc19405b502ec70113b6 + digest: sha256:81ed5ecdfc7cac5b699ba4537376f3563f6f04122c4ec9e735d3b3dc1d43dd32 +# created: 2022-05-05T22:08:23.383410683Z diff --git a/.github/auto-approve.yml b/.github/auto-approve.yml new file mode 100644 index 0000000000..311ebbb853 --- /dev/null +++ b/.github/auto-approve.yml @@ -0,0 +1,3 @@ +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/auto-approve +processes: + - "OwlBotTemplateChanges" diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index 8715e17dc4..fc2092ed7f 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -1,2 +1,2 @@ assign_issues: - - vi3k6i5 + - asthamohta diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile index 4e1b1fb8b5..238b87b9d1 100644 --- a/.kokoro/docker/docs/Dockerfile +++ b/.kokoro/docker/docs/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ubuntu:20.04 +from ubuntu:22.04 ENV DEBIAN_FRONTEND noninteractive @@ -60,8 +60,24 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && rm -f /var/cache/apt/archives/*.deb +###################### Install python 3.8.11 + +# Download python 3.8.11 +RUN wget https://www.python.org/ftp/python/3.8.11/Python-3.8.11.tgz + +# Extract files +RUN tar -xvf Python-3.8.11.tgz + +# Install python 3.8.11 +RUN ./Python-3.8.11/configure --enable-optimizations +RUN make altinstall + +###################### Install pip RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \ - && python3.8 /tmp/get-pip.py \ + && python3 /tmp/get-pip.py \ && rm /tmp/get-pip.py +# Test pip +RUN python3 -m pip + CMD ["python3.8"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a1735bb6..62faf8d9cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ [1]: https://pypi.org/project/google-cloud-spanner/#history +## [3.14.1](https://github.com/googleapis/python-spanner/compare/v3.14.0...v3.14.1) (2022-06-08) + + +### Bug Fixes + +* **deps:** require protobuf <4.0.0dev ([#731](https://github.com/googleapis/python-spanner/issues/731)) ([8004ae5](https://github.com/googleapis/python-spanner/commit/8004ae54b4a6e6a7b19d8da1de46f3526da881ff)) + + +### Documentation + +* fix changelog header to consistent size ([#732](https://github.com/googleapis/python-spanner/issues/732)) ([97b6d37](https://github.com/googleapis/python-spanner/commit/97b6d37c78a325c404d649a1db5e7337beedefb5)) + ## [3.14.0](https://github.com/googleapis/python-spanner/compare/v3.13.0...v3.14.0) (2022-04-20) @@ -40,7 +52,7 @@ * add support for row_count in cursor. ([#675](https://github.com/googleapis/python-spanner/issues/675)) ([d431339](https://github.com/googleapis/python-spanner/commit/d431339069874abf345347b777b3811464925e46)) * resolve DuplicateCredentialArgs error when using credentials_file ([#676](https://github.com/googleapis/python-spanner/issues/676)) ([39ff137](https://github.com/googleapis/python-spanner/commit/39ff13796adc13b6702d003e4d549775f8cef202)) -### [3.12.1](https://www.github.com/googleapis/python-spanner/compare/v3.12.0...v3.12.1) (2022-01-06) +## [3.12.1](https://www.github.com/googleapis/python-spanner/compare/v3.12.0...v3.12.1) (2022-01-06) ### Bug Fixes @@ -79,7 +91,7 @@ * list oneofs in docstring ([5ae4be8](https://www.github.com/googleapis/python-spanner/commit/5ae4be8ce0a429b33b31a119d7079ce4deb50ca2)) -### [3.11.1](https://www.github.com/googleapis/python-spanner/compare/v3.11.0...v3.11.1) (2021-10-04) +## [3.11.1](https://www.github.com/googleapis/python-spanner/compare/v3.11.0...v3.11.1) (2021-10-04) ### Bug Fixes @@ -330,7 +342,7 @@ * DB-API driver + unit tests ([#160](https://www.github.com/googleapis/python-spanner/issues/160)) ([2493fa1](https://www.github.com/googleapis/python-spanner/commit/2493fa1725d2d613f6c064637a4e215ee66255e3)) * migrate to v2.0.0 ([#147](https://www.github.com/googleapis/python-spanner/issues/147)) ([bf4b278](https://www.github.com/googleapis/python-spanner/commit/bf4b27827494e3dc33b1e4333dfe147a36a486b3)) -### [1.19.1](https://www.github.com/googleapis/python-spanner/compare/v1.19.0...v1.19.1) (2020-10-13) +## [1.19.1](https://www.github.com/googleapis/python-spanner/compare/v1.19.0...v1.19.1) (2020-10-13) ### Bug Fixes @@ -377,7 +389,7 @@ * add samples from spanner/cloud-client ([#117](https://www.github.com/googleapis/python-spanner/issues/117)) ([8910771](https://www.github.com/googleapis/python-spanner/commit/891077105d5093a73caf96683d10afef2cd17823)), closes [#804](https://www.github.com/googleapis/python-spanner/issues/804) [#815](https://www.github.com/googleapis/python-spanner/issues/815) [#818](https://www.github.com/googleapis/python-spanner/issues/818) [#887](https://www.github.com/googleapis/python-spanner/issues/887) [#914](https://www.github.com/googleapis/python-spanner/issues/914) [#922](https://www.github.com/googleapis/python-spanner/issues/922) [#928](https://www.github.com/googleapis/python-spanner/issues/928) [#962](https://www.github.com/googleapis/python-spanner/issues/962) [#992](https://www.github.com/googleapis/python-spanner/issues/992) [#1004](https://www.github.com/googleapis/python-spanner/issues/1004) [#1035](https://www.github.com/googleapis/python-spanner/issues/1035) [#1055](https://www.github.com/googleapis/python-spanner/issues/1055) [#1063](https://www.github.com/googleapis/python-spanner/issues/1063) [#1093](https://www.github.com/googleapis/python-spanner/issues/1093) [#1107](https://www.github.com/googleapis/python-spanner/issues/1107) [#1121](https://www.github.com/googleapis/python-spanner/issues/1121) [#1158](https://www.github.com/googleapis/python-spanner/issues/1158) [#1138](https://www.github.com/googleapis/python-spanner/issues/1138) [#1186](https://www.github.com/googleapis/python-spanner/issues/1186) [#1192](https://www.github.com/googleapis/python-spanner/issues/1192) [#1207](https://www.github.com/googleapis/python-spanner/issues/1207) [#1254](https://www.github.com/googleapis/python-spanner/issues/1254) [#1316](https://www.github.com/googleapis/python-spanner/issues/1316) [#1354](https://www.github.com/googleapis/python-spanner/issues/1354) [#1376](https://www.github.com/googleapis/python-spanner/issues/1376) [#1377](https://www.github.com/googleapis/python-spanner/issues/1377) [#1402](https://www.github.com/googleapis/python-spanner/issues/1402) [#1406](https://www.github.com/googleapis/python-spanner/issues/1406) [#1425](https://www.github.com/googleapis/python-spanner/issues/1425) [#1441](https://www.github.com/googleapis/python-spanner/issues/1441) [#1464](https://www.github.com/googleapis/python-spanner/issues/1464) [#1519](https://www.github.com/googleapis/python-spanner/issues/1519) [#1548](https://www.github.com/googleapis/python-spanner/issues/1548) [#1633](https://www.github.com/googleapis/python-spanner/issues/1633) [#1742](https://www.github.com/googleapis/python-spanner/issues/1742) [#1836](https://www.github.com/googleapis/python-spanner/issues/1836) [#1846](https://www.github.com/googleapis/python-spanner/issues/1846) [#1872](https://www.github.com/googleapis/python-spanner/issues/1872) [#1980](https://www.github.com/googleapis/python-spanner/issues/1980) [#2068](https://www.github.com/googleapis/python-spanner/issues/2068) [#2153](https://www.github.com/googleapis/python-spanner/issues/2153) [#2224](https://www.github.com/googleapis/python-spanner/issues/2224) [#2198](https://www.github.com/googleapis/python-spanner/issues/2198) [#2251](https://www.github.com/googleapis/python-spanner/issues/2251) [#2295](https://www.github.com/googleapis/python-spanner/issues/2295) [#2356](https://www.github.com/googleapis/python-spanner/issues/2356) [#2392](https://www.github.com/googleapis/python-spanner/issues/2392) [#2439](https://www.github.com/googleapis/python-spanner/issues/2439) [#2535](https://www.github.com/googleapis/python-spanner/issues/2535) [#2005](https://www.github.com/googleapis/python-spanner/issues/2005) [#2721](https://www.github.com/googleapis/python-spanner/issues/2721) [#3093](https://www.github.com/googleapis/python-spanner/issues/3093) [#3101](https://www.github.com/googleapis/python-spanner/issues/3101) [#2806](https://www.github.com/googleapis/python-spanner/issues/2806) [#3377](https://www.github.com/googleapis/python-spanner/issues/3377) * typo fix ([#109](https://www.github.com/googleapis/python-spanner/issues/109)) ([63b4324](https://www.github.com/googleapis/python-spanner/commit/63b432472613bd80e234ee9c9f73906db2f0a52b)) -### [1.17.1](https://www.github.com/googleapis/python-spanner/compare/v1.17.0...v1.17.1) (2020-06-24) +## [1.17.1](https://www.github.com/googleapis/python-spanner/compare/v1.17.0...v1.17.1) (2020-06-24) ### Documentation @@ -412,7 +424,7 @@ * add keepalive changes to synth.py ([#55](https://www.github.com/googleapis/python-spanner/issues/55)) ([805bbb7](https://www.github.com/googleapis/python-spanner/commit/805bbb766fd9c019f528e2f8ed1379d997622d03)) * pass gRPC config options to gRPC channel creation ([#26](https://www.github.com/googleapis/python-spanner/issues/26)) ([6c9a1ba](https://www.github.com/googleapis/python-spanner/commit/6c9a1badfed610a18454137e1b45156872914e7e)) -### [1.15.1](https://www.github.com/googleapis/python-spanner/compare/v1.15.0...v1.15.1) (2020-04-08) +## [1.15.1](https://www.github.com/googleapis/python-spanner/compare/v1.15.0...v1.15.1) (2020-04-08) ### Bug Fixes diff --git a/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py b/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py index c5d38710bf..34989553d5 100644 --- a/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +++ b/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py @@ -246,9 +246,9 @@ async def list_databases( from google.cloud import spanner_admin_database_v1 - def sample_list_databases(): + async def sample_list_databases(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.ListDatabasesRequest( @@ -259,7 +259,7 @@ def sample_list_databases(): page_result = client.list_databases(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -375,9 +375,9 @@ async def create_database( from google.cloud import spanner_admin_database_v1 - def sample_create_database(): + async def sample_create_database(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.CreateDatabaseRequest( @@ -390,7 +390,7 @@ def sample_create_database(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -501,9 +501,9 @@ async def get_database( from google.cloud import spanner_admin_database_v1 - def sample_get_database(): + async def sample_get_database(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.GetDatabaseRequest( @@ -511,7 +511,7 @@ def sample_get_database(): ) # Make the request - response = client.get_database(request=request) + response = await client.get_database(request=request) # Handle the response print(response) @@ -614,9 +614,9 @@ async def update_database_ddl( from google.cloud import spanner_admin_database_v1 - def sample_update_database_ddl(): + async def sample_update_database_ddl(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.UpdateDatabaseDdlRequest( @@ -629,7 +629,7 @@ def sample_update_database_ddl(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -772,9 +772,9 @@ async def drop_database( from google.cloud import spanner_admin_database_v1 - def sample_drop_database(): + async def sample_drop_database(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.DropDatabaseRequest( @@ -782,7 +782,7 @@ def sample_drop_database(): ) # Make the request - client.drop_database(request=request) + await client.drop_database(request=request) Args: request (Union[google.cloud.spanner_admin_database_v1.types.DropDatabaseRequest, dict]): @@ -866,9 +866,9 @@ async def get_database_ddl( from google.cloud import spanner_admin_database_v1 - def sample_get_database_ddl(): + async def sample_get_database_ddl(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.GetDatabaseDdlRequest( @@ -876,7 +876,7 @@ def sample_get_database_ddl(): ) # Make the request - response = client.get_database_ddl(request=request) + response = await client.get_database_ddl(request=request) # Handle the response print(response) @@ -981,9 +981,9 @@ async def set_iam_policy( from google.cloud import spanner_admin_database_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_set_iam_policy(): + async def sample_set_iam_policy(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.SetIamPolicyRequest( @@ -991,7 +991,7 @@ def sample_set_iam_policy(): ) # Make the request - response = client.set_iam_policy(request=request) + response = await client.set_iam_policy(request=request) # Handle the response print(response) @@ -1149,9 +1149,9 @@ async def get_iam_policy( from google.cloud import spanner_admin_database_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_get_iam_policy(): + async def sample_get_iam_policy(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.GetIamPolicyRequest( @@ -1159,7 +1159,7 @@ def sample_get_iam_policy(): ) # Make the request - response = client.get_iam_policy(request=request) + response = await client.get_iam_policy(request=request) # Handle the response print(response) @@ -1328,9 +1328,9 @@ async def test_iam_permissions( from google.cloud import spanner_admin_database_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_test_iam_permissions(): + async def sample_test_iam_permissions(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.TestIamPermissionsRequest( @@ -1339,7 +1339,7 @@ def sample_test_iam_permissions(): ) # Make the request - response = client.test_iam_permissions(request=request) + response = await client.test_iam_permissions(request=request) # Handle the response print(response) @@ -1450,9 +1450,9 @@ async def create_backup( from google.cloud import spanner_admin_database_v1 - def sample_create_backup(): + async def sample_create_backup(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.CreateBackupRequest( @@ -1465,7 +1465,7 @@ def sample_create_backup(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -1599,9 +1599,9 @@ async def copy_backup( from google.cloud import spanner_admin_database_v1 - def sample_copy_backup(): + async def sample_copy_backup(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.CopyBackupRequest( @@ -1615,7 +1615,7 @@ def sample_copy_backup(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -1751,9 +1751,9 @@ async def get_backup( from google.cloud import spanner_admin_database_v1 - def sample_get_backup(): + async def sample_get_backup(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.GetBackupRequest( @@ -1761,7 +1761,7 @@ def sample_get_backup(): ) # Make the request - response = client.get_backup(request=request) + response = await client.get_backup(request=request) # Handle the response print(response) @@ -1856,16 +1856,16 @@ async def update_backup( from google.cloud import spanner_admin_database_v1 - def sample_update_backup(): + async def sample_update_backup(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.UpdateBackupRequest( ) # Make the request - response = client.update_backup(request=request) + response = await client.update_backup(request=request) # Handle the response print(response) @@ -1979,9 +1979,9 @@ async def delete_backup( from google.cloud import spanner_admin_database_v1 - def sample_delete_backup(): + async def sample_delete_backup(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.DeleteBackupRequest( @@ -1989,7 +1989,7 @@ def sample_delete_backup(): ) # Make the request - client.delete_backup(request=request) + await client.delete_backup(request=request) Args: request (Union[google.cloud.spanner_admin_database_v1.types.DeleteBackupRequest, dict]): @@ -2075,9 +2075,9 @@ async def list_backups( from google.cloud import spanner_admin_database_v1 - def sample_list_backups(): + async def sample_list_backups(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.ListBackupsRequest( @@ -2088,7 +2088,7 @@ def sample_list_backups(): page_result = client.list_backups(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -2213,9 +2213,9 @@ async def restore_database( from google.cloud import spanner_admin_database_v1 - def sample_restore_database(): + async def sample_restore_database(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.RestoreDatabaseRequest( @@ -2229,7 +2229,7 @@ def sample_restore_database(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -2361,9 +2361,9 @@ async def list_database_operations( from google.cloud import spanner_admin_database_v1 - def sample_list_database_operations(): + async def sample_list_database_operations(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.ListDatabaseOperationsRequest( @@ -2374,7 +2374,7 @@ def sample_list_database_operations(): page_result = client.list_database_operations(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -2491,9 +2491,9 @@ async def list_backup_operations( from google.cloud import spanner_admin_database_v1 - def sample_list_backup_operations(): + async def sample_list_backup_operations(): # Create a client - client = spanner_admin_database_v1.DatabaseAdminClient() + client = spanner_admin_database_v1.DatabaseAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_database_v1.ListBackupOperationsRequest( @@ -2504,7 +2504,7 @@ def sample_list_backup_operations(): page_result = client.list_backup_operations(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: diff --git a/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py b/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py index 4bbd9558c2..df6936aac3 100644 --- a/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +++ b/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py @@ -248,9 +248,9 @@ async def list_instance_configs( from google.cloud import spanner_admin_instance_v1 - def sample_list_instance_configs(): + async def sample_list_instance_configs(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_instance_v1.ListInstanceConfigsRequest( @@ -261,7 +261,7 @@ def sample_list_instance_configs(): page_result = client.list_instance_configs(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -368,9 +368,9 @@ async def get_instance_config( from google.cloud import spanner_admin_instance_v1 - def sample_get_instance_config(): + async def sample_get_instance_config(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_instance_v1.GetInstanceConfigRequest( @@ -378,7 +378,7 @@ def sample_get_instance_config(): ) # Make the request - response = client.get_instance_config(request=request) + response = await client.get_instance_config(request=request) # Handle the response print(response) @@ -476,9 +476,9 @@ async def list_instances( from google.cloud import spanner_admin_instance_v1 - def sample_list_instances(): + async def sample_list_instances(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_instance_v1.ListInstancesRequest( @@ -489,7 +489,7 @@ def sample_list_instances(): page_result = client.list_instances(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -595,9 +595,9 @@ async def get_instance( from google.cloud import spanner_admin_instance_v1 - def sample_get_instance(): + async def sample_get_instance(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_instance_v1.GetInstanceRequest( @@ -605,7 +605,7 @@ def sample_get_instance(): ) # Make the request - response = client.get_instance(request=request) + response = await client.get_instance(request=request) # Handle the response print(response) @@ -740,9 +740,9 @@ async def create_instance( from google.cloud import spanner_admin_instance_v1 - def sample_create_instance(): + async def sample_create_instance(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) instance = spanner_admin_instance_v1.Instance() @@ -761,7 +761,7 @@ def sample_create_instance(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -923,9 +923,9 @@ async def update_instance( from google.cloud import spanner_admin_instance_v1 - def sample_update_instance(): + async def sample_update_instance(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) instance = spanner_admin_instance_v1.Instance() @@ -942,7 +942,7 @@ def sample_update_instance(): print("Waiting for operation to complete...") - response = operation.result() + response = await operation.result() # Handle the response print(response) @@ -1068,9 +1068,9 @@ async def delete_instance( from google.cloud import spanner_admin_instance_v1 - def sample_delete_instance(): + async def sample_delete_instance(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = spanner_admin_instance_v1.DeleteInstanceRequest( @@ -1078,7 +1078,7 @@ def sample_delete_instance(): ) # Make the request - client.delete_instance(request=request) + await client.delete_instance(request=request) Args: request (Union[google.cloud.spanner_admin_instance_v1.types.DeleteInstanceRequest, dict]): @@ -1167,9 +1167,9 @@ async def set_iam_policy( from google.cloud import spanner_admin_instance_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_set_iam_policy(): + async def sample_set_iam_policy(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.SetIamPolicyRequest( @@ -1177,7 +1177,7 @@ def sample_set_iam_policy(): ) # Make the request - response = client.set_iam_policy(request=request) + response = await client.set_iam_policy(request=request) # Handle the response print(response) @@ -1331,9 +1331,9 @@ async def get_iam_policy( from google.cloud import spanner_admin_instance_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_get_iam_policy(): + async def sample_get_iam_policy(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.GetIamPolicyRequest( @@ -1341,7 +1341,7 @@ def sample_get_iam_policy(): ) # Make the request - response = client.get_iam_policy(request=request) + response = await client.get_iam_policy(request=request) # Handle the response print(response) @@ -1507,9 +1507,9 @@ async def test_iam_permissions( from google.cloud import spanner_admin_instance_v1 from google.iam.v1 import iam_policy_pb2 # type: ignore - def sample_test_iam_permissions(): + async def sample_test_iam_permissions(): # Create a client - client = spanner_admin_instance_v1.InstanceAdminClient() + client = spanner_admin_instance_v1.InstanceAdminAsyncClient() # Initialize request argument(s) request = iam_policy_pb2.TestIamPermissionsRequest( @@ -1518,7 +1518,7 @@ def sample_test_iam_permissions(): ) # Make the request - response = client.test_iam_permissions(request=request) + response = await client.test_iam_permissions(request=request) # Handle the response print(response) diff --git a/google/cloud/spanner_dbapi/_helpers.py b/google/cloud/spanner_dbapi/_helpers.py index 177df9e9bd..ee4883d74f 100644 --- a/google/cloud/spanner_dbapi/_helpers.py +++ b/google/cloud/spanner_dbapi/_helpers.py @@ -13,7 +13,6 @@ # limitations under the License. from google.cloud.spanner_dbapi.parse_utils import get_param_types -from google.cloud.spanner_dbapi.parse_utils import parse_insert from google.cloud.spanner_dbapi.parse_utils import sql_pyformat_args_to_spanner from google.cloud.spanner_v1 import param_types @@ -51,44 +50,13 @@ def _execute_insert_heterogenous(transaction, sql_params_list): for sql, params in sql_params_list: sql, params = sql_pyformat_args_to_spanner(sql, params) - param_types = get_param_types(params) - transaction.execute_update(sql, params=params, param_types=param_types) - - -def _execute_insert_homogenous(transaction, parts): - # Perform an insert in one shot. - return transaction.insert( - parts.get("table"), parts.get("columns"), parts.get("values") - ) + transaction.execute_update(sql, params, get_param_types(params)) def handle_insert(connection, sql, params): - parts = parse_insert(sql, params) - - # The split between the two styles exists because: - # in the common case of multiple values being passed - # with simple pyformat arguments, - # SQL: INSERT INTO T (f1, f2) VALUES (%s, %s, %s) - # Params: [(1, 2, 3, 4, 5, 6, 7, 8, 9, 10,)] - # we can take advantage of a single RPC with: - # transaction.insert(table, columns, values) - # instead of invoking: - # with transaction: - # for sql, params in sql_params_list: - # transaction.execute_sql(sql, params, param_types) - # which invokes more RPCs and is more costly. - - if parts.get("homogenous"): - # The common case of multiple values being passed in - # non-complex pyformat args and need to be uploaded in one RPC. - return connection.database.run_in_transaction(_execute_insert_homogenous, parts) - else: - # All the other cases that are esoteric and need - # transaction.execute_sql - sql_params_list = parts.get("sql_params_list") - return connection.database.run_in_transaction( - _execute_insert_heterogenous, sql_params_list - ) + return connection.database.run_in_transaction( + _execute_insert_heterogenous, ((sql, params),) + ) class ColumnInfo: diff --git a/google/cloud/spanner_dbapi/connection.py b/google/cloud/spanner_dbapi/connection.py index 76f04338c4..91b63a2da1 100644 --- a/google/cloud/spanner_dbapi/connection.py +++ b/google/cloud/spanner_dbapi/connection.py @@ -24,8 +24,6 @@ from google.cloud.spanner_v1.snapshot import Snapshot from google.cloud.spanner_dbapi._helpers import _execute_insert_heterogenous -from google.cloud.spanner_dbapi._helpers import _execute_insert_homogenous -from google.cloud.spanner_dbapi._helpers import parse_insert from google.cloud.spanner_dbapi.checksum import _compare_checksums from google.cloud.spanner_dbapi.checksum import ResultsChecksum from google.cloud.spanner_dbapi.cursor import Cursor @@ -436,23 +434,13 @@ def run_statement(self, statement, retried=False): self._statements.append(statement) if statement.is_insert: - parts = parse_insert(statement.sql, statement.params) - - if parts.get("homogenous"): - _execute_insert_homogenous(transaction, parts) - return ( - iter(()), - ResultsChecksum() if retried else statement.checksum, - ) - else: - _execute_insert_heterogenous( - transaction, - parts.get("sql_params_list"), - ) - return ( - iter(()), - ResultsChecksum() if retried else statement.checksum, - ) + _execute_insert_heterogenous( + transaction, ((statement.sql, statement.params),) + ) + return ( + iter(()), + ResultsChecksum() if retried else statement.checksum, + ) return ( transaction.execute_sql( diff --git a/google/cloud/spanner_dbapi/parse_utils.py b/google/cloud/spanner_dbapi/parse_utils.py index 61bded4e80..e051f96a00 100644 --- a/google/cloud/spanner_dbapi/parse_utils.py +++ b/google/cloud/spanner_dbapi/parse_utils.py @@ -17,14 +17,12 @@ import datetime import decimal import re -from functools import reduce import sqlparse from google.cloud import spanner_v1 as spanner from google.cloud.spanner_v1 import JsonObject -from .exceptions import Error, ProgrammingError -from .parser import expect, VALUES +from .exceptions import Error from .types import DateStr, TimestampStr from .utils import sanitize_literals_for_upload @@ -185,6 +183,12 @@ def classify_stmt(query): :rtype: str :returns: The query type name. """ + # sqlparse will strip Cloud Spanner comments, + # still, special commenting styles, like + # PostgreSQL dollar quoted comments are not + # supported and will not be stripped. + query = sqlparse.format(query, strip_comments=True).strip() + if RE_DDL.match(query): return STMT_DDL @@ -199,255 +203,6 @@ def classify_stmt(query): return STMT_UPDATING -def parse_insert(insert_sql, params): - """ - Parse an INSERT statement and generate a list of tuples of the form: - [ - (SQL, params_per_row1), - (SQL, params_per_row2), - (SQL, params_per_row3), - ... - ] - - There are 4 variants of an INSERT statement: - a) INSERT INTO (columns...) VALUES (): no params - b) INSERT INTO
(columns...) SELECT_STMT: no params - c) INSERT INTO
(columns...) VALUES (%s,...): with params - d) INSERT INTO
(columns...) VALUES (%s,.....) with params and expressions - - Thus given each of the forms, it will produce a dictionary describing - how to upload the contents to Cloud Spanner: - Case a) - SQL: INSERT INTO T (f1, f2) VALUES (1, 2) - it produces: - { - 'sql_params_list': [ - ('INSERT INTO T (f1, f2) VALUES (1, 2)', None), - ], - } - - Case b) - SQL: 'INSERT INTO T (s, c) SELECT st, zc FROM cus WHERE col IN (%s, %s)', - it produces: - { - 'sql_params_list': [ - ('INSERT INTO T (s, c) SELECT st, zc FROM cus ORDER BY fn, ln', ('a', 'b')), - ] - } - - Case c) - SQL: INSERT INTO T (f1, f2) VALUES (%s, %s), (%s, %s) - Params: ['a', 'b', 'c', 'd'] - it produces: - { - 'sql_params_list': [ - ('INSERT INTO T (f1, f2) VALUES (%s, %s)', ('a', 'b')), - ('INSERT INTO T (f1, f2) VALUES (%s, %s)', ('c', 'd')) - ], - } - - Case d) - SQL: INSERT INTO T (f1, f2) VALUES (%s, LOWER(%s)), (UPPER(%s), %s) - Params: ['a', 'b', 'c', 'd'] - it produces: - { - 'sql_params_list': [ - ('INSERT INTO T (f1, f2) VALUES (%s, LOWER(%s))', ('a', 'b',)), - ('INSERT INTO T (f1, f2) VALUES (UPPER(%s), %s)', ('c', 'd',)) - ], - } - - :type insert_sql: str - :param insert_sql: A SQL insert request. - - :type params: list - :param params: A list of parameters. - - :rtype: dict - :returns: A dictionary that maps `sql_params_list` to the list of - parameters in cases a), b), d) or the dictionary with information - about the resulting table in case c). - """ # noqa - match = RE_INSERT.search(insert_sql) - - if not match: - raise ProgrammingError( - "Could not parse an INSERT statement from %s" % insert_sql - ) - - after_values_sql = RE_VALUES_TILL_END.findall(insert_sql) - if not after_values_sql: - # Case b) - insert_sql = sanitize_literals_for_upload(insert_sql) - return {"sql_params_list": [(insert_sql, params)]} - - if not params: - # Case a) perhaps? - # Check if any %s exists. - - # pyformat_str_count = after_values_sql.count("%s") - # if pyformat_str_count > 0: - # raise ProgrammingError( - # 'no params yet there are %d "%%s" tokens' % pyformat_str_count - # ) - for item in after_values_sql: - if item.count("%s") > 0: - raise ProgrammingError( - 'no params yet there are %d "%%s" tokens' % item.count("%s") - ) - - insert_sql = sanitize_literals_for_upload(insert_sql) - # Confirmed case of: - # SQL: INSERT INTO T (a1, a2) VALUES (1, 2) - # Params: None - return {"sql_params_list": [(insert_sql, None)]} - - _, values = expect(after_values_sql[0], VALUES) - - if values.homogenous(): - # Case c) - - columns = [mi.strip(" `") for mi in match.group("columns").split(",")] - sql_params_list = [] - insert_sql_preamble = "INSERT INTO %s (%s) VALUES %s" % ( - match.group("table_name"), - match.group("columns"), - values.argv[0], - ) - values_pyformat = [str(arg) for arg in values.argv] - rows_list = rows_for_insert_or_update(columns, params, values_pyformat) - insert_sql_preamble = sanitize_literals_for_upload(insert_sql_preamble) - for row in rows_list: - sql_params_list.append((insert_sql_preamble, row)) - - return {"sql_params_list": sql_params_list} - - # Case d) - # insert_sql is of the form: - # INSERT INTO T(c1, c2) VALUES (%s, %s), (%s, LOWER(%s)) - - # Sanity check: - # length(all_args) == len(params) - args_len = reduce(lambda a, b: a + b, [len(arg) for arg in values.argv]) - if args_len != len(params): - raise ProgrammingError( - "Invalid length: VALUES(...) len: %d != len(params): %d" - % (args_len, len(params)) - ) - - trim_index = insert_sql.find(after_values_sql[0]) - before_values_sql = insert_sql[:trim_index] - - sql_param_tuples = [] - for token_arg in values.argv: - row_sql = before_values_sql + " VALUES%s" % token_arg - row_sql = sanitize_literals_for_upload(row_sql) - row_params, params = ( - tuple(params[0 : len(token_arg)]), - params[len(token_arg) :], - ) - sql_param_tuples.append((row_sql, row_params)) - - return {"sql_params_list": sql_param_tuples} - - -def rows_for_insert_or_update(columns, params, pyformat_args=None): - """ - Create a tupled list of params to be used as a single value per - value that inserted from a statement such as - SQL: 'INSERT INTO t (f1, f2, f3) VALUES (%s, %s, %s), (%s, %s, %s), (%s, %s, %s)' - Params A: [(1, 2, 3), (4, 5, 6), (7, 8, 9)] - Params B: [1, 2, 3, 4, 5, 6, 7, 8, 9] - - We'll have to convert both params types into: - Params: [(1, 2, 3,), (4, 5, 6,), (7, 8, 9,)] - - :type columns: list - :param columns: A list of the columns of the table. - - :type params: list - :param params: A list of parameters. - - :rtype: list - :returns: A properly restructured list of the parameters. - """ # noqa - if not pyformat_args: - # This is the case where we have for example: - # SQL: 'INSERT INTO t (f1, f2, f3)' - # Params A: [(1, 2, 3), (4, 5, 6), (7, 8, 9)] - # Params B: [1, 2, 3, 4, 5, 6, 7, 8, 9] - # - # We'll have to convert both params types into: - # [(1, 2, 3,), (4, 5, 6,), (7, 8, 9,)] - contains_all_list_or_tuples = True - for param in params: - if not (isinstance(param, list) or isinstance(param, tuple)): - contains_all_list_or_tuples = False - break - - if contains_all_list_or_tuples: - # The case with Params A: [(1, 2, 3), (4, 5, 6)] - # Ensure that each param's length == len(columns) - columns_len = len(columns) - for param in params: - if columns_len != len(param): - raise Error( - "\nlen(`%s`)=%d\n!=\ncolum_len(`%s`)=%d" - % (param, len(param), columns, columns_len) - ) - return params - else: - # The case with Params B: [1, 2, 3] - # Insert statements' params are only passed as tuples or lists, - # yet for do_execute_update, we've got to pass in list of list. - # https://googleapis.dev/python/spanner/latest/transaction-api.html\ - # #google.cloud.spanner_v1.transaction.Transaction.insert - n_stride = len(columns) - else: - # This is the case where we have for example: - # SQL: 'INSERT INTO t (f1, f2, f3) VALUES (%s, %s, %s), - # (%s, %s, %s), (%s, %s, %s)' - # Params: [1, 2, 3, 4, 5, 6, 7, 8, 9] - # which should become - # Columns: (f1, f2, f3) - # new_params: [(1, 2, 3,), (4, 5, 6,), (7, 8, 9,)] - - # Sanity check 1: all the pyformat_values should have the exact same - # length. - first, rest = pyformat_args[0], pyformat_args[1:] - n_stride = first.count("%s") - for pyfmt_value in rest: - n = pyfmt_value.count("%s") - if n_stride != n: - raise Error( - "\nlen(`%s`)=%d\n!=\nlen(`%s`)=%d" - % (first, n_stride, pyfmt_value, n) - ) - - # Sanity check 2: len(params) MUST be a multiple of n_stride aka - # len(count of %s). - # so that we can properly group for example: - # Given pyformat args: - # (%s, %s, %s) - # Params: - # [1, 2, 3, 4, 5, 6, 7, 8, 9] - # into - # [(1, 2, 3), (4, 5, 6), (7, 8, 9)] - if (len(params) % n_stride) != 0: - raise ProgrammingError( - "Invalid length: len(params)=%d MUST be a multiple of " - "len(pyformat_args)=%d" % (len(params), n_stride) - ) - - # Now chop up the strides. - strides = [] - for step in range(0, len(params), n_stride): - stride = tuple(params[step : step + n_stride :]) - strides.append(stride) - - return strides - - def sql_pyformat_args_to_spanner(sql, params): """ Transform pyformat set SQL to named arguments for Cloud Spanner. diff --git a/google/cloud/spanner_v1/services/spanner/async_client.py b/google/cloud/spanner_v1/services/spanner/async_client.py index e831c1c9b4..7721e7610d 100644 --- a/google/cloud/spanner_v1/services/spanner/async_client.py +++ b/google/cloud/spanner_v1/services/spanner/async_client.py @@ -249,9 +249,9 @@ async def create_session( from google.cloud import spanner_v1 - def sample_create_session(): + async def sample_create_session(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.CreateSessionRequest( @@ -259,7 +259,7 @@ def sample_create_session(): ) # Make the request - response = client.create_session(request=request) + response = await client.create_session(request=request) # Handle the response print(response) @@ -355,9 +355,9 @@ async def batch_create_sessions( from google.cloud import spanner_v1 - def sample_batch_create_sessions(): + async def sample_batch_create_sessions(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.BatchCreateSessionsRequest( @@ -366,7 +366,7 @@ def sample_batch_create_sessions(): ) # Make the request - response = client.batch_create_sessions(request=request) + response = await client.batch_create_sessions(request=request) # Handle the response print(response) @@ -476,9 +476,9 @@ async def get_session( from google.cloud import spanner_v1 - def sample_get_session(): + async def sample_get_session(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.GetSessionRequest( @@ -486,7 +486,7 @@ def sample_get_session(): ) # Make the request - response = client.get_session(request=request) + response = await client.get_session(request=request) # Handle the response print(response) @@ -578,9 +578,9 @@ async def list_sessions( from google.cloud import spanner_v1 - def sample_list_sessions(): + async def sample_list_sessions(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.ListSessionsRequest( @@ -591,7 +591,7 @@ def sample_list_sessions(): page_result = client.list_sessions(request=request) # Handle the response - for response in page_result: + async for response in page_result: print(response) Args: @@ -697,9 +697,9 @@ async def delete_session( from google.cloud import spanner_v1 - def sample_delete_session(): + async def sample_delete_session(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.DeleteSessionRequest( @@ -707,7 +707,7 @@ def sample_delete_session(): ) # Make the request - client.delete_session(request=request) + await client.delete_session(request=request) Args: request (Union[google.cloud.spanner_v1.types.DeleteSessionRequest, dict]): @@ -801,9 +801,9 @@ async def execute_sql( from google.cloud import spanner_v1 - def sample_execute_sql(): + async def sample_execute_sql(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.ExecuteSqlRequest( @@ -812,7 +812,7 @@ def sample_execute_sql(): ) # Make the request - response = client.execute_sql(request=request) + response = await client.execute_sql(request=request) # Handle the response print(response) @@ -890,9 +890,9 @@ def execute_streaming_sql( from google.cloud import spanner_v1 - def sample_execute_streaming_sql(): + async def sample_execute_streaming_sql(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.ExecuteSqlRequest( @@ -901,10 +901,10 @@ def sample_execute_streaming_sql(): ) # Make the request - stream = client.execute_streaming_sql(request=request) + stream = await client.execute_streaming_sql(request=request) # Handle the response - for response in stream: + async for response in stream: print(response) Args: @@ -982,9 +982,9 @@ async def execute_batch_dml( from google.cloud import spanner_v1 - def sample_execute_batch_dml(): + async def sample_execute_batch_dml(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) statements = spanner_v1.Statement() @@ -997,7 +997,7 @@ def sample_execute_batch_dml(): ) # Make the request - response = client.execute_batch_dml(request=request) + response = await client.execute_batch_dml(request=request) # Handle the response print(response) @@ -1120,9 +1120,9 @@ async def read( from google.cloud import spanner_v1 - def sample_read(): + async def sample_read(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.ReadRequest( @@ -1132,7 +1132,7 @@ def sample_read(): ) # Make the request - response = client.read(request=request) + response = await client.read(request=request) # Handle the response print(response) @@ -1210,9 +1210,9 @@ def streaming_read( from google.cloud import spanner_v1 - def sample_streaming_read(): + async def sample_streaming_read(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.ReadRequest( @@ -1222,10 +1222,10 @@ def sample_streaming_read(): ) # Make the request - stream = client.streaming_read(request=request) + stream = await client.streaming_read(request=request) # Handle the response - for response in stream: + async for response in stream: print(response) Args: @@ -1296,9 +1296,9 @@ async def begin_transaction( from google.cloud import spanner_v1 - def sample_begin_transaction(): + async def sample_begin_transaction(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.BeginTransactionRequest( @@ -1306,7 +1306,7 @@ def sample_begin_transaction(): ) # Make the request - response = client.begin_transaction(request=request) + response = await client.begin_transaction(request=request) # Handle the response print(response) @@ -1425,9 +1425,9 @@ async def commit( from google.cloud import spanner_v1 - def sample_commit(): + async def sample_commit(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.CommitRequest( @@ -1436,7 +1436,7 @@ def sample_commit(): ) # Make the request - response = client.commit(request=request) + response = await client.commit(request=request) # Handle the response print(response) @@ -1579,9 +1579,9 @@ async def rollback( from google.cloud import spanner_v1 - def sample_rollback(): + async def sample_rollback(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.RollbackRequest( @@ -1590,7 +1590,7 @@ def sample_rollback(): ) # Make the request - client.rollback(request=request) + await client.rollback(request=request) Args: request (Union[google.cloud.spanner_v1.types.RollbackRequest, dict]): @@ -1693,9 +1693,9 @@ async def partition_query( from google.cloud import spanner_v1 - def sample_partition_query(): + async def sample_partition_query(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.PartitionQueryRequest( @@ -1704,7 +1704,7 @@ def sample_partition_query(): ) # Make the request - response = client.partition_query(request=request) + response = await client.partition_query(request=request) # Handle the response print(response) @@ -1793,9 +1793,9 @@ async def partition_read( from google.cloud import spanner_v1 - def sample_partition_read(): + async def sample_partition_read(): # Create a client - client = spanner_v1.SpannerClient() + client = spanner_v1.SpannerAsyncClient() # Initialize request argument(s) request = spanner_v1.PartitionReadRequest( @@ -1804,7 +1804,7 @@ def sample_partition_read(): ) # Make the request - response = client.partition_read(request=request) + response = await client.partition_read(request=request) # Handle the response print(response) diff --git a/noxfile.py b/noxfile.py index efe3b70104..57a4a1d179 100644 --- a/noxfile.py +++ b/noxfile.py @@ -25,7 +25,8 @@ import nox BLACK_VERSION = "black==22.3.0" -BLACK_PATHS = ["docs", "google", "tests", "noxfile.py", "setup.py"] +ISORT_VERSION = "isort==5.10.1" +LINT_PATHS = ["docs", "google", "tests", "noxfile.py", "setup.py"] DEFAULT_PYTHON_VERSION = "3.8" @@ -85,7 +86,7 @@ def lint(session): session.run( "black", "--check", - *BLACK_PATHS, + *LINT_PATHS, ) session.run("flake8", "google", "tests") @@ -96,7 +97,27 @@ def blacken(session): session.install(BLACK_VERSION) session.run( "black", - *BLACK_PATHS, + *LINT_PATHS, + ) + + +@nox.session(python=DEFAULT_PYTHON_VERSION) +def format(session): + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run( + "isort", + "--fss", + *LINT_PATHS, + ) + session.run( + "black", + *LINT_PATHS, ) diff --git a/samples/samples/noxfile.py b/samples/samples/noxfile.py index 949e0fde9a..38bb0a572b 100644 --- a/samples/samples/noxfile.py +++ b/samples/samples/noxfile.py @@ -30,6 +30,7 @@ # WARNING - WARNING - WARNING - WARNING - WARNING BLACK_VERSION = "black==22.3.0" +ISORT_VERSION = "isort==5.10.1" # Copy `noxfile_config.py` to your directory and modify it instead. @@ -168,12 +169,32 @@ def lint(session: nox.sessions.Session) -> None: @nox.session def blacken(session: nox.sessions.Session) -> None: + """Run black. Format code to uniform standard.""" session.install(BLACK_VERSION) python_files = [path for path in os.listdir(".") if path.endswith(".py")] session.run("black", *python_files) +# +# format = isort + black +# + +@nox.session +def format(session: nox.sessions.Session) -> None: + """ + Run isort to sort imports. Then run black + to format code to uniform standard. + """ + session.install(BLACK_VERSION, ISORT_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + # Use the --fss option to sort imports using strict alphabetical order. + # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections + session.run("isort", "--fss", *python_files) + session.run("black", *python_files) + + # # Sample Tests # diff --git a/samples/samples/requirements-test.txt b/samples/samples/requirements-test.txt index 3d42f3a24a..dcaba12c6d 100644 --- a/samples/samples/requirements-test.txt +++ b/samples/samples/requirements-test.txt @@ -1,4 +1,4 @@ -pytest==7.1.1 +pytest==7.1.2 pytest-dependency==0.5.1 mock==4.0.3 google-cloud-testutils==1.3.1 diff --git a/samples/samples/requirements.txt b/samples/samples/requirements.txt index c2b585853e..3ecc9eb46d 100644 --- a/samples/samples/requirements.txt +++ b/samples/samples/requirements.txt @@ -1,2 +1,2 @@ -google-cloud-spanner==3.13.0 +google-cloud-spanner==3.14.0 futures==3.3.0; python_version < "3" diff --git a/scripts/readme-gen/readme_gen.py b/scripts/readme-gen/readme_gen.py index d309d6e975..91b59676bf 100644 --- a/scripts/readme-gen/readme_gen.py +++ b/scripts/readme-gen/readme_gen.py @@ -28,7 +28,10 @@ jinja_env = jinja2.Environment( trim_blocks=True, loader=jinja2.FileSystemLoader( - os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')))) + os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + ), + autoescape=True, +) README_TMPL = jinja_env.get_template('README.tmpl.rst') diff --git a/setup.py b/setup.py index 28fd020ab5..69489023ce 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ name = "google-cloud-spanner" description = "Cloud Spanner API client library" -version = "3.14.0" +version = "3.14.1" # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' @@ -38,9 +38,10 @@ # https://github.com/googleapis/google-cloud-python/issues/10566 "google-cloud-core >= 1.4.1, < 3.0dev", "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", - "proto-plus >= 1.15.0, != 1.19.6", + "proto-plus >= 1.15.0, <2.0.0dev, != 1.19.6", "sqlparse >= 0.3.0", "packaging >= 14.3", + "protobuf >= 3.19.0, <4.0.0dev", ] extras = { "tracing": [ diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index 4c581a9373..81c7b183a9 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -15,3 +15,4 @@ opentelemetry-api==1.1.0 opentelemetry-sdk==1.1.0 opentelemetry-instrumentation==0.20b0 packaging==14.3 +protobuf==3.19.0 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index e69de29bb2..81c7b183a9 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -0,0 +1,18 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List *all* library dependencies and extras in this file. +# Pin the version to the lower bound. +# +# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", +# Then this file should have foo==1.14.0 +google-api-core==1.31.5 +google-cloud-core==1.4.1 +grpc-google-iam-v1==0.12.4 +libcst==0.2.5 +proto-plus==1.15.0 +sqlparse==0.3.0 +opentelemetry-api==1.1.0 +opentelemetry-sdk==1.1.0 +opentelemetry-instrumentation==0.20b0 +packaging==14.3 +protobuf==3.19.0 diff --git a/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py b/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py index bf1a442f66..de001b2663 100644 --- a/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py +++ b/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py @@ -14,7 +14,13 @@ # limitations under the License. # import os -import mock + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock +except ImportError: + import mock import grpc from grpc.experimental import aio @@ -768,7 +774,7 @@ def test_list_databases_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.ListDatabasesRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_databases), "__call__") as call: @@ -784,7 +790,7 @@ def test_list_databases_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -798,7 +804,7 @@ async def test_list_databases_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.ListDatabasesRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_databases), "__call__") as call: @@ -816,7 +822,7 @@ async def test_list_databases_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -947,7 +953,7 @@ def test_list_databases_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, spanner_database_admin.Database) for i in results) @@ -1183,7 +1189,7 @@ def test_create_database_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.CreateDatabaseRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_database), "__call__") as call: @@ -1199,7 +1205,7 @@ def test_create_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -1213,7 +1219,7 @@ async def test_create_database_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.CreateDatabaseRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_database), "__call__") as call: @@ -1231,7 +1237,7 @@ async def test_create_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -1442,7 +1448,7 @@ def test_get_database_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.GetDatabaseRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_database), "__call__") as call: @@ -1458,7 +1464,7 @@ def test_get_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1472,7 +1478,7 @@ async def test_get_database_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.GetDatabaseRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_database), "__call__") as call: @@ -1490,7 +1496,7 @@ async def test_get_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1675,7 +1681,7 @@ def test_update_database_ddl_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.UpdateDatabaseDdlRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1693,7 +1699,7 @@ def test_update_database_ddl_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1707,7 +1713,7 @@ async def test_update_database_ddl_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.UpdateDatabaseDdlRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1727,7 +1733,7 @@ async def test_update_database_ddl_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1918,7 +1924,7 @@ def test_drop_database_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.DropDatabaseRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.drop_database), "__call__") as call: @@ -1934,7 +1940,7 @@ def test_drop_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1948,7 +1954,7 @@ async def test_drop_database_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.DropDatabaseRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.drop_database), "__call__") as call: @@ -1964,7 +1970,7 @@ async def test_drop_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -2147,7 +2153,7 @@ def test_get_database_ddl_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.GetDatabaseDdlRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_database_ddl), "__call__") as call: @@ -2163,7 +2169,7 @@ def test_get_database_ddl_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -2177,7 +2183,7 @@ async def test_get_database_ddl_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.GetDatabaseDdlRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_database_ddl), "__call__") as call: @@ -2195,7 +2201,7 @@ async def test_get_database_ddl_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -2383,7 +2389,7 @@ def test_set_iam_policy_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.SetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: @@ -2399,7 +2405,7 @@ def test_set_iam_policy_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2413,7 +2419,7 @@ async def test_set_iam_policy_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.SetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: @@ -2429,7 +2435,7 @@ async def test_set_iam_policy_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2633,7 +2639,7 @@ def test_get_iam_policy_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.GetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: @@ -2649,7 +2655,7 @@ def test_get_iam_policy_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2663,7 +2669,7 @@ async def test_get_iam_policy_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.GetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: @@ -2679,7 +2685,7 @@ async def test_get_iam_policy_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2885,7 +2891,7 @@ def test_test_iam_permissions_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.TestIamPermissionsRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2903,7 +2909,7 @@ def test_test_iam_permissions_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2917,7 +2923,7 @@ async def test_test_iam_permissions_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.TestIamPermissionsRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2937,7 +2943,7 @@ async def test_test_iam_permissions_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -3148,7 +3154,7 @@ def test_create_backup_field_headers(): # a field header. Set these to a non-empty value. request = gsad_backup.CreateBackupRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_backup), "__call__") as call: @@ -3164,7 +3170,7 @@ def test_create_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -3178,7 +3184,7 @@ async def test_create_backup_field_headers_async(): # a field header. Set these to a non-empty value. request = gsad_backup.CreateBackupRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_backup), "__call__") as call: @@ -3196,7 +3202,7 @@ async def test_create_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -3394,7 +3400,7 @@ def test_copy_backup_field_headers(): # a field header. Set these to a non-empty value. request = backup.CopyBackupRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.copy_backup), "__call__") as call: @@ -3410,7 +3416,7 @@ def test_copy_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -3424,7 +3430,7 @@ async def test_copy_backup_field_headers_async(): # a field header. Set these to a non-empty value. request = backup.CopyBackupRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.copy_backup), "__call__") as call: @@ -3442,7 +3448,7 @@ async def test_copy_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -3680,7 +3686,7 @@ def test_get_backup_field_headers(): # a field header. Set these to a non-empty value. request = backup.GetBackupRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_backup), "__call__") as call: @@ -3696,7 +3702,7 @@ def test_get_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -3710,7 +3716,7 @@ async def test_get_backup_field_headers_async(): # a field header. Set these to a non-empty value. request = backup.GetBackupRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_backup), "__call__") as call: @@ -3726,7 +3732,7 @@ async def test_get_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -3932,7 +3938,7 @@ def test_update_backup_field_headers(): # a field header. Set these to a non-empty value. request = gsad_backup.UpdateBackupRequest() - request.backup.name = "backup.name/value" + request.backup.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_backup), "__call__") as call: @@ -3948,7 +3954,7 @@ def test_update_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "backup.name=backup.name/value", + "backup.name=name_value", ) in kw["metadata"] @@ -3962,7 +3968,7 @@ async def test_update_backup_field_headers_async(): # a field header. Set these to a non-empty value. request = gsad_backup.UpdateBackupRequest() - request.backup.name = "backup.name/value" + request.backup.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_backup), "__call__") as call: @@ -3978,7 +3984,7 @@ async def test_update_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "backup.name=backup.name/value", + "backup.name=name_value", ) in kw["metadata"] @@ -4162,7 +4168,7 @@ def test_delete_backup_field_headers(): # a field header. Set these to a non-empty value. request = backup.DeleteBackupRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: @@ -4178,7 +4184,7 @@ def test_delete_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -4192,7 +4198,7 @@ async def test_delete_backup_field_headers_async(): # a field header. Set these to a non-empty value. request = backup.DeleteBackupRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: @@ -4208,7 +4214,7 @@ async def test_delete_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -4390,7 +4396,7 @@ def test_list_backups_field_headers(): # a field header. Set these to a non-empty value. request = backup.ListBackupsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_backups), "__call__") as call: @@ -4406,7 +4412,7 @@ def test_list_backups_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -4420,7 +4426,7 @@ async def test_list_backups_field_headers_async(): # a field header. Set these to a non-empty value. request = backup.ListBackupsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_backups), "__call__") as call: @@ -4438,7 +4444,7 @@ async def test_list_backups_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -4569,7 +4575,7 @@ def test_list_backups_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, backup.Backup) for i in results) @@ -4805,7 +4811,7 @@ def test_restore_database_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.RestoreDatabaseRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.restore_database), "__call__") as call: @@ -4821,7 +4827,7 @@ def test_restore_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -4835,7 +4841,7 @@ async def test_restore_database_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.RestoreDatabaseRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.restore_database), "__call__") as call: @@ -4853,7 +4859,7 @@ async def test_restore_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -5060,7 +5066,7 @@ def test_list_database_operations_field_headers(): # a field header. Set these to a non-empty value. request = spanner_database_admin.ListDatabaseOperationsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -5078,7 +5084,7 @@ def test_list_database_operations_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -5092,7 +5098,7 @@ async def test_list_database_operations_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_database_admin.ListDatabaseOperationsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -5112,7 +5118,7 @@ async def test_list_database_operations_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -5249,7 +5255,7 @@ def test_list_database_operations_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, operations_pb2.Operation) for i in results) @@ -5502,7 +5508,7 @@ def test_list_backup_operations_field_headers(): # a field header. Set these to a non-empty value. request = backup.ListBackupOperationsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -5520,7 +5526,7 @@ def test_list_backup_operations_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -5534,7 +5540,7 @@ async def test_list_backup_operations_field_headers_async(): # a field header. Set these to a non-empty value. request = backup.ListBackupOperationsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -5554,7 +5560,7 @@ async def test_list_backup_operations_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -5691,7 +5697,7 @@ def test_list_backup_operations_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, operations_pb2.Operation) for i in results) diff --git a/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py b/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py index 59e7134f41..7d96090b8f 100644 --- a/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py +++ b/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py @@ -14,7 +14,13 @@ # limitations under the License. # import os -import mock + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock +except ImportError: + import mock import grpc from grpc.experimental import aio @@ -767,7 +773,7 @@ def test_list_instance_configs_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.ListInstanceConfigsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -785,7 +791,7 @@ def test_list_instance_configs_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -799,7 +805,7 @@ async def test_list_instance_configs_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.ListInstanceConfigsRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -819,7 +825,7 @@ async def test_list_instance_configs_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -956,7 +962,7 @@ def test_list_instance_configs_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all( isinstance(i, spanner_instance_admin.InstanceConfig) for i in results @@ -1222,7 +1228,7 @@ def test_get_instance_config_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.GetInstanceConfigRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1240,7 +1246,7 @@ def test_get_instance_config_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1254,7 +1260,7 @@ async def test_get_instance_config_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.GetInstanceConfigRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -1274,7 +1280,7 @@ async def test_get_instance_config_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1463,7 +1469,7 @@ def test_list_instances_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.ListInstancesRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_instances), "__call__") as call: @@ -1479,7 +1485,7 @@ def test_list_instances_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -1493,7 +1499,7 @@ async def test_list_instances_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.ListInstancesRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_instances), "__call__") as call: @@ -1511,7 +1517,7 @@ async def test_list_instances_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -1642,7 +1648,7 @@ def test_list_instances_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, spanner_instance_admin.Instance) for i in results) @@ -1908,7 +1914,7 @@ def test_get_instance_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.GetInstanceRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_instance), "__call__") as call: @@ -1924,7 +1930,7 @@ def test_get_instance_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1938,7 +1944,7 @@ async def test_get_instance_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.GetInstanceRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_instance), "__call__") as call: @@ -1956,7 +1962,7 @@ async def test_get_instance_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -2135,7 +2141,7 @@ def test_create_instance_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.CreateInstanceRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_instance), "__call__") as call: @@ -2151,7 +2157,7 @@ def test_create_instance_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -2165,7 +2171,7 @@ async def test_create_instance_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.CreateInstanceRequest() - request.parent = "parent/value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_instance), "__call__") as call: @@ -2183,7 +2189,7 @@ async def test_create_instance_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent/value", + "parent=parent_value", ) in kw["metadata"] @@ -2382,7 +2388,7 @@ def test_update_instance_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.UpdateInstanceRequest() - request.instance.name = "instance.name/value" + request.instance.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_instance), "__call__") as call: @@ -2398,7 +2404,7 @@ def test_update_instance_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "instance.name=instance.name/value", + "instance.name=name_value", ) in kw["metadata"] @@ -2412,7 +2418,7 @@ async def test_update_instance_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.UpdateInstanceRequest() - request.instance.name = "instance.name/value" + request.instance.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_instance), "__call__") as call: @@ -2430,7 +2436,7 @@ async def test_update_instance_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "instance.name=instance.name/value", + "instance.name=name_value", ) in kw["metadata"] @@ -2617,7 +2623,7 @@ def test_delete_instance_field_headers(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.DeleteInstanceRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_instance), "__call__") as call: @@ -2633,7 +2639,7 @@ def test_delete_instance_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -2647,7 +2653,7 @@ async def test_delete_instance_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner_instance_admin.DeleteInstanceRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_instance), "__call__") as call: @@ -2663,7 +2669,7 @@ async def test_delete_instance_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -2849,7 +2855,7 @@ def test_set_iam_policy_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.SetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: @@ -2865,7 +2871,7 @@ def test_set_iam_policy_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -2879,7 +2885,7 @@ async def test_set_iam_policy_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.SetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.set_iam_policy), "__call__") as call: @@ -2895,7 +2901,7 @@ async def test_set_iam_policy_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -3099,7 +3105,7 @@ def test_get_iam_policy_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.GetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: @@ -3115,7 +3121,7 @@ def test_get_iam_policy_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -3129,7 +3135,7 @@ async def test_get_iam_policy_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.GetIamPolicyRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_iam_policy), "__call__") as call: @@ -3145,7 +3151,7 @@ async def test_get_iam_policy_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -3351,7 +3357,7 @@ def test_test_iam_permissions_field_headers(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.TestIamPermissionsRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -3369,7 +3375,7 @@ def test_test_iam_permissions_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] @@ -3383,7 +3389,7 @@ async def test_test_iam_permissions_field_headers_async(): # a field header. Set these to a non-empty value. request = iam_policy_pb2.TestIamPermissionsRequest() - request.resource = "resource/value" + request.resource = "resource_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -3403,7 +3409,7 @@ async def test_test_iam_permissions_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "resource=resource/value", + "resource=resource_value", ) in kw["metadata"] diff --git a/tests/unit/gapic/spanner_v1/test_spanner.py b/tests/unit/gapic/spanner_v1/test_spanner.py index d4df289e48..f2b1471240 100644 --- a/tests/unit/gapic/spanner_v1/test_spanner.py +++ b/tests/unit/gapic/spanner_v1/test_spanner.py @@ -14,7 +14,13 @@ # limitations under the License. # import os -import mock + +# try/except added for compatibility with python < 3.8 +try: + from unittest import mock + from unittest.mock import AsyncMock +except ImportError: + import mock import grpc from grpc.experimental import aio @@ -712,7 +718,7 @@ def test_create_session_field_headers(): # a field header. Set these to a non-empty value. request = spanner.CreateSessionRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_session), "__call__") as call: @@ -728,7 +734,7 @@ def test_create_session_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -742,7 +748,7 @@ async def test_create_session_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.CreateSessionRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_session), "__call__") as call: @@ -758,7 +764,7 @@ async def test_create_session_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -940,7 +946,7 @@ def test_batch_create_sessions_field_headers(): # a field header. Set these to a non-empty value. request = spanner.BatchCreateSessionsRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -958,7 +964,7 @@ def test_batch_create_sessions_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -972,7 +978,7 @@ async def test_batch_create_sessions_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.BatchCreateSessionsRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -992,7 +998,7 @@ async def test_batch_create_sessions_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1190,7 +1196,7 @@ def test_get_session_field_headers(): # a field header. Set these to a non-empty value. request = spanner.GetSessionRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_session), "__call__") as call: @@ -1206,7 +1212,7 @@ def test_get_session_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1220,7 +1226,7 @@ async def test_get_session_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.GetSessionRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_session), "__call__") as call: @@ -1236,7 +1242,7 @@ async def test_get_session_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1418,7 +1424,7 @@ def test_list_sessions_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ListSessionsRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_sessions), "__call__") as call: @@ -1434,7 +1440,7 @@ def test_list_sessions_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1448,7 +1454,7 @@ async def test_list_sessions_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ListSessionsRequest() - request.database = "database/value" + request.database = "database_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_sessions), "__call__") as call: @@ -1466,7 +1472,7 @@ async def test_list_sessions_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database=database/value", + "database=database_value", ) in kw["metadata"] @@ -1597,7 +1603,7 @@ def test_list_sessions_pager(transport_name: str = "grpc"): assert pager._metadata == metadata - results = [i for i in pager] + results = list(pager) assert len(results) == 6 assert all(isinstance(i, spanner.Session) for i in results) @@ -1830,7 +1836,7 @@ def test_delete_session_field_headers(): # a field header. Set these to a non-empty value. request = spanner.DeleteSessionRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_session), "__call__") as call: @@ -1846,7 +1852,7 @@ def test_delete_session_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -1860,7 +1866,7 @@ async def test_delete_session_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.DeleteSessionRequest() - request.name = "name/value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_session), "__call__") as call: @@ -1876,7 +1882,7 @@ async def test_delete_session_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name/value", + "name=name_value", ) in kw["metadata"] @@ -2052,7 +2058,7 @@ def test_execute_sql_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ExecuteSqlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.execute_sql), "__call__") as call: @@ -2068,7 +2074,7 @@ def test_execute_sql_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2082,7 +2088,7 @@ async def test_execute_sql_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ExecuteSqlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.execute_sql), "__call__") as call: @@ -2100,7 +2106,7 @@ async def test_execute_sql_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2205,7 +2211,7 @@ def test_execute_streaming_sql_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ExecuteSqlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2223,7 +2229,7 @@ def test_execute_streaming_sql_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2237,7 +2243,7 @@ async def test_execute_streaming_sql_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ExecuteSqlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2258,7 +2264,7 @@ async def test_execute_streaming_sql_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2360,7 +2366,7 @@ def test_execute_batch_dml_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ExecuteBatchDmlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2378,7 +2384,7 @@ def test_execute_batch_dml_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2392,7 +2398,7 @@ async def test_execute_batch_dml_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ExecuteBatchDmlRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2412,7 +2418,7 @@ async def test_execute_batch_dml_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2508,7 +2514,7 @@ def test_read_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.read), "__call__") as call: @@ -2524,7 +2530,7 @@ def test_read_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2538,7 +2544,7 @@ async def test_read_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.read), "__call__") as call: @@ -2556,7 +2562,7 @@ async def test_read_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2655,7 +2661,7 @@ def test_streaming_read_field_headers(): # a field header. Set these to a non-empty value. request = spanner.ReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.streaming_read), "__call__") as call: @@ -2671,7 +2677,7 @@ def test_streaming_read_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2685,7 +2691,7 @@ async def test_streaming_read_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.ReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.streaming_read), "__call__") as call: @@ -2704,7 +2710,7 @@ async def test_streaming_read_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2812,7 +2818,7 @@ def test_begin_transaction_field_headers(): # a field header. Set these to a non-empty value. request = spanner.BeginTransactionRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2830,7 +2836,7 @@ def test_begin_transaction_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -2844,7 +2850,7 @@ async def test_begin_transaction_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.BeginTransactionRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( @@ -2864,7 +2870,7 @@ async def test_begin_transaction_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3056,7 +3062,7 @@ def test_commit_field_headers(): # a field header. Set these to a non-empty value. request = spanner.CommitRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.commit), "__call__") as call: @@ -3072,7 +3078,7 @@ def test_commit_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3086,7 +3092,7 @@ async def test_commit_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.CommitRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.commit), "__call__") as call: @@ -3104,7 +3110,7 @@ async def test_commit_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3316,7 +3322,7 @@ def test_rollback_field_headers(): # a field header. Set these to a non-empty value. request = spanner.RollbackRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.rollback), "__call__") as call: @@ -3332,7 +3338,7 @@ def test_rollback_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3346,7 +3352,7 @@ async def test_rollback_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.RollbackRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.rollback), "__call__") as call: @@ -3362,7 +3368,7 @@ async def test_rollback_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3548,7 +3554,7 @@ def test_partition_query_field_headers(): # a field header. Set these to a non-empty value. request = spanner.PartitionQueryRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_query), "__call__") as call: @@ -3564,7 +3570,7 @@ def test_partition_query_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3578,7 +3584,7 @@ async def test_partition_query_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.PartitionQueryRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_query), "__call__") as call: @@ -3596,7 +3602,7 @@ async def test_partition_query_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3692,7 +3698,7 @@ def test_partition_read_field_headers(): # a field header. Set these to a non-empty value. request = spanner.PartitionReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_read), "__call__") as call: @@ -3708,7 +3714,7 @@ def test_partition_read_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] @@ -3722,7 +3728,7 @@ async def test_partition_read_field_headers_async(): # a field header. Set these to a non-empty value. request = spanner.PartitionReadRequest() - request.session = "session/value" + request.session = "session_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_read), "__call__") as call: @@ -3740,7 +3746,7 @@ async def test_partition_read_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "session=session/value", + "session=session_value", ) in kw["metadata"] diff --git a/tests/unit/spanner_dbapi/test__helpers.py b/tests/unit/spanner_dbapi/test__helpers.py index 84d6b3e323..1782978d62 100644 --- a/tests/unit/spanner_dbapi/test__helpers.py +++ b/tests/unit/spanner_dbapi/test__helpers.py @@ -32,23 +32,37 @@ def test__execute_insert_heterogenous(self): "google.cloud.spanner_dbapi._helpers.get_param_types", return_value=None ) as mock_param_types: transaction = mock.MagicMock() - transaction.execute_update = mock_execute = mock.MagicMock() - _helpers._execute_insert_heterogenous(transaction, [params]) + transaction.execute_update = mock_update = mock.MagicMock() + _helpers._execute_insert_heterogenous(transaction, (params,)) mock_pyformat.assert_called_once_with(params[0], params[1]) mock_param_types.assert_called_once_with(None) - mock_execute.assert_called_once_with(sql, params=None, param_types=None) + mock_update.assert_called_once_with(sql, None, None) - def test__execute_insert_homogenous(self): + def test__execute_insert_heterogenous_error(self): from google.cloud.spanner_dbapi import _helpers + from google.api_core.exceptions import Unknown - transaction = mock.MagicMock() - transaction.insert = mock.MagicMock() - parts = mock.MagicMock() - parts.get = mock.MagicMock(return_value=0) + sql = "sql" + params = (sql, None) + with mock.patch( + "google.cloud.spanner_dbapi._helpers.sql_pyformat_args_to_spanner", + return_value=params, + ) as mock_pyformat: + with mock.patch( + "google.cloud.spanner_dbapi._helpers.get_param_types", return_value=None + ) as mock_param_types: + transaction = mock.MagicMock() + transaction.execute_update = mock_update = mock.MagicMock( + side_effect=Unknown("Unknown") + ) - _helpers._execute_insert_homogenous(transaction, parts) - transaction.insert.assert_called_once_with(0, 0, 0) + with self.assertRaises(Unknown): + _helpers._execute_insert_heterogenous(transaction, (params,)) + + mock_pyformat.assert_called_once_with(params[0], params[1]) + mock_param_types.assert_called_once_with(None) + mock_update.assert_called_once_with(sql, None, None) def test_handle_insert(self): from google.cloud.spanner_dbapi import _helpers @@ -56,19 +70,13 @@ def test_handle_insert(self): connection = mock.MagicMock() connection.database.run_in_transaction = mock_run_in = mock.MagicMock() sql = "sql" - parts = mock.MagicMock() - with mock.patch( - "google.cloud.spanner_dbapi._helpers.parse_insert", return_value=parts - ): - parts.get = mock.MagicMock(return_value=True) - mock_run_in.return_value = 0 - result = _helpers.handle_insert(connection, sql, None) - self.assertEqual(result, 0) - - parts.get = mock.MagicMock(return_value=False) - mock_run_in.return_value = 1 - result = _helpers.handle_insert(connection, sql, None) - self.assertEqual(result, 1) + mock_run_in.return_value = 0 + result = _helpers.handle_insert(connection, sql, None) + self.assertEqual(result, 0) + + mock_run_in.return_value = 1 + result = _helpers.handle_insert(connection, sql, None) + self.assertEqual(result, 1) class TestColumnInfo(unittest.TestCase): diff --git a/tests/unit/spanner_dbapi/test_connection.py b/tests/unit/spanner_dbapi/test_connection.py index 7902de6405..e15f6af33b 100644 --- a/tests/unit/spanner_dbapi/test_connection.py +++ b/tests/unit/spanner_dbapi/test_connection.py @@ -392,13 +392,17 @@ def test_run_statement_w_heterogenous_insert_statements(self): """Check that Connection executed heterogenous insert statements.""" from google.cloud.spanner_dbapi.checksum import ResultsChecksum from google.cloud.spanner_dbapi.cursor import Statement + from google.rpc.status_pb2 import Status + from google.rpc.code_pb2 import OK sql = "INSERT INTO T (f1, f2) VALUES (1, 2)" params = None param_types = None connection = self._make_connection() - connection.transaction_checkout = mock.Mock() + transaction = mock.MagicMock() + connection.transaction_checkout = mock.Mock(return_value=transaction) + transaction.batch_update = mock.Mock(return_value=(Status(code=OK), 1)) statement = Statement(sql, params, param_types, ResultsChecksum(), True) connection.run_statement(statement, retried=True) @@ -409,13 +413,17 @@ def test_run_statement_w_homogeneous_insert_statements(self): """Check that Connection executed homogeneous insert statements.""" from google.cloud.spanner_dbapi.checksum import ResultsChecksum from google.cloud.spanner_dbapi.cursor import Statement + from google.rpc.status_pb2 import Status + from google.rpc.code_pb2 import OK sql = "INSERT INTO T (f1, f2) VALUES (%s, %s), (%s, %s)" params = ["a", "b", "c", "d"] param_types = {"f1": str, "f2": str} connection = self._make_connection() - connection.transaction_checkout = mock.Mock() + transaction = mock.MagicMock() + connection.transaction_checkout = mock.Mock(return_value=transaction) + transaction.batch_update = mock.Mock(return_value=(Status(code=OK), 1)) statement = Statement(sql, params, param_types, ResultsChecksum(), True) connection.run_statement(statement, retried=True) diff --git a/tests/unit/spanner_dbapi/test_cursor.py b/tests/unit/spanner_dbapi/test_cursor.py index 71e4a96d6e..3f379f96ac 100644 --- a/tests/unit/spanner_dbapi/test_cursor.py +++ b/tests/unit/spanner_dbapi/test_cursor.py @@ -564,7 +564,7 @@ def test_executemany_insert_batch_aborted(self): transaction1 = mock.Mock(committed=False, rolled_back=False) transaction1.batch_update = mock.Mock( - side_effect=[(mock.Mock(code=ABORTED, details=err_details), [])] + side_effect=[(mock.Mock(code=ABORTED, message=err_details), [])] ) transaction2 = self._transaction_mock() @@ -732,15 +732,6 @@ def test_setoutputsize(self): with self.assertRaises(exceptions.InterfaceError): cursor.setoutputsize(size=None) - # def test_handle_insert(self): - # pass - # - # def test_do_execute_insert_heterogenous(self): - # pass - # - # def test_do_execute_insert_homogenous(self): - # pass - def test_handle_dql(self): from google.cloud.spanner_dbapi import utils from google.cloud.spanner_dbapi.cursor import _UNSET_COUNT diff --git a/tests/unit/spanner_dbapi/test_parse_utils.py b/tests/unit/spanner_dbapi/test_parse_utils.py index b0f363299b..511ad838cf 100644 --- a/tests/unit/spanner_dbapi/test_parse_utils.py +++ b/tests/unit/spanner_dbapi/test_parse_utils.py @@ -61,199 +61,6 @@ def test_classify_stmt(self): for query, want_class in cases: self.assertEqual(classify_stmt(query), want_class) - @unittest.skipIf(skip_condition, skip_message) - def test_parse_insert(self): - from google.cloud.spanner_dbapi.parse_utils import parse_insert - from google.cloud.spanner_dbapi.exceptions import ProgrammingError - - with self.assertRaises(ProgrammingError): - parse_insert("bad-sql", None) - - cases = [ - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)", - [1, 2, 3, 4, 5, 6], - { - "sql_params_list": [ - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)", - (1, 2, 3), - ), - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)", - (4, 5, 6), - ), - ] - }, - ), - ( - "INSERT INTO django_migrations(app, name, applied) VALUES (%s, %s, %s)", - [1, 2, 3, 4, 5, 6], - { - "sql_params_list": [ - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)", - (1, 2, 3), - ), - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)", - (4, 5, 6), - ), - ] - }, - ), - ( - "INSERT INTO sales.addresses (street, city, state, zip_code) " - "SELECT street, city, state, zip_code FROM sales.customers" - "ORDER BY first_name, last_name", - None, - { - "sql_params_list": [ - ( - "INSERT INTO sales.addresses (street, city, state, zip_code) " - "SELECT street, city, state, zip_code FROM sales.customers" - "ORDER BY first_name, last_name", - None, - ) - ] - }, - ), - ( - "INSERT INTO ap (n, ct, cn) " - "VALUES (%s, %s, %s), (%s, %s, %s), (%s, %s, %s),(%s, %s, %s)", - (1, 2, 3, 4, 5, 6, 7, 8, 9), - { - "sql_params_list": [ - ("INSERT INTO ap (n, ct, cn) VALUES (%s, %s, %s)", (1, 2, 3)), - ("INSERT INTO ap (n, ct, cn) VALUES (%s, %s, %s)", (4, 5, 6)), - ("INSERT INTO ap (n, ct, cn) VALUES (%s, %s, %s)", (7, 8, 9)), - ] - }, - ), - ( - "INSERT INTO `no` (`yes`) VALUES (%s)", - (1, 4, 5), - { - "sql_params_list": [ - ("INSERT INTO `no` (`yes`) VALUES (%s)", (1,)), - ("INSERT INTO `no` (`yes`) VALUES (%s)", (4,)), - ("INSERT INTO `no` (`yes`) VALUES (%s)", (5,)), - ] - }, - ), - ( - "INSERT INTO T (f1, f2) VALUES (1, 2)", - None, - {"sql_params_list": [("INSERT INTO T (f1, f2) VALUES (1, 2)", None)]}, - ), - ( - "INSERT INTO `no` (`yes`, tiff) VALUES (%s, LOWER(%s)), (%s, %s), (%s, %s)", - (1, "FOO", 5, 10, 11, 29), - { - "sql_params_list": [ - ( - "INSERT INTO `no` (`yes`, tiff) VALUES(%s, LOWER(%s))", - (1, "FOO"), - ), - ("INSERT INTO `no` (`yes`, tiff) VALUES(%s, %s)", (5, 10)), - ("INSERT INTO `no` (`yes`, tiff) VALUES(%s, %s)", (11, 29)), - ] - }, - ), - ] - - sql = "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s)" - with self.assertRaises(ProgrammingError): - parse_insert(sql, None) - - for sql, params, want in cases: - with self.subTest(sql=sql): - got = parse_insert(sql, params) - self.assertEqual(got, want, "Mismatch with parse_insert of `%s`" % sql) - - @unittest.skipIf(skip_condition, skip_message) - def test_parse_insert_invalid(self): - from google.cloud.spanner_dbapi import exceptions - from google.cloud.spanner_dbapi.parse_utils import parse_insert - - cases = [ - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s), (%s, %s, %s)", - [1, 2, 3, 4, 5, 6, 7], - "len\\(params\\)=7 MUST be a multiple of len\\(pyformat_args\\)=3", - ), - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s), (%s, %s, LOWER(%s))", - [1, 2, 3, 4, 5, 6, 7], - "Invalid length: VALUES\\(...\\) len: 6 != len\\(params\\): 7", - ), - ( - "INSERT INTO django_migrations (app, name, applied) VALUES (%s, %s, %s), (%s, %s, LOWER(%s)))", - [1, 2, 3, 4, 5, 6], - "VALUES: expected `,` got \\) in \\)", - ), - ] - - for sql, params, wantException in cases: - with self.subTest(sql=sql): - self.assertRaisesRegex( - exceptions.ProgrammingError, - wantException, - lambda: parse_insert(sql, params), - ) - - @unittest.skipIf(skip_condition, skip_message) - def test_rows_for_insert_or_update(self): - from google.cloud.spanner_dbapi.parse_utils import rows_for_insert_or_update - from google.cloud.spanner_dbapi.exceptions import Error - - with self.assertRaises(Error): - rows_for_insert_or_update([0], [[]]) - - with self.assertRaises(Error): - rows_for_insert_or_update([0], None, ["0", "%s"]) - - cases = [ - ( - ["id", "app", "name"], - [(5, "ap", "n"), (6, "bp", "m")], - None, - [(5, "ap", "n"), (6, "bp", "m")], - ), - ( - ["app", "name"], - [("ap", "n"), ("bp", "m")], - None, - [("ap", "n"), ("bp", "m")], - ), - ( - ["app", "name", "fn"], - ["ap", "n", "f1", "bp", "m", "f2", "cp", "o", "f3"], - ["(%s, %s, %s)", "(%s, %s, %s)", "(%s, %s, %s)"], - [("ap", "n", "f1"), ("bp", "m", "f2"), ("cp", "o", "f3")], - ), - ( - ["app", "name", "fn", "ln"], - [ - ("ap", "n", (45, "nested"), "ll"), - ("bp", "m", "f2", "mt"), - ("fp", "cp", "o", "f3"), - ], - None, - [ - ("ap", "n", (45, "nested"), "ll"), - ("bp", "m", "f2", "mt"), - ("fp", "cp", "o", "f3"), - ], - ), - (["app", "name", "fn"], ["ap", "n", "f1"], None, [("ap", "n", "f1")]), - ] - - for i, (columns, params, pyformat_args, want) in enumerate(cases): - with self.subTest(i=i): - got = rows_for_insert_or_update(columns, params, pyformat_args) - self.assertEqual(got, want) - @unittest.skipIf(skip_condition, skip_message) def test_sql_pyformat_args_to_spanner(self): from google.cloud.spanner_dbapi.parse_utils import sql_pyformat_args_to_spanner @@ -411,20 +218,3 @@ def test_escape_name(self): with self.subTest(name=name): got = escape_name(name) self.assertEqual(got, want) - - def test_insert_from_select(self): - """Check that INSERT from SELECT clause can be executed with arguments.""" - from google.cloud.spanner_dbapi.parse_utils import parse_insert - - SQL = """ -INSERT INTO tab_name (id, data) -SELECT tab_name.id + %s AS anon_1, tab_name.data -FROM tab_name -WHERE tab_name.data IN (%s, %s) -""" - ARGS = [5, "data2", "data3"] - - self.assertEqual( - parse_insert(SQL, ARGS), - {"sql_params_list": [(SQL, ARGS)]}, - )