google-cloud-spanner 3.50.1__tar.gz → 3.51.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 (184) hide show
  1. {google_cloud_spanner-3.50.1/google_cloud_spanner.egg-info → google_cloud_spanner-3.51.0}/PKG-INFO +1 -1
  2. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/gapic_version.py +1 -1
  3. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/gapic_version.py +1 -1
  4. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/connection.py +21 -9
  5. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/parse_utils.py +8 -1
  6. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/_helpers.py +131 -47
  7. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/_opentelemetry_tracing.py +29 -2
  8. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/batch.py +14 -2
  9. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/client.py +21 -0
  10. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/database.py +13 -1
  11. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/gapic_version.py +1 -1
  12. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/pool.py +7 -2
  13. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/session.py +28 -3
  14. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/snapshot.py +100 -14
  15. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/streamed.py +55 -10
  16. google_cloud_spanner-3.51.0/google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
  17. google_cloud_spanner-3.51.0/google/cloud/spanner_v1/testing/mock_spanner.py +216 -0
  18. google_cloud_spanner-3.51.0/google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
  19. google_cloud_spanner-3.51.0/google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
  20. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/transaction.py +38 -6
  21. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0/google_cloud_spanner.egg-info}/PKG-INFO +1 -1
  22. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google_cloud_spanner.egg-info/SOURCES.txt +9 -0
  23. google_cloud_spanner-3.51.0/tests/mockserver_tests/mock_server_test_base.py +139 -0
  24. google_cloud_spanner-3.51.0/tests/mockserver_tests/test_basics.py +87 -0
  25. google_cloud_spanner-3.51.0/tests/system/__init__.py +0 -0
  26. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_dbapi.py +45 -2
  27. google_cloud_spanner-3.51.0/tests/system/test_observability_options.py +134 -0
  28. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_session_api.py +26 -16
  29. google_cloud_spanner-3.51.0/tests/system/utils/__init__.py +0 -0
  30. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_connection.py +31 -0
  31. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_parse_utils.py +2 -1
  32. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_pool.py +29 -3
  33. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/LICENSE +0 -0
  34. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/MANIFEST.in +0 -0
  35. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/README.rst +0 -0
  36. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner.py +0 -0
  37. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/__init__.py +0 -0
  38. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/gapic_metadata.json +0 -0
  39. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/py.typed +0 -0
  40. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/__init__.py +0 -0
  41. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +0 -0
  42. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +0 -0
  43. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/client.py +0 -0
  44. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +0 -0
  45. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +0 -0
  46. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +0 -0
  47. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +0 -0
  48. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +0 -0
  49. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +0 -0
  50. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +0 -0
  51. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/types/__init__.py +0 -0
  52. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/types/backup.py +0 -0
  53. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/types/backup_schedule.py +0 -0
  54. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/types/common.py +0 -0
  55. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +0 -0
  56. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/__init__.py +0 -0
  57. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/gapic_metadata.json +0 -0
  58. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/py.typed +0 -0
  59. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/__init__.py +0 -0
  60. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +0 -0
  61. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +0 -0
  62. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +0 -0
  63. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +0 -0
  64. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +0 -0
  65. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +0 -0
  66. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +0 -0
  67. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +0 -0
  68. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +0 -0
  69. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +0 -0
  70. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/types/__init__.py +0 -0
  71. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/types/common.py +0 -0
  72. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +0 -0
  73. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/__init__.py +0 -0
  74. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/_helpers.py +0 -0
  75. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/batch_dml_executor.py +0 -0
  76. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/checksum.py +0 -0
  77. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/client_side_statement_executor.py +0 -0
  78. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/client_side_statement_parser.py +0 -0
  79. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/cursor.py +0 -0
  80. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/exceptions.py +0 -0
  81. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/parsed_statement.py +0 -0
  82. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/parser.py +0 -0
  83. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/partition_helper.py +0 -0
  84. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/transaction_helper.py +0 -0
  85. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/types.py +0 -0
  86. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/utils.py +0 -0
  87. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_dbapi/version.py +0 -0
  88. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/__init__.py +0 -0
  89. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/backup.py +0 -0
  90. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/data_types.py +0 -0
  91. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/gapic_metadata.json +0 -0
  92. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/instance.py +0 -0
  93. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/keyset.py +0 -0
  94. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/merged_result_set.py +0 -0
  95. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/param_types.py +0 -0
  96. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/py.typed +0 -0
  97. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/__init__.py +0 -0
  98. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/__init__.py +0 -0
  99. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/async_client.py +0 -0
  100. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/client.py +0 -0
  101. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/pagers.py +0 -0
  102. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/__init__.py +0 -0
  103. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/base.py +0 -0
  104. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/grpc.py +0 -0
  105. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +0 -0
  106. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/rest.py +0 -0
  107. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/services/spanner/transports/rest_base.py +0 -0
  108. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/table.py +0 -0
  109. {google_cloud_spanner-3.50.1/tests/system → google_cloud_spanner-3.51.0/google/cloud/spanner_v1/testing}/__init__.py +0 -0
  110. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/testing/database_test.py +0 -0
  111. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/testing/interceptors.py +0 -0
  112. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/__init__.py +0 -0
  113. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/commit_response.py +0 -0
  114. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/keys.py +0 -0
  115. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/mutation.py +0 -0
  116. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/query_plan.py +0 -0
  117. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/result_set.py +0 -0
  118. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/spanner.py +0 -0
  119. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/transaction.py +0 -0
  120. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google/cloud/spanner_v1/types/type.py +0 -0
  121. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google_cloud_spanner.egg-info/dependency_links.txt +0 -0
  122. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google_cloud_spanner.egg-info/not-zip-safe +0 -0
  123. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google_cloud_spanner.egg-info/requires.txt +0 -0
  124. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/google_cloud_spanner.egg-info/top_level.txt +0 -0
  125. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/setup.cfg +0 -0
  126. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/setup.py +0 -0
  127. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/__init__.py +0 -0
  128. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/_fixtures.py +0 -0
  129. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/_helpers.py +0 -0
  130. {google_cloud_spanner-3.50.1/tests/system/utils → google_cloud_spanner-3.51.0/tests/mockserver_tests}/__init__.py +0 -0
  131. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/_helpers.py +0 -0
  132. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/_sample_data.py +0 -0
  133. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/conftest.py +0 -0
  134. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_backup_api.py +0 -0
  135. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_database_api.py +0 -0
  136. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_instance_api.py +0 -0
  137. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_streaming_chunking.py +0 -0
  138. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/test_table_api.py +0 -0
  139. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/testdata/descriptors.pb +0 -0
  140. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/testdata/singer.proto +0 -0
  141. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/testdata/singer_pb2.py +0 -0
  142. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/utils/clear_streaming.py +0 -0
  143. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/utils/populate_streaming.py +0 -0
  144. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/utils/scrub_instances.py +0 -0
  145. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/system/utils/streaming_utils.py +0 -0
  146. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/__init__.py +0 -0
  147. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/__init__.py +0 -0
  148. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_admin_database_v1/__init__.py +0 -0
  149. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py +0 -0
  150. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_admin_instance_v1/__init__.py +0 -0
  151. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py +0 -0
  152. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_v1/__init__.py +0 -0
  153. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/gapic/spanner_v1/test_spanner.py +0 -0
  154. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/__init__.py +0 -0
  155. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test__helpers.py +0 -0
  156. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_batch_dml_executor.py +0 -0
  157. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_checksum.py +0 -0
  158. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_connect.py +0 -0
  159. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_cursor.py +0 -0
  160. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_globals.py +0 -0
  161. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_parser.py +0 -0
  162. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_transaction_helper.py +0 -0
  163. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_types.py +0 -0
  164. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/spanner_dbapi/test_utils.py +0 -0
  165. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/streaming-read-acceptance-test.json +0 -0
  166. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test__helpers.py +0 -0
  167. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test__opentelemetry_tracing.py +0 -0
  168. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_backup.py +0 -0
  169. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_batch.py +0 -0
  170. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_client.py +0 -0
  171. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_database.py +0 -0
  172. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_datatypes.py +0 -0
  173. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_instance.py +0 -0
  174. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_keyset.py +0 -0
  175. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_packaging.py +0 -0
  176. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_param_types.py +0 -0
  177. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_session.py +0 -0
  178. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_snapshot.py +0 -0
  179. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_spanner.py +0 -0
  180. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_streamed.py +0 -0
  181. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_table.py +0 -0
  182. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/test_transaction.py +0 -0
  183. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/testdata/singer.proto +0 -0
  184. {google_cloud_spanner-3.50.1 → google_cloud_spanner-3.51.0}/tests/unit/testdata/singer_pb2.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: google-cloud-spanner
3
- Version: 3.50.1
3
+ Version: 3.51.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.50.1" # {x-release-please-version}
16
+ __version__ = "3.51.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.50.1" # {x-release-please-version}
16
+ __version__ = "3.51.0" # {x-release-please-version}
@@ -89,9 +89,11 @@ class Connection:
89
89
  committed by other transactions since the start of the read-only transaction. Commit or rolling back
90
90
  the read-only transaction is semantically the same, and only indicates that the read-only transaction
91
91
  should end a that a new one should be started when the next statement is executed.
92
+
93
+ **kwargs: Initial value for connection variables.
92
94
  """
93
95
 
94
- def __init__(self, instance, database=None, read_only=False):
96
+ def __init__(self, instance, database=None, read_only=False, **kwargs):
95
97
  self._instance = instance
96
98
  self._database = database
97
99
  self._ddl_statements = []
@@ -117,6 +119,7 @@ class Connection:
117
119
  self._batch_dml_executor: BatchDmlExecutor = None
118
120
  self._transaction_helper = TransactionRetryHelper(self)
119
121
  self._autocommit_dml_mode: AutocommitDmlMode = AutocommitDmlMode.TRANSACTIONAL
122
+ self._connection_variables = kwargs
120
123
 
121
124
  @property
122
125
  def spanner_client(self):
@@ -206,6 +209,10 @@ class Connection:
206
209
  """
207
210
  return (not self._autocommit) or self._transaction_begin_marked
208
211
 
212
+ @property
213
+ def _ignore_transaction_warnings(self):
214
+ return self._connection_variables.get("ignore_transaction_warnings", False)
215
+
209
216
  @property
210
217
  def instance(self):
211
218
  """Instance to which this connection relates.
@@ -232,7 +239,7 @@ class Connection:
232
239
  Args:
233
240
  value (bool): True for ReadOnly mode, False for ReadWrite.
234
241
  """
235
- if self._spanner_transaction_started:
242
+ if self._read_only != value and self._spanner_transaction_started:
236
243
  raise ValueError(
237
244
  "Connection read/write mode can't be changed while a transaction is in progress. "
238
245
  "Commit or rollback the current transaction and try again."
@@ -270,7 +277,7 @@ class Connection:
270
277
  Args:
271
278
  value (dict): Staleness type and value.
272
279
  """
273
- if self._spanner_transaction_started:
280
+ if self._spanner_transaction_started and value != self._staleness:
274
281
  raise ValueError(
275
282
  "`staleness` option can't be changed while a transaction is in progress. "
276
283
  "Commit or rollback the current transaction and try again."
@@ -398,9 +405,10 @@ class Connection:
398
405
  if self.database is None:
399
406
  raise ValueError("Database needs to be passed for this operation")
400
407
  if not self._client_transaction_started:
401
- warnings.warn(
402
- CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
403
- )
408
+ if not self._ignore_transaction_warnings:
409
+ warnings.warn(
410
+ CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
411
+ )
404
412
  return
405
413
 
406
414
  self.run_prior_DDL_statements()
@@ -418,9 +426,10 @@ class Connection:
418
426
  This is a no-op if there is no active client transaction.
419
427
  """
420
428
  if not self._client_transaction_started:
421
- warnings.warn(
422
- CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
423
- )
429
+ if not self._ignore_transaction_warnings:
430
+ warnings.warn(
431
+ CLIENT_TRANSACTION_NOT_STARTED_WARNING, UserWarning, stacklevel=2
432
+ )
424
433
  return
425
434
  try:
426
435
  if self._spanner_transaction_started and not self._read_only:
@@ -654,6 +663,7 @@ def connect(
654
663
  user_agent=None,
655
664
  client=None,
656
665
  route_to_leader_enabled=True,
666
+ **kwargs,
657
667
  ):
658
668
  """Creates a connection to a Google Cloud Spanner database.
659
669
 
@@ -696,6 +706,8 @@ def connect(
696
706
  disable leader aware routing. Disabling leader aware routing would
697
707
  route all requests in RW/PDML transactions to the closest region.
698
708
 
709
+ **kwargs: Initial value for connection variables.
710
+
699
711
 
700
712
  :rtype: :class:`google.cloud.spanner_dbapi.connection.Connection`
701
713
  :returns: Connection object associated with the given Google Cloud Spanner
@@ -29,12 +29,19 @@ from .parsed_statement import ParsedStatement, StatementType, Statement
29
29
  from .types import DateStr, TimestampStr
30
30
  from .utils import sanitize_literals_for_upload
31
31
 
32
+ # Note: This mapping deliberately does not contain a value for float.
33
+ # The reason for that is that it is better to just let Spanner determine
34
+ # the parameter type instead of specifying one explicitly. The reason for
35
+ # this is that if the client specifies FLOAT64, and the actual column that
36
+ # the parameter is used for is of type FLOAT32, then Spanner will return an
37
+ # error. If however the client does not specify a type, then Spanner will
38
+ # automatically choose the appropriate type based on the column where the
39
+ # value will be inserted/updated or that it will be compared with.
32
40
  TYPES_MAP = {
33
41
  bool: spanner.param_types.BOOL,
34
42
  bytes: spanner.param_types.BYTES,
35
43
  str: spanner.param_types.STRING,
36
44
  int: spanner.param_types.INT64,
37
- float: spanner.param_types.FLOAT64,
38
45
  datetime.datetime: spanner.param_types.TIMESTAMP,
39
46
  datetime.date: spanner.param_types.DATE,
40
47
  DateStr: spanner.param_types.DATE,
@@ -266,66 +266,69 @@ def _parse_value_pb(value_pb, field_type, field_name, column_info=None):
266
266
  :returns: value extracted from value_pb
267
267
  :raises ValueError: if unknown type is passed
268
268
  """
269
+ decoder = _get_type_decoder(field_type, field_name, column_info)
270
+ return _parse_nullable(value_pb, decoder)
271
+
272
+
273
+ def _get_type_decoder(field_type, field_name, column_info=None):
274
+ """Returns a function that converts a Value protobuf to cell data.
275
+
276
+ :type field_type: :class:`~google.cloud.spanner_v1.types.Type`
277
+ :param field_type: type code for the value
278
+
279
+ :type field_name: str
280
+ :param field_name: column name
281
+
282
+ :type column_info: dict
283
+ :param column_info: (Optional) dict of column name and column information.
284
+ An object where column names as keys and custom objects as corresponding
285
+ values for deserialization. It's specifically useful for data types like
286
+ protobuf where deserialization logic is on user-specific code. When provided,
287
+ the custom object enables deserialization of backend-received column data.
288
+ If not provided, data remains serialized as bytes for Proto Messages and
289
+ integer for Proto Enums.
290
+
291
+ :rtype: a function that takes a single protobuf value as an input argument
292
+ :returns: a function that can be used to extract a value from a protobuf value
293
+ :raises ValueError: if unknown type is passed
294
+ """
295
+
269
296
  type_code = field_type.code
270
- if value_pb.HasField("null_value"):
271
- return None
272
297
  if type_code == TypeCode.STRING:
273
- return value_pb.string_value
298
+ return _parse_string
274
299
  elif type_code == TypeCode.BYTES:
275
- return value_pb.string_value.encode("utf8")
300
+ return _parse_bytes
276
301
  elif type_code == TypeCode.BOOL:
277
- return value_pb.bool_value
302
+ return _parse_bool
278
303
  elif type_code == TypeCode.INT64:
279
- return int(value_pb.string_value)
304
+ return _parse_int64
280
305
  elif type_code == TypeCode.FLOAT64:
281
- if value_pb.HasField("string_value"):
282
- return float(value_pb.string_value)
283
- else:
284
- return value_pb.number_value
306
+ return _parse_float
285
307
  elif type_code == TypeCode.FLOAT32:
286
- if value_pb.HasField("string_value"):
287
- return float(value_pb.string_value)
288
- else:
289
- return value_pb.number_value
308
+ return _parse_float
290
309
  elif type_code == TypeCode.DATE:
291
- return _date_from_iso8601_date(value_pb.string_value)
310
+ return _parse_date
292
311
  elif type_code == TypeCode.TIMESTAMP:
293
- DatetimeWithNanoseconds = datetime_helpers.DatetimeWithNanoseconds
294
- return DatetimeWithNanoseconds.from_rfc3339(value_pb.string_value)
295
- elif type_code == TypeCode.ARRAY:
296
- return [
297
- _parse_value_pb(
298
- item_pb, field_type.array_element_type, field_name, column_info
299
- )
300
- for item_pb in value_pb.list_value.values
301
- ]
302
- elif type_code == TypeCode.STRUCT:
303
- return [
304
- _parse_value_pb(
305
- item_pb, field_type.struct_type.fields[i].type_, field_name, column_info
306
- )
307
- for (i, item_pb) in enumerate(value_pb.list_value.values)
308
- ]
312
+ return _parse_timestamp
309
313
  elif type_code == TypeCode.NUMERIC:
310
- return decimal.Decimal(value_pb.string_value)
314
+ return _parse_numeric
311
315
  elif type_code == TypeCode.JSON:
312
- return JsonObject.from_str(value_pb.string_value)
316
+ return _parse_json
313
317
  elif type_code == TypeCode.PROTO:
314
- bytes_value = base64.b64decode(value_pb.string_value)
315
- if column_info is not None and column_info.get(field_name) is not None:
316
- default_proto_message = column_info.get(field_name)
317
- if isinstance(default_proto_message, Message):
318
- proto_message = type(default_proto_message)()
319
- proto_message.ParseFromString(bytes_value)
320
- return proto_message
321
- return bytes_value
318
+ return lambda value_pb: _parse_proto(value_pb, column_info, field_name)
322
319
  elif type_code == TypeCode.ENUM:
323
- int_value = int(value_pb.string_value)
324
- if column_info is not None and column_info.get(field_name) is not None:
325
- proto_enum = column_info.get(field_name)
326
- if isinstance(proto_enum, EnumTypeWrapper):
327
- return proto_enum.Name(int_value)
328
- return int_value
320
+ return lambda value_pb: _parse_proto_enum(value_pb, column_info, field_name)
321
+ elif type_code == TypeCode.ARRAY:
322
+ element_decoder = _get_type_decoder(
323
+ field_type.array_element_type, field_name, column_info
324
+ )
325
+ return lambda value_pb: _parse_array(value_pb, element_decoder)
326
+ elif type_code == TypeCode.STRUCT:
327
+ element_decoders = [
328
+ _get_type_decoder(item_field.type_, field_name, column_info)
329
+ for item_field in field_type.struct_type.fields
330
+ ]
331
+ return lambda value_pb: _parse_struct(value_pb, element_decoders)
329
332
  else:
330
333
  raise ValueError("Unknown type: %s" % (field_type,))
331
334
 
@@ -351,6 +354,87 @@ def _parse_list_value_pbs(rows, row_type):
351
354
  return result
352
355
 
353
356
 
357
+ def _parse_string(value_pb) -> str:
358
+ return value_pb.string_value
359
+
360
+
361
+ def _parse_bytes(value_pb):
362
+ return value_pb.string_value.encode("utf8")
363
+
364
+
365
+ def _parse_bool(value_pb) -> bool:
366
+ return value_pb.bool_value
367
+
368
+
369
+ def _parse_int64(value_pb) -> int:
370
+ return int(value_pb.string_value)
371
+
372
+
373
+ def _parse_float(value_pb) -> float:
374
+ if value_pb.HasField("string_value"):
375
+ return float(value_pb.string_value)
376
+ else:
377
+ return value_pb.number_value
378
+
379
+
380
+ def _parse_date(value_pb):
381
+ return _date_from_iso8601_date(value_pb.string_value)
382
+
383
+
384
+ def _parse_timestamp(value_pb):
385
+ DatetimeWithNanoseconds = datetime_helpers.DatetimeWithNanoseconds
386
+ return DatetimeWithNanoseconds.from_rfc3339(value_pb.string_value)
387
+
388
+
389
+ def _parse_numeric(value_pb):
390
+ return decimal.Decimal(value_pb.string_value)
391
+
392
+
393
+ def _parse_json(value_pb):
394
+ return JsonObject.from_str(value_pb.string_value)
395
+
396
+
397
+ def _parse_proto(value_pb, column_info, field_name):
398
+ bytes_value = base64.b64decode(value_pb.string_value)
399
+ if column_info is not None and column_info.get(field_name) is not None:
400
+ default_proto_message = column_info.get(field_name)
401
+ if isinstance(default_proto_message, Message):
402
+ proto_message = type(default_proto_message)()
403
+ proto_message.ParseFromString(bytes_value)
404
+ return proto_message
405
+ return bytes_value
406
+
407
+
408
+ def _parse_proto_enum(value_pb, column_info, field_name):
409
+ int_value = int(value_pb.string_value)
410
+ if column_info is not None and column_info.get(field_name) is not None:
411
+ proto_enum = column_info.get(field_name)
412
+ if isinstance(proto_enum, EnumTypeWrapper):
413
+ return proto_enum.Name(int_value)
414
+ return int_value
415
+
416
+
417
+ def _parse_array(value_pb, element_decoder) -> []:
418
+ return [
419
+ _parse_nullable(item_pb, element_decoder)
420
+ for item_pb in value_pb.list_value.values
421
+ ]
422
+
423
+
424
+ def _parse_struct(value_pb, element_decoders):
425
+ return [
426
+ _parse_nullable(item_pb, element_decoders[i])
427
+ for (i, item_pb) in enumerate(value_pb.list_value.values)
428
+ ]
429
+
430
+
431
+ def _parse_nullable(value_pb, decoder):
432
+ if value_pb.HasField("null_value"):
433
+ return None
434
+ else:
435
+ return decoder(value_pb)
436
+
437
+
354
438
  class _SessionWrapper(object):
355
439
  """Base class for objects wrapping a session.
356
440
 
@@ -15,6 +15,8 @@
15
15
  """Manages OpenTelemetry trace creation and handling"""
16
16
 
17
17
  from contextlib import contextmanager
18
+ from datetime import datetime
19
+ import os
18
20
 
19
21
  from google.cloud.spanner_v1 import SpannerClient
20
22
  from google.cloud.spanner_v1 import gapic_version
@@ -33,6 +35,9 @@ except ImportError:
33
35
 
34
36
  TRACER_NAME = "cloud.google.com/python/spanner"
35
37
  TRACER_VERSION = gapic_version.__version__
38
+ extended_tracing_globally_disabled = (
39
+ os.getenv("SPANNER_ENABLE_EXTENDED_TRACING", "").lower() == "false"
40
+ )
36
41
 
37
42
 
38
43
  def get_tracer(tracer_provider=None):
@@ -51,13 +56,29 @@ def get_tracer(tracer_provider=None):
51
56
 
52
57
 
53
58
  @contextmanager
54
- def trace_call(name, session, extra_attributes=None):
59
+ def trace_call(name, session, extra_attributes=None, observability_options=None):
60
+ if session:
61
+ session._last_use_time = datetime.now()
62
+
55
63
  if not HAS_OPENTELEMETRY_INSTALLED or not session:
56
64
  # Empty context manager. Users will have to check if the generated value is None or a span
57
65
  yield None
58
66
  return
59
67
 
60
- tracer = get_tracer()
68
+ tracer_provider = None
69
+
70
+ # By default enable_extended_tracing=True because in a bid to minimize
71
+ # breaking changes and preserve legacy behavior, we are keeping it turned
72
+ # on by default.
73
+ enable_extended_tracing = True
74
+
75
+ if isinstance(observability_options, dict): # Avoid false positives with mock.Mock
76
+ tracer_provider = observability_options.get("tracer_provider", None)
77
+ enable_extended_tracing = observability_options.get(
78
+ "enable_extended_tracing", enable_extended_tracing
79
+ )
80
+
81
+ tracer = get_tracer(tracer_provider)
61
82
 
62
83
  # Set base attributes that we know for every trace created
63
84
  attributes = {
@@ -72,6 +93,12 @@ def trace_call(name, session, extra_attributes=None):
72
93
  if extra_attributes:
73
94
  attributes.update(extra_attributes)
74
95
 
96
+ if extended_tracing_globally_disabled:
97
+ enable_extended_tracing = False
98
+
99
+ if not enable_extended_tracing:
100
+ attributes.pop("db.statement", False)
101
+
75
102
  with tracer.start_as_current_span(
76
103
  name, kind=trace.SpanKind.CLIENT, attributes=attributes
77
104
  ) as span:
@@ -205,7 +205,13 @@ class Batch(_BatchBase):
205
205
  max_commit_delay=max_commit_delay,
206
206
  request_options=request_options,
207
207
  )
208
- with trace_call("CloudSpanner.Commit", self._session, trace_attributes):
208
+ observability_options = getattr(database, "observability_options", None)
209
+ with trace_call(
210
+ "CloudSpanner.Commit",
211
+ self._session,
212
+ trace_attributes,
213
+ observability_options=observability_options,
214
+ ):
209
215
  method = functools.partial(
210
216
  api.commit,
211
217
  request=request,
@@ -318,7 +324,13 @@ class MutationGroups(_SessionWrapper):
318
324
  request_options=request_options,
319
325
  exclude_txn_from_change_streams=exclude_txn_from_change_streams,
320
326
  )
321
- with trace_call("CloudSpanner.BatchWrite", self._session, trace_attributes):
327
+ observability_options = getattr(database, "observability_options", None)
328
+ with trace_call(
329
+ "CloudSpanner.BatchWrite",
330
+ self._session,
331
+ trace_attributes,
332
+ observability_options=observability_options,
333
+ ):
322
334
  method = functools.partial(
323
335
  api.batch_write,
324
336
  request=request,
@@ -126,6 +126,16 @@ class Client(ClientWithProject):
126
126
  for all ReadRequests and ExecuteSqlRequests that indicates which replicas
127
127
  or regions should be used for non-transactional reads or queries.
128
128
 
129
+ :type observability_options: dict (str -> any) or None
130
+ :param observability_options: (Optional) the configuration to control
131
+ the tracer's behavior.
132
+ tracer_provider is the injected tracer provider
133
+ enable_extended_tracing: :type:boolean when set to true will allow for
134
+ spans that issue SQL statements to be annotated with SQL.
135
+ Default `True`, please set it to `False` to turn it off
136
+ or you can use the environment variable `SPANNER_ENABLE_EXTENDED_TRACING=<boolean>`
137
+ to control it.
138
+
129
139
  :raises: :class:`ValueError <exceptions.ValueError>` if both ``read_only``
130
140
  and ``admin`` are :data:`True`
131
141
  """
@@ -146,6 +156,7 @@ class Client(ClientWithProject):
146
156
  query_options=None,
147
157
  route_to_leader_enabled=True,
148
158
  directed_read_options=None,
159
+ observability_options=None,
149
160
  ):
150
161
  self._emulator_host = _get_spanner_emulator_host()
151
162
 
@@ -187,6 +198,7 @@ class Client(ClientWithProject):
187
198
 
188
199
  self._route_to_leader_enabled = route_to_leader_enabled
189
200
  self._directed_read_options = directed_read_options
201
+ self._observability_options = observability_options
190
202
 
191
203
  @property
192
204
  def credentials(self):
@@ -268,6 +280,15 @@ class Client(ClientWithProject):
268
280
  """
269
281
  return self._route_to_leader_enabled
270
282
 
283
+ @property
284
+ def observability_options(self):
285
+ """Getter for observability_options.
286
+
287
+ :rtype: dict
288
+ :returns: The configured observability_options if set.
289
+ """
290
+ return self._observability_options
291
+
271
292
  @property
272
293
  def directed_read_options(self):
273
294
  """Getter for directed_read_options.
@@ -142,7 +142,7 @@ class Database(object):
142
142
  statements in 'ddl_statements' above.
143
143
  """
144
144
 
145
- _spanner_api = None
145
+ _spanner_api: SpannerClient = None
146
146
 
147
147
  def __init__(
148
148
  self,
@@ -718,6 +718,7 @@ class Database(object):
718
718
  method=method,
719
719
  request=request,
720
720
  transaction_selector=txn_selector,
721
+ observability_options=self.observability_options,
721
722
  )
722
723
 
723
724
  result_set = StreamedResultSet(iterator)
@@ -1106,6 +1107,17 @@ class Database(object):
1106
1107
  response = api.set_iam_policy(request=request, metadata=metadata)
1107
1108
  return response
1108
1109
 
1110
+ @property
1111
+ def observability_options(self):
1112
+ """
1113
+ Returns the observability options that you set when creating
1114
+ the SpannerClient.
1115
+ """
1116
+ if not (self._instance and self._instance._client):
1117
+ return None
1118
+
1119
+ return getattr(self._instance._client, "observability_options", None)
1120
+
1109
1121
 
1110
1122
  class BatchCheckout(object):
1111
1123
  """Context manager for using a batch from a database.
@@ -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.50.1" # {x-release-please-version}
16
+ __version__ = "3.51.0" # {x-release-please-version}
@@ -145,7 +145,8 @@ class FixedSizePool(AbstractSessionPool):
145
145
  - Pre-allocates / creates a fixed number of sessions.
146
146
 
147
147
  - "Pings" existing sessions via :meth:`session.exists` before returning
148
- them, and replaces expired sessions.
148
+ sessions that have not been used for more than 55 minutes and replaces
149
+ expired sessions.
149
150
 
150
151
  - Blocks, with a timeout, when :meth:`get` is called on an empty pool.
151
152
  Raises after timing out.
@@ -171,6 +172,7 @@ class FixedSizePool(AbstractSessionPool):
171
172
 
172
173
  DEFAULT_SIZE = 10
173
174
  DEFAULT_TIMEOUT = 10
175
+ DEFAULT_MAX_AGE_MINUTES = 55
174
176
 
175
177
  def __init__(
176
178
  self,
@@ -178,11 +180,13 @@ class FixedSizePool(AbstractSessionPool):
178
180
  default_timeout=DEFAULT_TIMEOUT,
179
181
  labels=None,
180
182
  database_role=None,
183
+ max_age_minutes=DEFAULT_MAX_AGE_MINUTES,
181
184
  ):
182
185
  super(FixedSizePool, self).__init__(labels=labels, database_role=database_role)
183
186
  self.size = size
184
187
  self.default_timeout = default_timeout
185
188
  self._sessions = queue.LifoQueue(size)
189
+ self._max_age = datetime.timedelta(minutes=max_age_minutes)
186
190
 
187
191
  def bind(self, database):
188
192
  """Associate the pool with a database.
@@ -230,8 +234,9 @@ class FixedSizePool(AbstractSessionPool):
230
234
  timeout = self.default_timeout
231
235
 
232
236
  session = self._sessions.get(block=True, timeout=timeout)
237
+ age = _NOW() - session.last_use_time
233
238
 
234
- if not session.exists():
239
+ if age >= self._max_age and not session.exists():
235
240
  session = self._database.session()
236
241
  session.create()
237
242
 
@@ -17,6 +17,7 @@
17
17
  from functools import total_ordering
18
18
  import random
19
19
  import time
20
+ from datetime import datetime
20
21
 
21
22
  from google.api_core.exceptions import Aborted
22
23
  from google.api_core.exceptions import GoogleAPICallError
@@ -69,6 +70,7 @@ class Session(object):
69
70
  labels = {}
70
71
  self._labels = labels
71
72
  self._database_role = database_role
73
+ self._last_use_time = datetime.utcnow()
72
74
 
73
75
  def __lt__(self, other):
74
76
  return self._session_id < other._session_id
@@ -78,6 +80,14 @@ class Session(object):
78
80
  """Read-only ID, set by the back-end during :meth:`create`."""
79
81
  return self._session_id
80
82
 
83
+ @property
84
+ def last_use_time(self):
85
+ """ "Approximate last use time of this session
86
+
87
+ :rtype: datetime
88
+ :returns: the approximate last use time of this session"""
89
+ return self._last_use_time
90
+
81
91
  @property
82
92
  def database_role(self):
83
93
  """User-assigned database-role for the session.
@@ -142,7 +152,13 @@ class Session(object):
142
152
  if self._labels:
143
153
  request.session.labels = self._labels
144
154
 
145
- with trace_call("CloudSpanner.CreateSession", self, self._labels):
155
+ observability_options = getattr(self._database, "observability_options", None)
156
+ with trace_call(
157
+ "CloudSpanner.CreateSession",
158
+ self,
159
+ self._labels,
160
+ observability_options=observability_options,
161
+ ):
146
162
  session_pb = api.create_session(
147
163
  request=request,
148
164
  metadata=metadata,
@@ -169,7 +185,10 @@ class Session(object):
169
185
  )
170
186
  )
171
187
 
172
- with trace_call("CloudSpanner.GetSession", self) as span:
188
+ observability_options = getattr(self._database, "observability_options", None)
189
+ with trace_call(
190
+ "CloudSpanner.GetSession", self, observability_options=observability_options
191
+ ) as span:
173
192
  try:
174
193
  api.get_session(name=self.name, metadata=metadata)
175
194
  if span:
@@ -194,7 +213,12 @@ class Session(object):
194
213
  raise ValueError("Session ID not set by back-end")
195
214
  api = self._database.spanner_api
196
215
  metadata = _metadata_with_prefix(self._database.name)
197
- with trace_call("CloudSpanner.DeleteSession", self):
216
+ observability_options = getattr(self._database, "observability_options", None)
217
+ with trace_call(
218
+ "CloudSpanner.DeleteSession",
219
+ self,
220
+ observability_options=observability_options,
221
+ ):
198
222
  api.delete_session(name=self.name, metadata=metadata)
199
223
 
200
224
  def ping(self):
@@ -208,6 +232,7 @@ class Session(object):
208
232
  metadata = _metadata_with_prefix(self._database.name)
209
233
  request = ExecuteSqlRequest(session=self.name, sql="SELECT 1")
210
234
  api.execute_sql(request=request, metadata=metadata)
235
+ self._last_use_time = datetime.now()
211
236
 
212
237
  def snapshot(self, **kw):
213
238
  """Create a snapshot to perform a set of reads with shared staleness.