google-cloud-spanner 3.58.0__tar.gz → 3.59.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {google_cloud_spanner-3.58.0/google_cloud_spanner.egg-info → google_cloud_spanner-3.59.0}/PKG-INFO +1 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/client.py +20 -11
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/database.py +28 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/merged_result_set.py +37 -4
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +18 -10
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0/google_cloud_spanner.egg-info}/PKG-INFO +1 -1
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google_cloud_spanner.egg-info/SOURCES.txt +1 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_client.py +23 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_database.py +15 -0
- google_cloud_spanner-3.59.0/tests/unit/test_merged_result_set.py +119 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_spanner_metrics_tracer_factory.py +47 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/LICENSE +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/MANIFEST.in +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/README.rst +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/py.typed +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/types/backup.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/types/backup_schedule.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/types/common.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/py.typed +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/types/common.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/_helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/batch_dml_executor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/checksum.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/client_side_statement_executor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/client_side_statement_parser.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/connection.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/cursor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/exceptions.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/parse_utils.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/parsed_statement.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/parser.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/partition_helper.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/transaction_helper.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/types.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/utils.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_dbapi/version.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/_helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/_opentelemetry_tracing.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/backup.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/batch.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/data_types.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/database_sessions_manager.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/instance.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/keyset.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/constants.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/metrics_capture.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/metrics_exporter.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/metrics_interceptor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/metrics_tracer.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/param_types.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/pool.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/py.typed +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/request_id_header.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/async_client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/client.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/pagers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/grpc.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/rest.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/services/spanner/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/session.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/snapshot.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/streamed.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/table.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/database_test.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/interceptors.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/mock_database_admin.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/mock_spanner.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/transaction.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/change_stream.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/commit_response.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/keys.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/mutation.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/query_plan.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/result_set.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/spanner.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/transaction.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/types/type.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google_cloud_spanner.egg-info/dependency_links.txt +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google_cloud_spanner.egg-info/not-zip-safe +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google_cloud_spanner.egg-info/requires.txt +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google_cloud_spanner.egg-info/top_level.txt +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/setup.cfg +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/setup.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/_builders.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/_fixtures.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/_helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/mock_server_test_base.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_aborted_transaction.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_basics.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_dbapi_autocommit.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_dbapi_isolation_level.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_request_id_header.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/mockserver_tests/test_tags.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/_helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/_sample_data.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/conftest.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_backup_api.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_database_api.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_dbapi.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_instance_api.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_observability_options.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_session_api.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_streaming_chunking.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/test_table_api.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/testdata/descriptors.pb +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/testdata/singer.proto +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/testdata/singer_pb2.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/utils/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/utils/clear_streaming.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/utils/populate_streaming.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/utils/scrub_instances.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/system/utils/streaming_utils.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_admin_database_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_admin_instance_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_v1/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/gapic/spanner_v1/test_spanner.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/__init__.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test__helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_batch_dml_executor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_checksum.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_client_side_statement_executor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_connect.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_connection.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_cursor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_globals.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_parse_utils.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_parser.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_transaction_helper.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_types.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/spanner_dbapi/test_utils.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/streaming-read-acceptance-test.json +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test__helpers.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test__opentelemetry_tracing.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_atomic_counter.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_backup.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_batch.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_database_session_manager.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_datatypes.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_instance.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_keyset.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics_capture.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics_exporter.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics_interceptor.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics_tracer.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_metrics_tracer_factory.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_packaging.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_param_types.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_pool.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_session.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_snapshot.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_spanner.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_streamed.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_table.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/test_transaction.py +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/testdata/singer.proto +0 -0
- {google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/tests/unit/testdata/singer_pb2.py +0 -0
{google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/client.py
RENAMED
|
@@ -25,6 +25,7 @@ In the hierarchy of API concepts
|
|
|
25
25
|
"""
|
|
26
26
|
import grpc
|
|
27
27
|
import os
|
|
28
|
+
import logging
|
|
28
29
|
import warnings
|
|
29
30
|
|
|
30
31
|
from google.api_core.gapic_v1 import client_info
|
|
@@ -97,6 +98,9 @@ def _get_spanner_optimizer_statistics_package():
|
|
|
97
98
|
return os.getenv(OPTIMIZER_STATISITCS_PACKAGE_ENV_VAR, "")
|
|
98
99
|
|
|
99
100
|
|
|
101
|
+
log = logging.getLogger(__name__)
|
|
102
|
+
|
|
103
|
+
|
|
100
104
|
def _get_spanner_enable_builtin_metrics():
|
|
101
105
|
return os.getenv(ENABLE_SPANNER_METRICS_ENV_VAR) == "true"
|
|
102
106
|
|
|
@@ -240,19 +244,24 @@ class Client(ClientWithProject):
|
|
|
240
244
|
and HAS_GOOGLE_CLOUD_MONITORING_INSTALLED
|
|
241
245
|
):
|
|
242
246
|
meter_provider = metrics.NoOpMeterProvider()
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
try:
|
|
248
|
+
if not _get_spanner_emulator_host():
|
|
249
|
+
meter_provider = MeterProvider(
|
|
250
|
+
metric_readers=[
|
|
251
|
+
PeriodicExportingMetricReader(
|
|
252
|
+
CloudMonitoringMetricsExporter(
|
|
253
|
+
project_id=project, credentials=credentials
|
|
254
|
+
),
|
|
255
|
+
export_interval_millis=METRIC_EXPORT_INTERVAL_MS,
|
|
249
256
|
),
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
257
|
+
]
|
|
258
|
+
)
|
|
259
|
+
metrics.set_meter_provider(meter_provider)
|
|
260
|
+
SpannerMetricsTracerFactory()
|
|
261
|
+
except Exception as e:
|
|
262
|
+
log.warning(
|
|
263
|
+
"Failed to initialize Spanner built-in metrics. Error: %s", e
|
|
253
264
|
)
|
|
254
|
-
metrics.set_meter_provider(meter_provider)
|
|
255
|
-
SpannerMetricsTracerFactory()
|
|
256
265
|
else:
|
|
257
266
|
SpannerMetricsTracerFactory(enabled=False)
|
|
258
267
|
|
{google_cloud_spanner-3.58.0 → google_cloud_spanner-3.59.0}/google/cloud/spanner_v1/database.py
RENAMED
|
@@ -1532,6 +1532,14 @@ class BatchSnapshot(object):
|
|
|
1532
1532
|
"transaction_id": snapshot._transaction_id,
|
|
1533
1533
|
}
|
|
1534
1534
|
|
|
1535
|
+
def __enter__(self):
|
|
1536
|
+
"""Begin ``with`` block."""
|
|
1537
|
+
return self
|
|
1538
|
+
|
|
1539
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
1540
|
+
"""End ``with`` block."""
|
|
1541
|
+
self.close()
|
|
1542
|
+
|
|
1535
1543
|
@property
|
|
1536
1544
|
def observability_options(self):
|
|
1537
1545
|
return getattr(self._database, "observability_options", {})
|
|
@@ -1703,6 +1711,7 @@ class BatchSnapshot(object):
|
|
|
1703
1711
|
*,
|
|
1704
1712
|
retry=gapic_v1.method.DEFAULT,
|
|
1705
1713
|
timeout=gapic_v1.method.DEFAULT,
|
|
1714
|
+
lazy_decode=False,
|
|
1706
1715
|
):
|
|
1707
1716
|
"""Process a single, partitioned read.
|
|
1708
1717
|
|
|
@@ -1717,6 +1726,14 @@ class BatchSnapshot(object):
|
|
|
1717
1726
|
:type timeout: float
|
|
1718
1727
|
:param timeout: (Optional) The timeout for this request.
|
|
1719
1728
|
|
|
1729
|
+
:type lazy_decode: bool
|
|
1730
|
+
:param lazy_decode:
|
|
1731
|
+
(Optional) If this argument is set to ``true``, the iterator
|
|
1732
|
+
returns the underlying protobuf values instead of decoded Python
|
|
1733
|
+
objects. This reduces the time that is needed to iterate through
|
|
1734
|
+
large result sets. The application is responsible for decoding
|
|
1735
|
+
the data that is needed.
|
|
1736
|
+
|
|
1720
1737
|
|
|
1721
1738
|
:rtype: :class:`~google.cloud.spanner_v1.streamed.StreamedResultSet`
|
|
1722
1739
|
:returns: a result set instance which can be used to consume rows.
|
|
@@ -1844,6 +1861,7 @@ class BatchSnapshot(object):
|
|
|
1844
1861
|
self,
|
|
1845
1862
|
batch,
|
|
1846
1863
|
*,
|
|
1864
|
+
lazy_decode: bool = False,
|
|
1847
1865
|
retry=gapic_v1.method.DEFAULT,
|
|
1848
1866
|
timeout=gapic_v1.method.DEFAULT,
|
|
1849
1867
|
):
|
|
@@ -1854,6 +1872,13 @@ class BatchSnapshot(object):
|
|
|
1854
1872
|
one of the mappings returned from an earlier call to
|
|
1855
1873
|
:meth:`generate_query_batches`.
|
|
1856
1874
|
|
|
1875
|
+
:type lazy_decode: bool
|
|
1876
|
+
:param lazy_decode:
|
|
1877
|
+
(Optional) If this argument is set to ``true``, the iterator
|
|
1878
|
+
returns the underlying protobuf values instead of decoded Python
|
|
1879
|
+
objects. This reduces the time that is needed to iterate through
|
|
1880
|
+
large result sets.
|
|
1881
|
+
|
|
1857
1882
|
:type retry: :class:`~google.api_core.retry.Retry`
|
|
1858
1883
|
:param retry: (Optional) The retry settings for this request.
|
|
1859
1884
|
|
|
@@ -1870,6 +1895,7 @@ class BatchSnapshot(object):
|
|
|
1870
1895
|
return self._get_snapshot().execute_sql(
|
|
1871
1896
|
partition=batch["partition"],
|
|
1872
1897
|
**batch["query"],
|
|
1898
|
+
lazy_decode=lazy_decode,
|
|
1873
1899
|
retry=retry,
|
|
1874
1900
|
timeout=timeout,
|
|
1875
1901
|
)
|
|
@@ -1883,6 +1909,7 @@ class BatchSnapshot(object):
|
|
|
1883
1909
|
max_partitions=None,
|
|
1884
1910
|
query_options=None,
|
|
1885
1911
|
data_boost_enabled=False,
|
|
1912
|
+
lazy_decode=False,
|
|
1886
1913
|
):
|
|
1887
1914
|
"""Start a partitioned query operation to get list of partitions and
|
|
1888
1915
|
then executes each partition on a separate thread
|
|
@@ -1943,7 +1970,7 @@ class BatchSnapshot(object):
|
|
|
1943
1970
|
data_boost_enabled,
|
|
1944
1971
|
)
|
|
1945
1972
|
)
|
|
1946
|
-
return MergedResultSet(self, partitions, 0)
|
|
1973
|
+
return MergedResultSet(self, partitions, 0, lazy_decode=lazy_decode)
|
|
1947
1974
|
|
|
1948
1975
|
def process(self, batch):
|
|
1949
1976
|
"""Process a single, partitioned query or read.
|
|
@@ -33,10 +33,13 @@ class PartitionExecutor:
|
|
|
33
33
|
rows in the queue
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
def __init__(
|
|
36
|
+
def __init__(
|
|
37
|
+
self, batch_snapshot, partition_id, merged_result_set, lazy_decode=False
|
|
38
|
+
):
|
|
37
39
|
self._batch_snapshot: BatchSnapshot = batch_snapshot
|
|
38
40
|
self._partition_id = partition_id
|
|
39
41
|
self._merged_result_set: MergedResultSet = merged_result_set
|
|
42
|
+
self._lazy_decode = lazy_decode
|
|
40
43
|
self._queue: Queue[PartitionExecutorResult] = merged_result_set._queue
|
|
41
44
|
|
|
42
45
|
def run(self):
|
|
@@ -52,7 +55,9 @@ class PartitionExecutor:
|
|
|
52
55
|
def __run(self):
|
|
53
56
|
results = None
|
|
54
57
|
try:
|
|
55
|
-
results = self._batch_snapshot.process_query_batch(
|
|
58
|
+
results = self._batch_snapshot.process_query_batch(
|
|
59
|
+
self._partition_id, lazy_decode=self._lazy_decode
|
|
60
|
+
)
|
|
56
61
|
for row in results:
|
|
57
62
|
if self._merged_result_set._metadata is None:
|
|
58
63
|
self._set_metadata(results)
|
|
@@ -75,6 +80,7 @@ class PartitionExecutor:
|
|
|
75
80
|
try:
|
|
76
81
|
if not is_exception:
|
|
77
82
|
self._merged_result_set._metadata = results.metadata
|
|
83
|
+
self._merged_result_set._result_set = results
|
|
78
84
|
finally:
|
|
79
85
|
self._merged_result_set.metadata_lock.release()
|
|
80
86
|
self._merged_result_set.metadata_event.set()
|
|
@@ -94,7 +100,10 @@ class MergedResultSet:
|
|
|
94
100
|
records in the MergedResultSet is not guaranteed.
|
|
95
101
|
"""
|
|
96
102
|
|
|
97
|
-
def __init__(
|
|
103
|
+
def __init__(
|
|
104
|
+
self, batch_snapshot, partition_ids, max_parallelism, lazy_decode=False
|
|
105
|
+
):
|
|
106
|
+
self._result_set = None
|
|
98
107
|
self._exception = None
|
|
99
108
|
self._metadata = None
|
|
100
109
|
self.metadata_event = Event()
|
|
@@ -110,7 +119,7 @@ class MergedResultSet:
|
|
|
110
119
|
partition_executors = []
|
|
111
120
|
for partition_id in partition_ids:
|
|
112
121
|
partition_executors.append(
|
|
113
|
-
PartitionExecutor(batch_snapshot, partition_id, self)
|
|
122
|
+
PartitionExecutor(batch_snapshot, partition_id, self, lazy_decode)
|
|
114
123
|
)
|
|
115
124
|
executor = ThreadPoolExecutor(max_workers=parallelism)
|
|
116
125
|
for partition_executor in partition_executors:
|
|
@@ -144,3 +153,27 @@ class MergedResultSet:
|
|
|
144
153
|
def stats(self):
|
|
145
154
|
# TODO: Implement
|
|
146
155
|
return None
|
|
156
|
+
|
|
157
|
+
def decode_row(self, row: []) -> []:
|
|
158
|
+
"""Decodes a row from protobuf values to Python objects. This function
|
|
159
|
+
should only be called for result sets that use ``lazy_decoding=True``.
|
|
160
|
+
The array that is returned by this function is the same as the array
|
|
161
|
+
that would have been returned by the rows iterator if ``lazy_decoding=False``.
|
|
162
|
+
|
|
163
|
+
:returns: an array containing the decoded values of all the columns in the given row
|
|
164
|
+
"""
|
|
165
|
+
if self._result_set is None:
|
|
166
|
+
raise ValueError("iterator not started")
|
|
167
|
+
return self._result_set.decode_row(row)
|
|
168
|
+
|
|
169
|
+
def decode_column(self, row: [], column_index: int):
|
|
170
|
+
"""Decodes a column from a protobuf value to a Python object. This function
|
|
171
|
+
should only be called for result sets that use ``lazy_decoding=True``.
|
|
172
|
+
The object that is returned by this function is the same as the object
|
|
173
|
+
that would have been returned by the rows iterator if ``lazy_decoding=False``.
|
|
174
|
+
|
|
175
|
+
:returns: the decoded column value
|
|
176
|
+
"""
|
|
177
|
+
if self._result_set is None:
|
|
178
|
+
raise ValueError("iterator not started")
|
|
179
|
+
return self._result_set.decode_column(row, column_index)
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
from .metrics_tracer_factory import MetricsTracerFactory
|
|
19
19
|
import os
|
|
20
|
+
import logging
|
|
20
21
|
from .constants import (
|
|
21
22
|
SPANNER_SERVICE_NAME,
|
|
22
23
|
GOOGLE_CLOUD_REGION_KEY,
|
|
@@ -33,9 +34,6 @@ try:
|
|
|
33
34
|
|
|
34
35
|
import mmh3
|
|
35
36
|
|
|
36
|
-
# Override Resource detector logging to not warn when GCP resources are not detected
|
|
37
|
-
import logging
|
|
38
|
-
|
|
39
37
|
logging.getLogger("opentelemetry.resourcedetector.gcp_resource_detector").setLevel(
|
|
40
38
|
logging.ERROR
|
|
41
39
|
)
|
|
@@ -48,6 +46,8 @@ from .metrics_tracer import MetricsTracer
|
|
|
48
46
|
from google.cloud.spanner_v1 import __version__
|
|
49
47
|
from uuid import uuid4
|
|
50
48
|
|
|
49
|
+
log = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
51
|
|
|
52
52
|
class SpannerMetricsTracerFactory(MetricsTracerFactory):
|
|
53
53
|
"""A factory for creating SpannerMetricsTracer instances."""
|
|
@@ -158,15 +158,23 @@ class SpannerMetricsTracerFactory(MetricsTracerFactory):
|
|
|
158
158
|
def _get_location() -> str:
|
|
159
159
|
"""Get the location of the resource.
|
|
160
160
|
|
|
161
|
+
In case of any error during detection, this method will log a warning
|
|
162
|
+
and default to the "global" location.
|
|
163
|
+
|
|
161
164
|
Returns:
|
|
162
165
|
str: The location of the resource. If OpenTelemetry is not installed, returns a global region.
|
|
163
166
|
"""
|
|
164
167
|
if not HAS_OPENTELEMETRY_INSTALLED:
|
|
165
168
|
return GOOGLE_CLOUD_REGION_GLOBAL
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
try:
|
|
170
|
+
detector = gcp_resource_detector.GoogleCloudResourceDetector()
|
|
171
|
+
resources = detector.detect()
|
|
172
|
+
|
|
173
|
+
if GOOGLE_CLOUD_REGION_KEY in resources.attributes:
|
|
174
|
+
return resources.attributes[GOOGLE_CLOUD_REGION_KEY]
|
|
175
|
+
except Exception as e:
|
|
176
|
+
log.warning(
|
|
177
|
+
"Failed to detect GCP resource location for Spanner metrics, defaulting to 'global'. Error: %s",
|
|
178
|
+
e,
|
|
179
|
+
)
|
|
180
|
+
return GOOGLE_CLOUD_REGION_GLOBAL
|
|
@@ -167,6 +167,7 @@ tests/unit/test_database_session_manager.py
|
|
|
167
167
|
tests/unit/test_datatypes.py
|
|
168
168
|
tests/unit/test_instance.py
|
|
169
169
|
tests/unit/test_keyset.py
|
|
170
|
+
tests/unit/test_merged_result_set.py
|
|
170
171
|
tests/unit/test_metrics.py
|
|
171
172
|
tests/unit/test_metrics_capture.py
|
|
172
173
|
tests/unit/test_metrics_exporter.py
|
|
@@ -255,6 +255,29 @@ class TestClient(unittest.TestCase):
|
|
|
255
255
|
expected_scopes, creds, directed_read_options=self.DIRECTED_READ_OPTIONS
|
|
256
256
|
)
|
|
257
257
|
|
|
258
|
+
@mock.patch.dict(os.environ, {"SPANNER_ENABLE_BUILTIN_METRICS": "true"})
|
|
259
|
+
@mock.patch("google.cloud.spanner_v1.client.SpannerMetricsTracerFactory")
|
|
260
|
+
def test_constructor_w_metrics_initialization_error(
|
|
261
|
+
self, mock_spanner_metrics_factory
|
|
262
|
+
):
|
|
263
|
+
"""
|
|
264
|
+
Test that Client constructor handles exceptions during metrics
|
|
265
|
+
initialization and logs a warning.
|
|
266
|
+
"""
|
|
267
|
+
from google.cloud.spanner_v1.client import Client
|
|
268
|
+
|
|
269
|
+
mock_spanner_metrics_factory.side_effect = Exception("Metrics init failed")
|
|
270
|
+
creds = build_scoped_credentials()
|
|
271
|
+
|
|
272
|
+
with self.assertLogs("google.cloud.spanner_v1.client", level="WARNING") as log:
|
|
273
|
+
client = Client(project=self.PROJECT, credentials=creds)
|
|
274
|
+
self.assertIsNotNone(client)
|
|
275
|
+
self.assertIn(
|
|
276
|
+
"Failed to initialize Spanner built-in metrics. Error: Metrics init failed",
|
|
277
|
+
log.output[0],
|
|
278
|
+
)
|
|
279
|
+
mock_spanner_metrics_factory.assert_called_once()
|
|
280
|
+
|
|
258
281
|
def test_constructor_route_to_leader_disbled(self):
|
|
259
282
|
from google.cloud.spanner_v1 import client as MUT
|
|
260
283
|
|
|
@@ -3141,6 +3141,7 @@ class TestBatchSnapshot(_BaseTest):
|
|
|
3141
3141
|
params=params,
|
|
3142
3142
|
param_types=param_types,
|
|
3143
3143
|
partition=token,
|
|
3144
|
+
lazy_decode=False,
|
|
3144
3145
|
retry=gapic_v1.method.DEFAULT,
|
|
3145
3146
|
timeout=gapic_v1.method.DEFAULT,
|
|
3146
3147
|
)
|
|
@@ -3170,6 +3171,7 @@ class TestBatchSnapshot(_BaseTest):
|
|
|
3170
3171
|
params=params,
|
|
3171
3172
|
param_types=param_types,
|
|
3172
3173
|
partition=token,
|
|
3174
|
+
lazy_decode=False,
|
|
3173
3175
|
retry=retry,
|
|
3174
3176
|
timeout=2.0,
|
|
3175
3177
|
)
|
|
@@ -3193,11 +3195,23 @@ class TestBatchSnapshot(_BaseTest):
|
|
|
3193
3195
|
snapshot.execute_sql.assert_called_once_with(
|
|
3194
3196
|
sql=sql,
|
|
3195
3197
|
partition=token,
|
|
3198
|
+
lazy_decode=False,
|
|
3196
3199
|
retry=gapic_v1.method.DEFAULT,
|
|
3197
3200
|
timeout=gapic_v1.method.DEFAULT,
|
|
3198
3201
|
directed_read_options=DIRECTED_READ_OPTIONS,
|
|
3199
3202
|
)
|
|
3200
3203
|
|
|
3204
|
+
def test_context_manager(self):
|
|
3205
|
+
database = self._make_database()
|
|
3206
|
+
batch_txn = self._make_one(database)
|
|
3207
|
+
session = batch_txn._session = self._make_session()
|
|
3208
|
+
session.is_multiplexed = False
|
|
3209
|
+
|
|
3210
|
+
with batch_txn:
|
|
3211
|
+
pass
|
|
3212
|
+
|
|
3213
|
+
session.delete.assert_called_once_with()
|
|
3214
|
+
|
|
3201
3215
|
def test_close_wo_session(self):
|
|
3202
3216
|
database = self._make_database()
|
|
3203
3217
|
batch_txn = self._make_one(database)
|
|
@@ -3292,6 +3306,7 @@ class TestBatchSnapshot(_BaseTest):
|
|
|
3292
3306
|
params=params,
|
|
3293
3307
|
param_types=param_types,
|
|
3294
3308
|
partition=token,
|
|
3309
|
+
lazy_decode=False,
|
|
3295
3310
|
retry=gapic_v1.method.DEFAULT,
|
|
3296
3311
|
timeout=gapic_v1.method.DEFAULT,
|
|
3297
3312
|
)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Copyright 2025 Google LLC All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import unittest
|
|
16
|
+
|
|
17
|
+
import mock
|
|
18
|
+
from google.cloud.spanner_v1.streamed import StreamedResultSet
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestMergedResultSet(unittest.TestCase):
|
|
22
|
+
def _get_target_class(self):
|
|
23
|
+
from google.cloud.spanner_v1.merged_result_set import MergedResultSet
|
|
24
|
+
|
|
25
|
+
return MergedResultSet
|
|
26
|
+
|
|
27
|
+
def _make_one(self, *args, **kwargs):
|
|
28
|
+
klass = self._get_target_class()
|
|
29
|
+
obj = super(klass, klass).__new__(klass)
|
|
30
|
+
from threading import Event, Lock
|
|
31
|
+
|
|
32
|
+
obj.metadata_event = Event()
|
|
33
|
+
obj.metadata_lock = Lock()
|
|
34
|
+
obj._metadata = None
|
|
35
|
+
obj._result_set = None
|
|
36
|
+
return obj
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _make_value(value):
|
|
40
|
+
from google.cloud.spanner_v1._helpers import _make_value_pb
|
|
41
|
+
|
|
42
|
+
return _make_value_pb(value)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _make_scalar_field(name, type_):
|
|
46
|
+
from google.cloud.spanner_v1 import StructType
|
|
47
|
+
from google.cloud.spanner_v1 import Type
|
|
48
|
+
|
|
49
|
+
return StructType.Field(name=name, type_=Type(code=type_))
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def _make_result_set_metadata(fields=()):
|
|
53
|
+
from google.cloud.spanner_v1 import ResultSetMetadata
|
|
54
|
+
from google.cloud.spanner_v1 import StructType
|
|
55
|
+
|
|
56
|
+
metadata = ResultSetMetadata(row_type=StructType(fields=[]))
|
|
57
|
+
for field in fields:
|
|
58
|
+
metadata.row_type.fields.append(field)
|
|
59
|
+
return metadata
|
|
60
|
+
|
|
61
|
+
def test_stats_property(self):
|
|
62
|
+
merged = self._make_one()
|
|
63
|
+
# The property is currently not implemented, so it should just return None.
|
|
64
|
+
self.assertIsNone(merged.stats)
|
|
65
|
+
|
|
66
|
+
def test_decode_row(self):
|
|
67
|
+
merged = self._make_one()
|
|
68
|
+
|
|
69
|
+
merged._result_set = mock.create_autospec(StreamedResultSet, instance=True)
|
|
70
|
+
merged._result_set.decode_row.return_value = ["Phred", 42]
|
|
71
|
+
|
|
72
|
+
raw_row = [self._make_value("Phred"), self._make_value(42)]
|
|
73
|
+
decoded_row = merged.decode_row(raw_row)
|
|
74
|
+
|
|
75
|
+
self.assertEqual(decoded_row, ["Phred", 42])
|
|
76
|
+
merged._result_set.decode_row.assert_called_once_with(raw_row)
|
|
77
|
+
|
|
78
|
+
def test_decode_row_no_result_set(self):
|
|
79
|
+
merged = self._make_one()
|
|
80
|
+
merged._result_set = None
|
|
81
|
+
with self.assertRaisesRegex(ValueError, "iterator not started"):
|
|
82
|
+
merged.decode_row([])
|
|
83
|
+
|
|
84
|
+
def test_decode_row_type_error(self):
|
|
85
|
+
merged = self._make_one()
|
|
86
|
+
merged._result_set = mock.create_autospec(StreamedResultSet, instance=True)
|
|
87
|
+
merged._result_set.decode_row.side_effect = TypeError
|
|
88
|
+
|
|
89
|
+
with self.assertRaises(TypeError):
|
|
90
|
+
merged.decode_row("not a list")
|
|
91
|
+
|
|
92
|
+
def test_decode_column(self):
|
|
93
|
+
merged = self._make_one()
|
|
94
|
+
merged._result_set = mock.create_autospec(StreamedResultSet, instance=True)
|
|
95
|
+
merged._result_set.decode_column.side_effect = ["Phred", 42]
|
|
96
|
+
|
|
97
|
+
raw_row = [self._make_value("Phred"), self._make_value(42)]
|
|
98
|
+
decoded_name = merged.decode_column(raw_row, 0)
|
|
99
|
+
decoded_age = merged.decode_column(raw_row, 1)
|
|
100
|
+
|
|
101
|
+
self.assertEqual(decoded_name, "Phred")
|
|
102
|
+
self.assertEqual(decoded_age, 42)
|
|
103
|
+
merged._result_set.decode_column.assert_has_calls(
|
|
104
|
+
[mock.call(raw_row, 0), mock.call(raw_row, 1)]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def test_decode_column_no_result_set(self):
|
|
108
|
+
merged = self._make_one()
|
|
109
|
+
merged._result_set = None
|
|
110
|
+
with self.assertRaisesRegex(ValueError, "iterator not started"):
|
|
111
|
+
merged.decode_column([], 0)
|
|
112
|
+
|
|
113
|
+
def test_decode_column_type_error(self):
|
|
114
|
+
merged = self._make_one()
|
|
115
|
+
merged._result_set = mock.create_autospec(StreamedResultSet, instance=True)
|
|
116
|
+
merged._result_set.decode_column.side_effect = TypeError
|
|
117
|
+
|
|
118
|
+
with self.assertRaises(TypeError):
|
|
119
|
+
merged.decode_column("not a list", 0)
|
|
@@ -13,9 +13,17 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
+
import pytest
|
|
17
|
+
import unittest
|
|
18
|
+
from unittest import mock
|
|
19
|
+
|
|
20
|
+
from google.cloud.spanner_v1.metrics.constants import GOOGLE_CLOUD_REGION_KEY
|
|
16
21
|
from google.cloud.spanner_v1.metrics.spanner_metrics_tracer_factory import (
|
|
17
22
|
SpannerMetricsTracerFactory,
|
|
18
23
|
)
|
|
24
|
+
from opentelemetry.sdk.resources import Resource
|
|
25
|
+
|
|
26
|
+
pytest.importorskip("opentelemetry")
|
|
19
27
|
|
|
20
28
|
|
|
21
29
|
class TestSpannerMetricsTracerFactory:
|
|
@@ -48,3 +56,42 @@ class TestSpannerMetricsTracerFactory:
|
|
|
48
56
|
location = SpannerMetricsTracerFactory._get_location()
|
|
49
57
|
assert isinstance(location, str)
|
|
50
58
|
assert location # Simply asserting for non empty as this can change depending on the instance this test runs in.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TestSpannerMetricsTracerFactoryGetLocation(unittest.TestCase):
|
|
62
|
+
@mock.patch(
|
|
63
|
+
"opentelemetry.resourcedetector.gcp_resource_detector.GoogleCloudResourceDetector.detect"
|
|
64
|
+
)
|
|
65
|
+
def test_get_location_with_region(self, mock_detect):
|
|
66
|
+
"""Test that _get_location returns the region when detected."""
|
|
67
|
+
mock_resource = Resource.create({GOOGLE_CLOUD_REGION_KEY: "us-central1"})
|
|
68
|
+
mock_detect.return_value = mock_resource
|
|
69
|
+
|
|
70
|
+
location = SpannerMetricsTracerFactory._get_location()
|
|
71
|
+
assert location == "us-central1"
|
|
72
|
+
|
|
73
|
+
@mock.patch(
|
|
74
|
+
"opentelemetry.resourcedetector.gcp_resource_detector.GoogleCloudResourceDetector.detect"
|
|
75
|
+
)
|
|
76
|
+
def test_get_location_without_region(self, mock_detect):
|
|
77
|
+
"""Test that _get_location returns 'global' when no region is detected."""
|
|
78
|
+
mock_resource = Resource.create({}) # No region attribute
|
|
79
|
+
mock_detect.return_value = mock_resource
|
|
80
|
+
|
|
81
|
+
location = SpannerMetricsTracerFactory._get_location()
|
|
82
|
+
assert location == "global"
|
|
83
|
+
|
|
84
|
+
@mock.patch(
|
|
85
|
+
"opentelemetry.resourcedetector.gcp_resource_detector.GoogleCloudResourceDetector.detect"
|
|
86
|
+
)
|
|
87
|
+
def test_get_location_with_exception(self, mock_detect):
|
|
88
|
+
"""Test that _get_location returns 'global' and logs a warning on exception."""
|
|
89
|
+
mock_detect.side_effect = Exception("detector failed")
|
|
90
|
+
|
|
91
|
+
with self.assertLogs(
|
|
92
|
+
"google.cloud.spanner_v1.metrics.spanner_metrics_tracer_factory",
|
|
93
|
+
level="WARNING",
|
|
94
|
+
) as log:
|
|
95
|
+
location = SpannerMetricsTracerFactory._get_location()
|
|
96
|
+
assert location == "global"
|
|
97
|
+
self.assertIn("Failed to detect GCP resource location", log.output[0])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|