google-cloud-spanner 3.61.0__tar.gz → 3.63.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.
Files changed (217) hide show
  1. {google_cloud_spanner-3.61.0/google_cloud_spanner.egg-info → google_cloud_spanner-3.63.0}/PKG-INFO +1 -1
  2. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/gapic_version.py +1 -1
  3. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/gapic_version.py +1 -1
  4. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parse_utils.py +5 -0
  5. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/version.py +1 -1
  6. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/__init__.py +3 -0
  7. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/_helpers.py +77 -3
  8. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/_opentelemetry_tracing.py +2 -0
  9. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/batch.py +13 -10
  10. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/client.py +42 -20
  11. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/database.py +79 -11
  12. google_cloud_spanner-3.63.0/google/cloud/spanner_v1/exceptions.py +42 -0
  13. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/gapic_version.py +1 -1
  14. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_capture.py +17 -7
  15. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_interceptor.py +20 -24
  16. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +17 -2
  17. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/param_types.py +1 -0
  18. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/pool.py +20 -16
  19. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/request_id_header.py +10 -0
  20. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/session.py +51 -44
  21. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/snapshot.py +57 -60
  22. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/streamed.py +1 -0
  23. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/transaction.py +46 -34
  24. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0/google_cloud_spanner.egg-info}/PKG-INFO +1 -1
  25. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/SOURCES.txt +4 -0
  26. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_aborted_transaction.py +26 -13
  27. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_dbapi_isolation_level.py +1 -0
  28. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_observability_options.py +17 -14
  29. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_session_api.py +16 -0
  30. google_cloud_spanner-3.63.0/tests/unit/conftest.py +27 -0
  31. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_parse_utils.py +23 -0
  32. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test__helpers.py +13 -0
  33. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test__opentelemetry_tracing.py +8 -1
  34. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_batch.py +27 -5
  35. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_client.py +78 -10
  36. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_database.py +20 -1
  37. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_database_session_manager.py +8 -2
  38. google_cloud_spanner-3.63.0/tests/unit/test_exceptions.py +65 -0
  39. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics.py +30 -10
  40. google_cloud_spanner-3.63.0/tests/unit/test_metrics_concurrency.py +94 -0
  41. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_interceptor.py +34 -42
  42. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_pool.py +19 -0
  43. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_session.py +72 -13
  44. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_snapshot.py +90 -3
  45. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_spanner.py +27 -0
  46. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_transaction.py +19 -0
  47. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/LICENSE +0 -0
  48. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/MANIFEST.in +0 -0
  49. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/README.rst +0 -0
  50. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner.py +0 -0
  51. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/__init__.py +0 -0
  52. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/gapic_metadata.json +0 -0
  53. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/py.typed +0 -0
  54. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/__init__.py +0 -0
  55. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +0 -0
  56. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +0 -0
  57. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/client.py +0 -0
  58. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +0 -0
  59. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +0 -0
  60. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +0 -0
  61. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +0 -0
  62. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +0 -0
  63. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +0 -0
  64. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +0 -0
  65. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/__init__.py +0 -0
  66. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/backup.py +0 -0
  67. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/backup_schedule.py +0 -0
  68. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/common.py +0 -0
  69. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +0 -0
  70. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/__init__.py +0 -0
  71. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/gapic_metadata.json +0 -0
  72. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/py.typed +0 -0
  73. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/__init__.py +0 -0
  74. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +0 -0
  75. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +0 -0
  76. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +0 -0
  77. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +0 -0
  78. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +0 -0
  79. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +0 -0
  80. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +0 -0
  81. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +0 -0
  82. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +0 -0
  83. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +0 -0
  84. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/__init__.py +0 -0
  85. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/common.py +0 -0
  86. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +0 -0
  87. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/__init__.py +0 -0
  88. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/_helpers.py +0 -0
  89. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/batch_dml_executor.py +0 -0
  90. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/checksum.py +0 -0
  91. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/client_side_statement_executor.py +0 -0
  92. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/client_side_statement_parser.py +0 -0
  93. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/connection.py +0 -0
  94. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/cursor.py +0 -0
  95. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/exceptions.py +0 -0
  96. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parsed_statement.py +0 -0
  97. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parser.py +0 -0
  98. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/partition_helper.py +0 -0
  99. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/transaction_helper.py +0 -0
  100. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/types.py +0 -0
  101. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/utils.py +0 -0
  102. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/backup.py +0 -0
  103. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/data_types.py +0 -0
  104. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/database_sessions_manager.py +0 -0
  105. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/gapic_metadata.json +0 -0
  106. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/instance.py +0 -0
  107. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/keyset.py +0 -0
  108. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/merged_result_set.py +0 -0
  109. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/constants.py +0 -0
  110. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_exporter.py +0 -0
  111. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_tracer.py +0 -0
  112. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +0 -0
  113. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/py.typed +0 -0
  114. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/__init__.py +0 -0
  115. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/__init__.py +0 -0
  116. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/async_client.py +0 -0
  117. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/client.py +0 -0
  118. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/pagers.py +0 -0
  119. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/__init__.py +0 -0
  120. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/base.py +0 -0
  121. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/grpc.py +0 -0
  122. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +0 -0
  123. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/rest.py +0 -0
  124. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/rest_base.py +0 -0
  125. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/table.py +0 -0
  126. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/__init__.py +0 -0
  127. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/database_test.py +0 -0
  128. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/interceptors.py +0 -0
  129. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/mock_database_admin.py +0 -0
  130. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/mock_spanner.py +0 -0
  131. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +0 -0
  132. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +0 -0
  133. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/__init__.py +0 -0
  134. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/change_stream.py +0 -0
  135. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/commit_response.py +0 -0
  136. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/keys.py +0 -0
  137. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/location.py +0 -0
  138. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/mutation.py +0 -0
  139. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/query_plan.py +0 -0
  140. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/result_set.py +0 -0
  141. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/spanner.py +0 -0
  142. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/transaction.py +0 -0
  143. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/type.py +0 -0
  144. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/dependency_links.txt +0 -0
  145. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/not-zip-safe +0 -0
  146. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/requires.txt +0 -0
  147. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/top_level.txt +0 -0
  148. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/setup.cfg +0 -0
  149. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/setup.py +0 -0
  150. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/__init__.py +0 -0
  151. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/_builders.py +0 -0
  152. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/_fixtures.py +0 -0
  153. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/_helpers.py +0 -0
  154. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/__init__.py +0 -0
  155. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/mock_server_test_base.py +0 -0
  156. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_basics.py +0 -0
  157. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_dbapi_autocommit.py +0 -0
  158. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_request_id_header.py +0 -0
  159. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_tags.py +0 -0
  160. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/__init__.py +0 -0
  161. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/_helpers.py +0 -0
  162. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/_sample_data.py +0 -0
  163. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/conftest.py +0 -0
  164. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_backup_api.py +0 -0
  165. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_database_api.py +0 -0
  166. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_dbapi.py +0 -0
  167. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_instance_api.py +0 -0
  168. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_metrics.py +0 -0
  169. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_streaming_chunking.py +0 -0
  170. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/test_table_api.py +0 -0
  171. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/descriptors.pb +0 -0
  172. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/singer.proto +0 -0
  173. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/singer_pb2.py +0 -0
  174. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/utils/__init__.py +0 -0
  175. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/utils/clear_streaming.py +0 -0
  176. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/utils/populate_streaming.py +0 -0
  177. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/utils/scrub_instances.py +0 -0
  178. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/system/utils/streaming_utils.py +0 -0
  179. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/__init__.py +0 -0
  180. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/__init__.py +0 -0
  181. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_database_v1/__init__.py +0 -0
  182. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py +0 -0
  183. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_instance_v1/__init__.py +0 -0
  184. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py +0 -0
  185. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_v1/__init__.py +0 -0
  186. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_v1/test_spanner.py +0 -0
  187. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/__init__.py +0 -0
  188. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test__helpers.py +0 -0
  189. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_batch_dml_executor.py +0 -0
  190. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_checksum.py +0 -0
  191. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_client_side_statement_executor.py +0 -0
  192. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_connect.py +0 -0
  193. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_connection.py +0 -0
  194. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_cursor.py +0 -0
  195. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_globals.py +0 -0
  196. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_parser.py +0 -0
  197. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_transaction_helper.py +0 -0
  198. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_types.py +0 -0
  199. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_utils.py +0 -0
  200. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/streaming-read-acceptance-test.json +0 -0
  201. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_atomic_counter.py +0 -0
  202. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_backup.py +0 -0
  203. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_datatypes.py +0 -0
  204. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_instance.py +0 -0
  205. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_keyset.py +0 -0
  206. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_merged_result_set.py +0 -0
  207. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_capture.py +0 -0
  208. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_exporter.py +0 -0
  209. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_tracer.py +0 -0
  210. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_tracer_factory.py +0 -0
  211. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_packaging.py +0 -0
  212. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_param_types.py +0 -0
  213. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_spanner_metrics_tracer_factory.py +0 -0
  214. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_streamed.py +0 -0
  215. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/test_table.py +0 -0
  216. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/testdata/singer.proto +0 -0
  217. {google_cloud_spanner-3.61.0 → google_cloud_spanner-3.63.0}/tests/unit/testdata/singer_pb2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-cloud-spanner
3
- Version: 3.61.0
3
+ Version: 3.63.0
4
4
  Summary: Google Cloud Spanner API client library
5
5
  Home-page: https://github.com/googleapis/python-spanner
6
6
  Author: Google LLC
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "3.61.0" # {x-release-please-version}
16
+ __version__ = "3.63.0" # {x-release-please-version}
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "3.61.0" # {x-release-please-version}
16
+ __version__ = "3.63.0" # {x-release-please-version}
@@ -233,6 +233,11 @@ def classify_statement(query, args=None):
233
233
  :rtype: ParsedStatement
234
234
  :returns: parsed statement attributes.
235
235
  """
236
+ # Check for RUN PARTITION command to avoid sqlparse processing it.
237
+ # sqlparse fails with "Maximum grouping depth exceeded" on long partition IDs.
238
+ if re.match(r"^\s*RUN\s+PARTITION\s+.+", query, re.IGNORECASE):
239
+ return client_side_statement_parser.parse_stmt(query.strip())
240
+
236
241
  # sqlparse will strip Cloud Spanner comments,
237
242
  # still, special commenting styles, like
238
243
  # PostgreSQL dollar quoted comments are not
@@ -15,6 +15,6 @@
15
15
  import platform
16
16
 
17
17
  PY_VERSION = platform.python_version()
18
- __version__ = "3.61.0"
18
+ __version__ = "3.63.0"
19
19
  VERSION = __version__
20
20
  DEFAULT_USER_AGENT = "gl-dbapi/" + VERSION
@@ -65,6 +65,7 @@ from .types.type import TypeAnnotationCode
65
65
  from .types.type import TypeCode
66
66
  from .data_types import JsonObject, Interval
67
67
  from .transaction import BatchTransactionId, DefaultTransactionOptions
68
+ from .exceptions import wrap_with_request_id
68
69
 
69
70
  from google.cloud.spanner_v1 import param_types
70
71
  from google.cloud.spanner_v1.client import Client
@@ -88,6 +89,8 @@ __all__ = (
88
89
  # google.cloud.spanner_v1
89
90
  "__version__",
90
91
  "param_types",
92
+ # google.cloud.spanner_v1.exceptions
93
+ "wrap_with_request_id",
91
94
  # google.cloud.spanner_v1.client
92
95
  "Client",
93
96
  # google.cloud.spanner_v1.keyset
@@ -21,6 +21,8 @@ import time
21
21
  import base64
22
22
  import threading
23
23
  import logging
24
+ import uuid
25
+ from contextlib import contextmanager
24
26
 
25
27
  from google.protobuf.struct_pb2 import ListValue
26
28
  from google.protobuf.struct_pb2 import Value
@@ -33,8 +35,12 @@ from google.cloud._helpers import _date_from_iso8601_date
33
35
  from google.cloud.spanner_v1.types import ExecuteSqlRequest
34
36
  from google.cloud.spanner_v1.types import TransactionOptions
35
37
  from google.cloud.spanner_v1.data_types import JsonObject, Interval
36
- from google.cloud.spanner_v1.request_id_header import with_request_id
38
+ from google.cloud.spanner_v1.request_id_header import (
39
+ with_request_id,
40
+ with_request_id_metadata_only,
41
+ )
37
42
  from google.cloud.spanner_v1.types import TypeCode
43
+ from google.cloud.spanner_v1.exceptions import wrap_with_request_id
38
44
 
39
45
  from google.rpc.error_details_pb2 import RetryInfo
40
46
 
@@ -298,6 +304,8 @@ def _make_value_pb(value):
298
304
  return Value(string_value=base64.b64encode(value))
299
305
  if isinstance(value, Interval):
300
306
  return Value(string_value=str(value))
307
+ if isinstance(value, uuid.UUID):
308
+ return Value(string_value=str(value))
301
309
 
302
310
  raise ValueError("Unknown type: %s" % (value,))
303
311
 
@@ -399,6 +407,8 @@ def _get_type_decoder(field_type, field_name, column_info=None):
399
407
  return _parse_numeric
400
408
  elif type_code == TypeCode.JSON:
401
409
  return _parse_json
410
+ elif type_code == TypeCode.UUID:
411
+ return _parse_uuid
402
412
  elif type_code == TypeCode.PROTO:
403
413
  return lambda value_pb: _parse_proto(value_pb, column_info, field_name)
404
414
  elif type_code == TypeCode.ENUM:
@@ -481,6 +491,10 @@ def _parse_json(value_pb):
481
491
  return JsonObject.from_str(value_pb.string_value)
482
492
 
483
493
 
494
+ def _parse_uuid(value_pb):
495
+ return uuid.UUID(value_pb.string_value)
496
+
497
+
484
498
  def _parse_proto(value_pb, column_info, field_name):
485
499
  bytes_value = base64.b64decode(value_pb.string_value)
486
500
  if column_info is not None and column_info.get(field_name) is not None:
@@ -603,9 +617,11 @@ def _retry(
603
617
  try:
604
618
  return func()
605
619
  except Exception as exc:
606
- if (
620
+ is_allowed = (
607
621
  allowed_exceptions is None or exc.__class__ in allowed_exceptions
608
- ) and retries < retry_count:
622
+ )
623
+
624
+ if is_allowed and retries < retry_count:
609
625
  if (
610
626
  allowed_exceptions is not None
611
627
  and allowed_exceptions[exc.__class__] is not None
@@ -758,9 +774,67 @@ class AtomicCounter:
758
774
 
759
775
 
760
776
  def _metadata_with_request_id(*args, **kwargs):
777
+ """Return metadata with request ID header.
778
+
779
+ This function returns only the metadata list (not a tuple),
780
+ maintaining backward compatibility with existing code.
781
+
782
+ Args:
783
+ *args: Arguments to pass to with_request_id
784
+ **kwargs: Keyword arguments to pass to with_request_id
785
+
786
+ Returns:
787
+ list: gRPC metadata with request ID header
788
+ """
789
+ return with_request_id_metadata_only(*args, **kwargs)
790
+
791
+
792
+ def _metadata_with_request_id_and_req_id(*args, **kwargs):
793
+ """Return both metadata and request ID string.
794
+
795
+ This is used when we need to augment errors with the request ID.
796
+
797
+ Args:
798
+ *args: Arguments to pass to with_request_id
799
+ **kwargs: Keyword arguments to pass to with_request_id
800
+
801
+ Returns:
802
+ tuple: (metadata, request_id)
803
+ """
761
804
  return with_request_id(*args, **kwargs)
762
805
 
763
806
 
807
+ def _augment_error_with_request_id(error, request_id=None):
808
+ """Augment an error with request ID information.
809
+
810
+ Args:
811
+ error: The error to augment (typically GoogleAPICallError)
812
+ request_id (str): The request ID to include
813
+
814
+ Returns:
815
+ The augmented error with request ID information
816
+ """
817
+ return wrap_with_request_id(error, request_id)
818
+
819
+
820
+ @contextmanager
821
+ def _augment_errors_with_request_id(request_id):
822
+ """Context manager to augment exceptions with request ID.
823
+
824
+ Args:
825
+ request_id (str): The request ID to include in exceptions
826
+
827
+ Yields:
828
+ None
829
+ """
830
+ try:
831
+ yield
832
+ except Exception as exc:
833
+ augmented = _augment_error_with_request_id(exc, request_id)
834
+ # Use exception chaining to preserve the original exception
835
+ raise augmented from exc
836
+
837
+
764
838
  def _merge_Transaction_Options(
765
839
  defaultTransactionOptions: TransactionOptions,
766
840
  mergeTransactionOptions: TransactionOptions,
@@ -36,6 +36,7 @@ from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
36
36
 
37
37
  TRACER_NAME = "cloud.google.com/python/spanner"
38
38
  TRACER_VERSION = gapic_version.__version__
39
+ GCP_RESOURCE_NAME_PREFIX = "//spanner.googleapis.com/"
39
40
  extended_tracing_globally_disabled = (
40
41
  os.getenv("SPANNER_ENABLE_EXTENDED_TRACING", "").lower() == "false"
41
42
  )
@@ -106,6 +107,7 @@ def trace_call(
106
107
  "gcp.client.service": "spanner",
107
108
  "gcp.client.version": TRACER_VERSION,
108
109
  "gcp.client.repo": "googleapis/python-spanner",
110
+ "gcp.resource.name": GCP_RESOURCE_NAME_PREFIX + db_name,
109
111
  }
110
112
 
111
113
  if extra_attributes:
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """Context manager for Cloud Spanner batched writes."""
16
+
16
17
  import functools
17
18
  from typing import List, Optional
18
19
 
@@ -252,20 +253,22 @@ class Batch(_BatchBase):
252
253
  max_commit_delay=max_commit_delay,
253
254
  request_options=request_options,
254
255
  )
256
+ # This code is retried due to ABORTED, hence nth_request
257
+ # should be increased. attempt can only be increased if
258
+ # we encounter UNAVAILABLE or INTERNAL.
259
+ call_metadata, error_augmenter = database.with_error_augmentation(
260
+ getattr(database, "_next_nth_request", 0),
261
+ 1,
262
+ metadata,
263
+ span,
264
+ )
255
265
  commit_method = functools.partial(
256
266
  api.commit,
257
267
  request=commit_request,
258
- metadata=database.metadata_with_request_id(
259
- # This code is retried due to ABORTED, hence nth_request
260
- # should be increased. attempt can only be increased if
261
- # we encounter UNAVAILABLE or INTERNAL.
262
- getattr(database, "_next_nth_request", 0),
263
- 1,
264
- metadata,
265
- span,
266
- ),
268
+ metadata=call_metadata,
267
269
  )
268
- return commit_method()
270
+ with error_augmenter:
271
+ return commit_method()
269
272
 
270
273
  response = _retry_on_aborted_exception(
271
274
  wrapped_method,
@@ -23,10 +23,12 @@ In the hierarchy of API concepts
23
23
  * a :class:`~google.cloud.spanner_v1.instance.Instance` owns a
24
24
  :class:`~google.cloud.spanner_v1.database.Database`
25
25
  """
26
+
26
27
  import grpc
27
28
  import os
28
29
  import logging
29
30
  import warnings
31
+ import threading
30
32
 
31
33
  from google.api_core.gapic_v1 import client_info
32
34
  from google.auth.credentials import AnonymousCredentials
@@ -99,11 +101,50 @@ def _get_spanner_optimizer_statistics_package():
99
101
 
100
102
  log = logging.getLogger(__name__)
101
103
 
104
+ _metrics_monitor_initialized = False
105
+ _metrics_monitor_lock = threading.Lock()
106
+
102
107
 
103
108
  def _get_spanner_enable_builtin_metrics_env():
104
109
  return os.getenv(SPANNER_DISABLE_BUILTIN_METRICS_ENV_VAR) != "true"
105
110
 
106
111
 
112
+ def _initialize_metrics(project, credentials):
113
+ """
114
+ Initializes the Spanner built-in metrics.
115
+
116
+ This function sets up the OpenTelemetry MeterProvider and the SpannerMetricsTracerFactory.
117
+ It uses a lock to ensure that initialization happens only once.
118
+ """
119
+ global _metrics_monitor_initialized
120
+ if not _metrics_monitor_initialized:
121
+ with _metrics_monitor_lock:
122
+ if not _metrics_monitor_initialized:
123
+ meter_provider = metrics.NoOpMeterProvider()
124
+ try:
125
+ if not _get_spanner_emulator_host():
126
+ meter_provider = MeterProvider(
127
+ metric_readers=[
128
+ PeriodicExportingMetricReader(
129
+ CloudMonitoringMetricsExporter(
130
+ project_id=project,
131
+ credentials=credentials,
132
+ ),
133
+ export_interval_millis=METRIC_EXPORT_INTERVAL_MS,
134
+ ),
135
+ ]
136
+ )
137
+ metrics.set_meter_provider(meter_provider)
138
+ SpannerMetricsTracerFactory()
139
+ _metrics_monitor_initialized = True
140
+ except Exception as e:
141
+ # log is already defined at module level
142
+ log.warning(
143
+ "Failed to initialize Spanner built-in metrics. Error: %s",
144
+ e,
145
+ )
146
+
147
+
107
148
  class Client(ClientWithProject):
108
149
  """Client for interacting with Cloud Spanner API.
109
150
 
@@ -251,31 +292,12 @@ class Client(ClientWithProject):
251
292
  "http://" in self._emulator_host or "https://" in self._emulator_host
252
293
  ):
253
294
  warnings.warn(_EMULATOR_HOST_HTTP_SCHEME)
254
- # Check flag to enable Spanner builtin metrics
255
295
  if (
256
296
  _get_spanner_enable_builtin_metrics_env()
257
297
  and not disable_builtin_metrics
258
298
  and HAS_GOOGLE_CLOUD_MONITORING_INSTALLED
259
299
  ):
260
- meter_provider = metrics.NoOpMeterProvider()
261
- try:
262
- if not _get_spanner_emulator_host():
263
- meter_provider = MeterProvider(
264
- metric_readers=[
265
- PeriodicExportingMetricReader(
266
- CloudMonitoringMetricsExporter(
267
- project_id=project, credentials=credentials
268
- ),
269
- export_interval_millis=METRIC_EXPORT_INTERVAL_MS,
270
- ),
271
- ]
272
- )
273
- metrics.set_meter_provider(meter_provider)
274
- SpannerMetricsTracerFactory()
275
- except Exception as e:
276
- log.warning(
277
- "Failed to initialize Spanner built-in metrics. Error: %s", e
278
- )
300
+ _initialize_metrics(project, credentials)
279
301
  else:
280
302
  SpannerMetricsTracerFactory(enabled=False)
281
303
 
@@ -25,7 +25,6 @@ import threading
25
25
 
26
26
  import google.auth.credentials
27
27
  from google.api_core.retry import Retry
28
- from google.api_core.retry import if_exception_type
29
28
  from google.cloud.exceptions import NotFound
30
29
  from google.api_core.exceptions import Aborted
31
30
  from google.api_core import gapic_v1
@@ -55,6 +54,8 @@ from google.cloud.spanner_v1._helpers import (
55
54
  _metadata_with_prefix,
56
55
  _metadata_with_leader_aware_routing,
57
56
  _metadata_with_request_id,
57
+ _augment_errors_with_request_id,
58
+ _metadata_with_request_id_and_req_id,
58
59
  )
59
60
  from google.cloud.spanner_v1.batch import Batch
60
61
  from google.cloud.spanner_v1.batch import MutationGroups
@@ -496,6 +497,66 @@ class Database(object):
496
497
  span,
497
498
  )
498
499
 
500
+ def metadata_and_request_id(
501
+ self, nth_request, nth_attempt, prior_metadata=[], span=None
502
+ ):
503
+ """Return metadata and request ID string.
504
+
505
+ This method returns both the gRPC metadata with request ID header
506
+ and the request ID string itself, which can be used to augment errors.
507
+
508
+ Args:
509
+ nth_request: The request sequence number
510
+ nth_attempt: The attempt number (for retries)
511
+ prior_metadata: Prior metadata to include
512
+ span: Optional span for tracing
513
+
514
+ Returns:
515
+ tuple: (metadata_list, request_id_string)
516
+ """
517
+ if span is None:
518
+ span = get_current_span()
519
+
520
+ return _metadata_with_request_id_and_req_id(
521
+ self._nth_client_id,
522
+ self._channel_id,
523
+ nth_request,
524
+ nth_attempt,
525
+ prior_metadata,
526
+ span,
527
+ )
528
+
529
+ def with_error_augmentation(
530
+ self, nth_request, nth_attempt, prior_metadata=[], span=None
531
+ ):
532
+ """Context manager for gRPC calls with error augmentation.
533
+
534
+ This context manager provides both metadata with request ID and
535
+ automatically augments any exceptions with the request ID.
536
+
537
+ Args:
538
+ nth_request: The request sequence number
539
+ nth_attempt: The attempt number (for retries)
540
+ prior_metadata: Prior metadata to include
541
+ span: Optional span for tracing
542
+
543
+ Yields:
544
+ tuple: (metadata_list, context_manager)
545
+ """
546
+ if span is None:
547
+ span = get_current_span()
548
+
549
+ metadata, request_id = _metadata_with_request_id_and_req_id(
550
+ self._nth_client_id,
551
+ self._channel_id,
552
+ nth_request,
553
+ nth_attempt,
554
+ prior_metadata,
555
+ span,
556
+ )
557
+
558
+ return metadata, _augment_errors_with_request_id(request_id)
559
+
499
560
  def __eq__(self, other):
500
561
  if not isinstance(other, self.__class__):
501
562
  return NotImplemented
@@ -783,16 +844,18 @@ class Database(object):
783
844
 
784
845
  try:
785
846
  add_span_event(span, "Starting BeginTransaction")
786
- txn = api.begin_transaction(
787
- session=session.name,
788
- options=txn_options,
789
- metadata=self.metadata_with_request_id(
790
- self._next_nth_request,
791
- 1,
792
- metadata,
793
- span,
794
- ),
847
+ call_metadata, error_augmenter = self.with_error_augmentation(
848
+ self._next_nth_request,
849
+ 1,
850
+ metadata,
851
+ span,
795
852
  )
853
+ with error_augmenter:
854
+ txn = api.begin_transaction(
855
+ session=session.name,
856
+ options=txn_options,
857
+ metadata=call_metadata,
858
+ )
796
859
 
797
860
  txn_selector = TransactionSelector(id=txn.id)
798
861
 
@@ -2060,5 +2123,10 @@ def _retry_on_aborted(func, retry_config):
2060
2123
  :type retry_config: Retry
2061
2124
  :param retry_config: retry object with the settings to be used
2062
2125
  """
2063
- retry = retry_config.with_predicate(if_exception_type(Aborted))
2126
+
2127
+ def _is_aborted(exc):
2128
+ """Check if exception is Aborted."""
2129
+ return isinstance(exc, Aborted)
2130
+
2131
+ retry = retry_config.with_predicate(_is_aborted)
2064
2132
  return retry(func)
@@ -0,0 +1,42 @@
1
+ # Copyright 2026 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
+ """Cloud Spanner exception utilities with request ID support."""
16
+
17
+ from google.api_core.exceptions import GoogleAPICallError
18
+
19
+
20
+ def wrap_with_request_id(error, request_id=None):
21
+ """Add request ID information to a GoogleAPICallError.
22
+
23
+ This function adds request_id as an attribute to the exception,
24
+ preserving the original exception type for exception handling compatibility.
25
+ The request_id is also appended to the error message so it appears in logs.
26
+
27
+ Args:
28
+ error: The error to augment. If not a GoogleAPICallError, returns as-is
29
+ request_id (str): The request ID to include
30
+
31
+ Returns:
32
+ The original error with request_id attribute added and message updated
33
+ (if GoogleAPICallError and request_id is provided), otherwise returns
34
+ the original error unchanged.
35
+ """
36
+ if isinstance(error, GoogleAPICallError) and request_id:
37
+ # Add request_id as an attribute for programmatic access
38
+ error.request_id = request_id
39
+ # Modify the message to include request_id so it appears in logs
40
+ if hasattr(error, "message") and error.message:
41
+ error.message = f"{error.message}, request_id = {request_id}"
42
+ return error
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "3.61.0" # {x-release-please-version}
16
+ __version__ = "3.63.0" # {x-release-please-version}
@@ -20,6 +20,8 @@ are consistently recorded for Cloud Spanner operations, facilitating observabili
20
20
  performance monitoring.
21
21
  """
22
22
 
23
+ from contextvars import Token
24
+
23
25
  from .spanner_metrics_tracer_factory import SpannerMetricsTracerFactory
24
26
 
25
27
 
@@ -30,6 +32,9 @@ class MetricsCapture:
30
32
  the start and completion of metrics tracing for a given operation.
31
33
  """
32
34
 
35
+ _token: Token
36
+ """Token to reset the context variable after the operation completes."""
37
+
33
38
  def __enter__(self):
34
39
  """Enter the runtime context related to this object.
35
40
 
@@ -45,11 +50,11 @@ class MetricsCapture:
45
50
  return self
46
51
 
47
52
  # Define a new metrics tracer for the new operation
48
- SpannerMetricsTracerFactory.current_metrics_tracer = (
49
- factory.create_metrics_tracer()
50
- )
51
- if SpannerMetricsTracerFactory.current_metrics_tracer:
52
- SpannerMetricsTracerFactory.current_metrics_tracer.record_operation_start()
53
+ # Set the context var and keep the token for reset
54
+ tracer = factory.create_metrics_tracer()
55
+ self._token = SpannerMetricsTracerFactory.set_current_tracer(tracer)
56
+ if tracer:
57
+ tracer.record_operation_start()
53
58
  return self
54
59
 
55
60
  def __exit__(self, exc_type, exc_value, traceback):
@@ -70,6 +75,11 @@ class MetricsCapture:
70
75
  if not SpannerMetricsTracerFactory().enabled:
71
76
  return False
72
77
 
73
- if SpannerMetricsTracerFactory.current_metrics_tracer:
74
- SpannerMetricsTracerFactory.current_metrics_tracer.record_operation_completion()
78
+ tracer = SpannerMetricsTracerFactory.get_current_tracer()
79
+ if tracer:
80
+ tracer.record_operation_completion()
81
+
82
+ # Reset the context var using the token
83
+ if getattr(self, "_token", None):
84
+ SpannerMetricsTracerFactory.reset_current_tracer(self._token)
75
85
  return False # Propagate the exception if any
@@ -97,22 +97,17 @@ class MetricsInterceptor(ClientInterceptor):
97
97
  Args:
98
98
  resources (Dict[str, str]): A dictionary containing project, instance, and database information.
99
99
  """
100
- if SpannerMetricsTracerFactory.current_metrics_tracer is None:
100
+ tracer = SpannerMetricsTracerFactory.get_current_tracer()
101
+ if tracer is None:
101
102
  return
102
103
 
103
104
  if resources:
104
105
  if "project" in resources:
105
- SpannerMetricsTracerFactory.current_metrics_tracer.set_project(
106
- resources["project"]
107
- )
106
+ tracer.set_project(resources["project"])
108
107
  if "instance" in resources:
109
- SpannerMetricsTracerFactory.current_metrics_tracer.set_instance(
110
- resources["instance"]
111
- )
108
+ tracer.set_instance(resources["instance"])
112
109
  if "database" in resources:
113
- SpannerMetricsTracerFactory.current_metrics_tracer.set_database(
114
- resources["database"]
115
- )
110
+ tracer.set_database(resources["database"])
116
111
 
117
112
  def intercept(self, invoked_method, request_or_iterator, call_details):
118
113
  """Intercept gRPC calls to collect metrics.
@@ -126,31 +121,32 @@ class MetricsInterceptor(ClientInterceptor):
126
121
  The RPC response
127
122
  """
128
123
  factory = SpannerMetricsTracerFactory()
129
- if (
130
- SpannerMetricsTracerFactory.current_metrics_tracer is None
131
- or not factory.enabled
132
- ):
124
+ tracer = SpannerMetricsTracerFactory.get_current_tracer()
125
+ if tracer is None or not factory.enabled:
133
126
  return invoked_method(request_or_iterator, call_details)
134
127
 
135
128
  # Setup Metric Tracer attributes from call details
136
- ## Extract Project / Instance / Databse from header information
137
- resources = self._extract_resource_from_path(call_details.metadata)
138
- self._set_metrics_tracer_attributes(resources)
129
+ ## Extract Project / Instance / Database from header information if not already set
130
+ if not (
131
+ tracer.client_attributes.get("project_id")
132
+ and tracer.client_attributes.get("instance_id")
133
+ and tracer.client_attributes.get("database")
134
+ ):
135
+ resources = self._extract_resource_from_path(call_details.metadata)
136
+ self._set_metrics_tracer_attributes(resources)
139
137
 
140
138
  ## Format method to be be spanner.<method name>
141
139
  method_name = self._remove_prefix(
142
140
  call_details.method, SPANNER_METHOD_PREFIX
143
141
  ).replace("/", ".")
144
142
 
145
- SpannerMetricsTracerFactory.current_metrics_tracer.set_method(method_name)
146
- SpannerMetricsTracerFactory.current_metrics_tracer.record_attempt_start()
143
+ tracer.set_method(method_name)
144
+ tracer.record_attempt_start()
147
145
  response = invoked_method(request_or_iterator, call_details)
148
- SpannerMetricsTracerFactory.current_metrics_tracer.record_attempt_completion()
146
+ tracer.record_attempt_completion()
149
147
 
150
148
  # Process and send GFE metrics if enabled
151
- if SpannerMetricsTracerFactory.current_metrics_tracer.gfe_enabled:
149
+ if tracer.gfe_enabled:
152
150
  metadata = response.initial_metadata()
153
- SpannerMetricsTracerFactory.current_metrics_trace.record_gfe_metrics(
154
- metadata
155
- )
151
+ tracer.record_gfe_metrics(metadata)
156
152
  return response