snowflake-connector-python 4.4.0__cp314-cp314-win_amd64.whl

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 (302) hide show
  1. snowflake/connector/__init__.py +118 -0
  2. snowflake/connector/_query_context_cache.py +276 -0
  3. snowflake/connector/_sql_util.py +48 -0
  4. snowflake/connector/_utils.py +353 -0
  5. snowflake/connector/aio/README.md +88 -0
  6. snowflake/connector/aio/__init__.py +163 -0
  7. snowflake/connector/aio/_azure_storage_client.py +227 -0
  8. snowflake/connector/aio/_bind_upload_agent.py +69 -0
  9. snowflake/connector/aio/_connection.py +1216 -0
  10. snowflake/connector/aio/_cursor.py +1402 -0
  11. snowflake/connector/aio/_description.py +5 -0
  12. snowflake/connector/aio/_direct_file_operation_utils.py +88 -0
  13. snowflake/connector/aio/_file_transfer_agent.py +316 -0
  14. snowflake/connector/aio/_gcs_storage_client.py +360 -0
  15. snowflake/connector/aio/_network.py +860 -0
  16. snowflake/connector/aio/_ocsp_asn1crypto.py +51 -0
  17. snowflake/connector/aio/_ocsp_snowflake.py +608 -0
  18. snowflake/connector/aio/_pandas_tools.py +561 -0
  19. snowflake/connector/aio/_result_batch.py +442 -0
  20. snowflake/connector/aio/_result_set.py +309 -0
  21. snowflake/connector/aio/_s3_storage_client.py +460 -0
  22. snowflake/connector/aio/_session_manager.py +588 -0
  23. snowflake/connector/aio/_storage_client.py +331 -0
  24. snowflake/connector/aio/_telemetry.py +97 -0
  25. snowflake/connector/aio/_time_util.py +57 -0
  26. snowflake/connector/aio/_wif_util.py +324 -0
  27. snowflake/connector/aio/auth/__init__.py +52 -0
  28. snowflake/connector/aio/auth/_auth.py +406 -0
  29. snowflake/connector/aio/auth/_by_plugin.py +131 -0
  30. snowflake/connector/aio/auth/_default.py +28 -0
  31. snowflake/connector/aio/auth/_idtoken.py +54 -0
  32. snowflake/connector/aio/auth/_keypair.py +60 -0
  33. snowflake/connector/aio/auth/_no_auth.py +31 -0
  34. snowflake/connector/aio/auth/_oauth.py +27 -0
  35. snowflake/connector/aio/auth/_oauth_code.py +117 -0
  36. snowflake/connector/aio/auth/_oauth_credentials.py +100 -0
  37. snowflake/connector/aio/auth/_okta.py +247 -0
  38. snowflake/connector/aio/auth/_pat.py +27 -0
  39. snowflake/connector/aio/auth/_usrpwdmfa.py +30 -0
  40. snowflake/connector/aio/auth/_webbrowser.py +405 -0
  41. snowflake/connector/aio/auth/_workload_identity.py +60 -0
  42. snowflake/connector/arrow_context.py +211 -0
  43. snowflake/connector/auth/__init__.py +53 -0
  44. snowflake/connector/auth/_auth.py +669 -0
  45. snowflake/connector/auth/_http_server.py +257 -0
  46. snowflake/connector/auth/_oauth_base.py +472 -0
  47. snowflake/connector/auth/by_plugin.py +219 -0
  48. snowflake/connector/auth/default.py +36 -0
  49. snowflake/connector/auth/idtoken.py +72 -0
  50. snowflake/connector/auth/keypair.py +225 -0
  51. snowflake/connector/auth/no_auth.py +39 -0
  52. snowflake/connector/auth/oauth.py +49 -0
  53. snowflake/connector/auth/oauth_code.py +490 -0
  54. snowflake/connector/auth/oauth_credentials.py +71 -0
  55. snowflake/connector/auth/okta.py +339 -0
  56. snowflake/connector/auth/pat.py +40 -0
  57. snowflake/connector/auth/usrpwdmfa.py +69 -0
  58. snowflake/connector/auth/webbrowser.py +514 -0
  59. snowflake/connector/auth/workload_identity.py +110 -0
  60. snowflake/connector/azure_storage_client.py +278 -0
  61. snowflake/connector/backoff_policies.py +141 -0
  62. snowflake/connector/bind_upload_agent.py +89 -0
  63. snowflake/connector/cache.py +696 -0
  64. snowflake/connector/compat.py +127 -0
  65. snowflake/connector/config_manager.py +553 -0
  66. snowflake/connector/connection.py +2671 -0
  67. snowflake/connector/connection_diagnostic.py +793 -0
  68. snowflake/connector/constants.py +460 -0
  69. snowflake/connector/converter.py +809 -0
  70. snowflake/connector/converter_issue23517.py +87 -0
  71. snowflake/connector/converter_null.py +14 -0
  72. snowflake/connector/converter_snowsql.py +205 -0
  73. snowflake/connector/crl.py +919 -0
  74. snowflake/connector/crl_cache.py +734 -0
  75. snowflake/connector/cursor.py +2099 -0
  76. snowflake/connector/dbapi.py +53 -0
  77. snowflake/connector/description.py +21 -0
  78. snowflake/connector/direct_file_operation_utils.py +88 -0
  79. snowflake/connector/encryption_util.py +220 -0
  80. snowflake/connector/errorcode.py +94 -0
  81. snowflake/connector/errors.py +666 -0
  82. snowflake/connector/externals_utils/__init__.py +0 -0
  83. snowflake/connector/externals_utils/externals_setup.py +30 -0
  84. snowflake/connector/feature.py +4 -0
  85. snowflake/connector/file_compression_type.py +118 -0
  86. snowflake/connector/file_lock.py +72 -0
  87. snowflake/connector/file_transfer_agent.py +1244 -0
  88. snowflake/connector/file_util.py +153 -0
  89. snowflake/connector/gcs_storage_client.py +476 -0
  90. snowflake/connector/gzip_decoder.py +85 -0
  91. snowflake/connector/interval_util.py +26 -0
  92. snowflake/connector/local_storage_client.py +90 -0
  93. snowflake/connector/log_configuration.py +62 -0
  94. snowflake/connector/logging_utils/__init__.py +0 -0
  95. snowflake/connector/logging_utils/filters.py +72 -0
  96. snowflake/connector/minicore/__init__.py +0 -0
  97. snowflake/connector/minicore/aix_ppc64/libsf_mini_core.a +0 -0
  98. snowflake/connector/minicore/aix_ppc64/libsf_mini_core_static.a +0 -0
  99. snowflake/connector/minicore/linux_aarch64_glibc/libsf_mini_core.so +0 -0
  100. snowflake/connector/minicore/linux_aarch64_musl/libsf_mini_core.so +0 -0
  101. snowflake/connector/minicore/linux_x86_64_glibc/libsf_mini_core.so +0 -0
  102. snowflake/connector/minicore/linux_x86_64_musl/libsf_mini_core.so +0 -0
  103. snowflake/connector/minicore/macos_aarch64/libsf_mini_core.dylib +0 -0
  104. snowflake/connector/minicore/macos_x86_64/libsf_mini_core.dylib +0 -0
  105. snowflake/connector/minicore/windows_x86_64/sf_mini_core.dll +0 -0
  106. snowflake/connector/minicore/windows_x86_64/sf_mini_core_static.lib +0 -0
  107. snowflake/connector/nanoarrow_arrow_iterator.cp314-win_amd64.pyd +0 -0
  108. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
  109. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  110. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
  111. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  112. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  113. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  114. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +570 -0
  115. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
  116. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
  117. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
  118. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1140 -0
  119. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +138 -0
  120. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
  121. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  122. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
  123. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  124. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
  125. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
  126. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
  127. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  128. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
  129. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  130. snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  131. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  132. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
  133. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +75 -0
  134. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +57 -0
  135. snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  136. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
  137. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  138. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
  139. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  140. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  141. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  142. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
  143. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
  144. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
  145. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  146. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
  147. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  148. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
  149. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  150. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
  151. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
  152. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  153. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +67 -0
  154. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  155. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
  156. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
  157. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  158. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
  159. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
  160. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
  161. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  162. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
  163. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
  164. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  165. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  166. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  167. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
  168. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
  169. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
  170. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  171. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
  172. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
  173. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
  174. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  175. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  176. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
  177. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
  178. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  179. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  180. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  181. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  182. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  183. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
  184. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
  185. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
  186. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  187. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  188. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
  189. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
  190. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
  191. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
  192. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +262 -0
  193. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
  194. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
  195. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
  196. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
  197. snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
  198. snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
  199. snowflake/connector/network.py +1227 -0
  200. snowflake/connector/ocsp_asn1crypto.py +447 -0
  201. snowflake/connector/ocsp_snowflake.py +1939 -0
  202. snowflake/connector/options.py +179 -0
  203. snowflake/connector/os_details.py +88 -0
  204. snowflake/connector/pandas_tools.py +734 -0
  205. snowflake/connector/platform_detection.py +555 -0
  206. snowflake/connector/proxy.py +28 -0
  207. snowflake/connector/py.typed +0 -0
  208. snowflake/connector/result_batch.py +917 -0
  209. snowflake/connector/result_set.py +340 -0
  210. snowflake/connector/s3_storage_client.py +614 -0
  211. snowflake/connector/secret_detector.py +181 -0
  212. snowflake/connector/session_manager.py +650 -0
  213. snowflake/connector/sf_dirs.py +64 -0
  214. snowflake/connector/sfbinaryformat.py +35 -0
  215. snowflake/connector/sfdatetime.py +345 -0
  216. snowflake/connector/snow_logging.py +144 -0
  217. snowflake/connector/sqlstate.py +9 -0
  218. snowflake/connector/ssd_internal_keys.py +30 -0
  219. snowflake/connector/ssl_wrap_socket.py +281 -0
  220. snowflake/connector/storage_client.py +486 -0
  221. snowflake/connector/telemetry.py +254 -0
  222. snowflake/connector/telemetry_oob.py +544 -0
  223. snowflake/connector/test_util.py +30 -0
  224. snowflake/connector/time_util.py +159 -0
  225. snowflake/connector/token_cache.py +457 -0
  226. snowflake/connector/tool/__init__.py +0 -0
  227. snowflake/connector/tool/dump_certs.py +57 -0
  228. snowflake/connector/tool/dump_ocsp_response.py +139 -0
  229. snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
  230. snowflake/connector/tool/probe_connection.py +69 -0
  231. snowflake/connector/url_util.py +55 -0
  232. snowflake/connector/util_text.py +320 -0
  233. snowflake/connector/vendored/__init__.py +3 -0
  234. snowflake/connector/vendored/requests/LICENSE +175 -0
  235. snowflake/connector/vendored/requests/__init__.py +184 -0
  236. snowflake/connector/vendored/requests/__version__.py +14 -0
  237. snowflake/connector/vendored/requests/_internal_utils.py +50 -0
  238. snowflake/connector/vendored/requests/adapters.py +696 -0
  239. snowflake/connector/vendored/requests/api.py +157 -0
  240. snowflake/connector/vendored/requests/auth.py +314 -0
  241. snowflake/connector/vendored/requests/certs.py +17 -0
  242. snowflake/connector/vendored/requests/compat.py +106 -0
  243. snowflake/connector/vendored/requests/cookies.py +561 -0
  244. snowflake/connector/vendored/requests/exceptions.py +151 -0
  245. snowflake/connector/vendored/requests/help.py +134 -0
  246. snowflake/connector/vendored/requests/hooks.py +33 -0
  247. snowflake/connector/vendored/requests/models.py +1039 -0
  248. snowflake/connector/vendored/requests/packages.py +23 -0
  249. snowflake/connector/vendored/requests/sessions.py +831 -0
  250. snowflake/connector/vendored/requests/status_codes.py +128 -0
  251. snowflake/connector/vendored/requests/structures.py +99 -0
  252. snowflake/connector/vendored/requests/utils.py +1086 -0
  253. snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
  254. snowflake/connector/vendored/urllib3/__init__.py +211 -0
  255. snowflake/connector/vendored/urllib3/_base_connection.py +165 -0
  256. snowflake/connector/vendored/urllib3/_collections.py +487 -0
  257. snowflake/connector/vendored/urllib3/_request_methods.py +278 -0
  258. snowflake/connector/vendored/urllib3/_version.py +34 -0
  259. snowflake/connector/vendored/urllib3/connection.py +1108 -0
  260. snowflake/connector/vendored/urllib3/connectionpool.py +1178 -0
  261. snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  262. snowflake/connector/vendored/urllib3/contrib/emscripten/__init__.py +17 -0
  263. snowflake/connector/vendored/urllib3/contrib/emscripten/connection.py +260 -0
  264. snowflake/connector/vendored/urllib3/contrib/emscripten/emscripten_fetch_worker.js +110 -0
  265. snowflake/connector/vendored/urllib3/contrib/emscripten/fetch.py +726 -0
  266. snowflake/connector/vendored/urllib3/contrib/emscripten/request.py +22 -0
  267. snowflake/connector/vendored/urllib3/contrib/emscripten/response.py +277 -0
  268. snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +564 -0
  269. snowflake/connector/vendored/urllib3/contrib/socks.py +228 -0
  270. snowflake/connector/vendored/urllib3/exceptions.py +335 -0
  271. snowflake/connector/vendored/urllib3/fields.py +341 -0
  272. snowflake/connector/vendored/urllib3/filepost.py +89 -0
  273. snowflake/connector/vendored/urllib3/http2/__init__.py +53 -0
  274. snowflake/connector/vendored/urllib3/http2/connection.py +356 -0
  275. snowflake/connector/vendored/urllib3/http2/probe.py +87 -0
  276. snowflake/connector/vendored/urllib3/poolmanager.py +651 -0
  277. snowflake/connector/vendored/urllib3/py.typed +2 -0
  278. snowflake/connector/vendored/urllib3/response.py +1480 -0
  279. snowflake/connector/vendored/urllib3/util/__init__.py +42 -0
  280. snowflake/connector/vendored/urllib3/util/connection.py +137 -0
  281. snowflake/connector/vendored/urllib3/util/proxy.py +43 -0
  282. snowflake/connector/vendored/urllib3/util/request.py +263 -0
  283. snowflake/connector/vendored/urllib3/util/response.py +101 -0
  284. snowflake/connector/vendored/urllib3/util/retry.py +549 -0
  285. snowflake/connector/vendored/urllib3/util/ssl_.py +527 -0
  286. snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
  287. snowflake/connector/vendored/urllib3/util/ssltransport.py +271 -0
  288. snowflake/connector/vendored/urllib3/util/timeout.py +275 -0
  289. snowflake/connector/vendored/urllib3/util/url.py +469 -0
  290. snowflake/connector/vendored/urllib3/util/util.py +42 -0
  291. snowflake/connector/vendored/urllib3/util/wait.py +124 -0
  292. snowflake/connector/version.py +3 -0
  293. snowflake/connector/wif_util.py +434 -0
  294. snowflake_connector_python-4.4.0.dist-info/DELVEWHEEL +2 -0
  295. snowflake_connector_python-4.4.0.dist-info/METADATA +1591 -0
  296. snowflake_connector_python-4.4.0.dist-info/RECORD +302 -0
  297. snowflake_connector_python-4.4.0.dist-info/WHEEL +5 -0
  298. snowflake_connector_python-4.4.0.dist-info/entry_points.txt +4 -0
  299. snowflake_connector_python-4.4.0.dist-info/licenses/LICENSE.txt +202 -0
  300. snowflake_connector_python-4.4.0.dist-info/licenses/NOTICE +8 -0
  301. snowflake_connector_python-4.4.0.dist-info/top_level.txt +1 -0
  302. snowflake_connector_python.libs/msvcp140-0f885b509a685d2bbfa652fed26b5fb3.dll +0 -0
@@ -0,0 +1,1216 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import atexit
5
+ import copy
6
+ import logging
7
+ import os
8
+ import pathlib
9
+ import sys
10
+ import typing
11
+ import uuid
12
+ import warnings
13
+ from contextlib import suppress
14
+ from io import StringIO
15
+ from logging import getLogger
16
+ from types import TracebackType
17
+ from typing import Any, AsyncIterator, Iterable, TypeVar
18
+
19
+ from snowflake.connector import (
20
+ DatabaseError,
21
+ EasyLoggingConfigPython,
22
+ Error,
23
+ OperationalError,
24
+ ProgrammingError,
25
+ )
26
+
27
+ from .._query_context_cache import QueryContextCache
28
+ from ..compat import IS_LINUX, quote, urlencode
29
+ from ..config_manager import CONFIG_MANAGER, _get_default_connection_params
30
+ from ..connection import DEFAULT_CONFIGURATION as DEFAULT_CONFIGURATION_SYNC
31
+ from ..connection import SnowflakeConnection as SnowflakeConnectionSync
32
+ from ..connection import _get_private_bytes_from_file
33
+ from ..constants import (
34
+ _CONNECTIVITY_ERR_MSG,
35
+ _OAUTH_DEFAULT_SCOPE,
36
+ PARAMETER_AUTOCOMMIT,
37
+ PARAMETER_CLIENT_PREFETCH_THREADS,
38
+ PARAMETER_CLIENT_REQUEST_MFA_TOKEN,
39
+ PARAMETER_CLIENT_SESSION_KEEP_ALIVE,
40
+ PARAMETER_CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY,
41
+ PARAMETER_CLIENT_STORE_TEMPORARY_CREDENTIAL,
42
+ PARAMETER_CLIENT_TELEMETRY_ENABLED,
43
+ PARAMETER_CLIENT_VALIDATE_DEFAULT_PARAMETERS,
44
+ PARAMETER_ENABLE_STAGE_S3_PRIVATELINK_FOR_US_EAST_1,
45
+ PARAMETER_QUERY_CONTEXT_CACHE_SIZE,
46
+ PARAMETER_SERVICE_NAME,
47
+ PARAMETER_TIMEZONE,
48
+ QueryStatus,
49
+ )
50
+ from ..description import PLATFORM, PYTHON_VERSION, SNOWFLAKE_CONNECTOR_VERSION
51
+ from ..errorcode import (
52
+ ER_CONNECTION_IS_CLOSED,
53
+ ER_FAILED_TO_CONNECT_TO_DB,
54
+ ER_INVALID_VALUE,
55
+ ER_INVALID_WIF_SETTINGS,
56
+ )
57
+ from ..network import (
58
+ DEFAULT_AUTHENTICATOR,
59
+ EXTERNAL_BROWSER_AUTHENTICATOR,
60
+ KEY_PAIR_AUTHENTICATOR,
61
+ OAUTH_AUTHENTICATOR,
62
+ OAUTH_AUTHORIZATION_CODE,
63
+ OAUTH_CLIENT_CREDENTIALS,
64
+ PAT_WITH_EXTERNAL_SESSION,
65
+ PROGRAMMATIC_ACCESS_TOKEN,
66
+ REQUEST_ID,
67
+ USR_PWD_MFA_AUTHENTICATOR,
68
+ WORKLOAD_IDENTITY_AUTHENTICATOR,
69
+ ReauthenticationRequest,
70
+ )
71
+ from ..sqlstate import SQLSTATE_CONNECTION_NOT_EXISTS, SQLSTATE_FEATURE_NOT_SUPPORTED
72
+ from ..telemetry import TelemetryData, TelemetryField
73
+ from ..time_util import get_time_millis
74
+ from ..util_text import split_statements
75
+ from ..wif_util import AttestationProvider
76
+ from ._cursor import SnowflakeCursor, SnowflakeCursorBase
77
+ from ._description import CLIENT_NAME
78
+ from ._direct_file_operation_utils import FileOperationParser, StreamDownloader
79
+ from ._network import SnowflakeRestful
80
+ from ._session_manager import (
81
+ AioHttpConfig,
82
+ SessionManager,
83
+ SessionManagerFactory,
84
+ SnowflakeSSLConnectorFactory,
85
+ )
86
+ from ._telemetry import TelemetryClient
87
+ from ._time_util import HeartBeatTimer
88
+ from .auth import (
89
+ FIRST_PARTY_AUTHENTICATORS,
90
+ Auth,
91
+ AuthByDefault,
92
+ AuthByIdToken,
93
+ AuthByKeyPair,
94
+ AuthByOAuth,
95
+ AuthByOauthCode,
96
+ AuthByOauthCredentials,
97
+ AuthByOkta,
98
+ AuthByPAT,
99
+ AuthByPlugin,
100
+ AuthByUsrPwdMfa,
101
+ AuthByWebBrowser,
102
+ AuthByWorkloadIdentity,
103
+ )
104
+
105
+ logger = getLogger(__name__)
106
+
107
+ # deep copy to avoid pollute sync config
108
+ DEFAULT_CONFIGURATION = copy.deepcopy(DEFAULT_CONFIGURATION_SYNC)
109
+ DEFAULT_CONFIGURATION["application"] = (CLIENT_NAME, (type(None), str))
110
+
111
+ if sys.version_info >= (3, 13) or typing.TYPE_CHECKING:
112
+ CursorCls = TypeVar("CursorCls", bound=SnowflakeCursorBase, default=SnowflakeCursor)
113
+ else:
114
+ CursorCls = TypeVar("CursorCls", bound=SnowflakeCursorBase)
115
+
116
+
117
+ class SnowflakeConnection(SnowflakeConnectionSync):
118
+ OCSP_ENV_LOCK = asyncio.Lock()
119
+
120
+ def __init__(
121
+ self,
122
+ connection_name: str | None = None,
123
+ connections_file_path: pathlib.Path | None = None,
124
+ **kwargs,
125
+ ) -> None:
126
+ """Create a new SnowflakeConnection.
127
+
128
+ Connections can be loaded from the TOML file located at
129
+ snowflake.connector.constants.CONNECTIONS_FILE.
130
+
131
+ When connection_name is supplied we will first load that connection
132
+ and then override any other values supplied.
133
+
134
+ When no arguments are given (other than connection_file_path) the
135
+ default connection will be loaded first. Note that no overwriting is
136
+ supported in this case.
137
+
138
+ If overwriting values from the default connection is desirable, supply
139
+ the name explicitly.
140
+ """
141
+ # note we don't call super here because asyncio can not/is not recommended
142
+ # to perform async operation in the __init__ while in the sync connection we
143
+ # perform connect
144
+
145
+ self._conn_parameters = self._init_connection_parameters(
146
+ kwargs, connection_name, connections_file_path
147
+ )
148
+ # SNOW-2352456: disable endpoint-based platform detection queries for async connection
149
+ if "platform_detection_timeout_seconds" not in kwargs:
150
+ self._platform_detection_timeout_seconds = 0.0
151
+
152
+ self.expired = False
153
+ # check SNOW-1218851 for long term improvement plan to refactor ocsp code
154
+ atexit.register(self._close_at_exit)
155
+
156
+ # Set up the file operation parser and stream downloader.
157
+ self._file_operation_parser = FileOperationParser(self)
158
+ self._stream_downloader = StreamDownloader(self)
159
+ self._snowflake_version: str | None = None
160
+
161
+ # CRL is disabled for async connection
162
+ self._crl_config = None # default value = disabled
163
+
164
+ @property
165
+ async def snowflake_version(self) -> str:
166
+ # The result from SELECT CURRENT_VERSION() is `<version> <internal hash>`,
167
+ # and we only need the first part
168
+ if self._snowflake_version is None:
169
+ self._snowflake_version = str(
170
+ (
171
+ await (
172
+ await self.cursor().execute("SELECT CURRENT_VERSION()")
173
+ ).fetchall()
174
+ )[0][0]
175
+ ).split(" ")[0]
176
+
177
+ return self._snowflake_version
178
+
179
+ def __enter__(self):
180
+ # async connection does not support sync context manager
181
+ raise TypeError(
182
+ "'SnowflakeConnection' object does not support the context manager protocol"
183
+ )
184
+
185
+ def __exit__(self, exc_type, exc_val, exc_tb):
186
+ # async connection does not support sync context manager
187
+ raise TypeError(
188
+ "'SnowflakeConnection' object does not support the context manager protocol"
189
+ )
190
+
191
+ async def __aenter__(self) -> SnowflakeConnection:
192
+ """Context manager."""
193
+ # Idempotent __aenter__ - required to be able to use both:
194
+ # - with snowflake.connector.aio.SnowflakeConnection(**k)
195
+ # - with snowflake.connector.aio.connect(**k)
196
+ if self.is_closed():
197
+ await self.connect()
198
+ return self
199
+
200
+ async def __aexit__(
201
+ self,
202
+ exc_type: type[BaseException] | None,
203
+ exc_val: BaseException | None,
204
+ exc_tb: TracebackType | None,
205
+ ) -> None:
206
+ """Context manager with commit or rollback teardown."""
207
+ if not self._session_parameters.get("AUTOCOMMIT", False):
208
+ # Either AUTOCOMMIT is turned off, or is not set so we default to old behavior
209
+ if exc_tb is None:
210
+ await self.commit()
211
+ else:
212
+ await self.rollback()
213
+ await self.close()
214
+
215
+ async def __open_connection(self):
216
+ """Opens a new network connection."""
217
+ self.converter = self._converter_class(
218
+ use_numpy=self._numpy, support_negative_year=self._support_negative_year
219
+ )
220
+
221
+ self._rest = SnowflakeRestful(
222
+ host=self.host,
223
+ port=self.port,
224
+ protocol=self._protocol,
225
+ inject_client_pause=self._inject_client_pause,
226
+ connection=self,
227
+ session_manager=self._session_manager, # connection shares the session pool used for making Backend related requests
228
+ )
229
+ logger.debug("REST API object was created: %s:%s", self.host, self.port)
230
+
231
+ if "SF_OCSP_RESPONSE_CACHE_SERVER_URL" in os.environ:
232
+ logger.debug(
233
+ "Custom OCSP Cache Server URL found in environment - %s",
234
+ os.environ["SF_OCSP_RESPONSE_CACHE_SERVER_URL"],
235
+ )
236
+
237
+ if ".privatelink.snowflakecomputing." in self.host.lower():
238
+ await SnowflakeConnection.setup_ocsp_privatelink(
239
+ self.application, self.host
240
+ )
241
+ else:
242
+ if "SF_OCSP_RESPONSE_CACHE_SERVER_URL" in os.environ:
243
+ del os.environ["SF_OCSP_RESPONSE_CACHE_SERVER_URL"]
244
+
245
+ if self._session_parameters is None:
246
+ self._session_parameters = {}
247
+ if self._autocommit is not None:
248
+ self._session_parameters[PARAMETER_AUTOCOMMIT] = self._autocommit
249
+
250
+ if self._timezone is not None:
251
+ self._session_parameters[PARAMETER_TIMEZONE] = self._timezone
252
+
253
+ if self._validate_default_parameters:
254
+ # Snowflake will validate the requested database, schema, and warehouse
255
+ self._session_parameters[PARAMETER_CLIENT_VALIDATE_DEFAULT_PARAMETERS] = (
256
+ True
257
+ )
258
+
259
+ if self.client_session_keep_alive is not None:
260
+ self._session_parameters[PARAMETER_CLIENT_SESSION_KEEP_ALIVE] = (
261
+ self._client_session_keep_alive
262
+ )
263
+
264
+ if self.client_session_keep_alive_heartbeat_frequency is not None:
265
+ self._session_parameters[
266
+ PARAMETER_CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY
267
+ ] = self._validate_client_session_keep_alive_heartbeat_frequency()
268
+
269
+ if self.client_prefetch_threads:
270
+ self._session_parameters[PARAMETER_CLIENT_PREFETCH_THREADS] = (
271
+ self._validate_client_prefetch_threads()
272
+ )
273
+
274
+ # Setup authenticator - validation happens in __config
275
+ auth = Auth(self.rest)
276
+
277
+ if self._session_token and self._master_token:
278
+ await auth._rest.update_tokens(
279
+ self._session_token,
280
+ self._master_token,
281
+ self._master_validity_in_seconds,
282
+ )
283
+ heartbeat_ret = await auth._rest._heartbeat()
284
+ logger.debug(heartbeat_ret)
285
+ if not heartbeat_ret or not heartbeat_ret.get("success"):
286
+ Error.errorhandler_wrapper(
287
+ self,
288
+ None,
289
+ ProgrammingError,
290
+ {
291
+ "msg": "Session and master tokens invalid",
292
+ "errno": ER_INVALID_VALUE,
293
+ },
294
+ )
295
+ else:
296
+ logger.debug("Session and master token validation successful.")
297
+
298
+ else:
299
+ if self.auth_class is not None:
300
+ if type(
301
+ self.auth_class
302
+ ) not in FIRST_PARTY_AUTHENTICATORS and not issubclass(
303
+ type(self.auth_class), AuthByKeyPair
304
+ ):
305
+ raise TypeError("auth_class must be a child class of AuthByKeyPair")
306
+ self.auth_class = self.auth_class
307
+ elif self._authenticator == DEFAULT_AUTHENTICATOR:
308
+ self.auth_class = AuthByDefault(
309
+ password=self._password,
310
+ timeout=self.login_timeout,
311
+ backoff_generator=self._backoff_generator,
312
+ )
313
+ elif self._authenticator == EXTERNAL_BROWSER_AUTHENTICATOR:
314
+ self._session_parameters[
315
+ PARAMETER_CLIENT_STORE_TEMPORARY_CREDENTIAL
316
+ ] = (self._client_store_temporary_credential if IS_LINUX else True)
317
+ auth.read_temporary_credentials(
318
+ self.host,
319
+ self.user,
320
+ self._session_parameters,
321
+ )
322
+ # Depending on whether self._rest.id_token is available we do different
323
+ # auth_instance
324
+ if self._rest.id_token is None:
325
+ self.auth_class = AuthByWebBrowser(
326
+ application=self.application,
327
+ protocol=self._protocol,
328
+ host=self.host,
329
+ port=self.port,
330
+ timeout=self.login_timeout,
331
+ backoff_generator=self._backoff_generator,
332
+ )
333
+ else:
334
+ self.auth_class = AuthByIdToken(
335
+ id_token=self._rest.id_token,
336
+ application=self.application,
337
+ protocol=self._protocol,
338
+ host=self.host,
339
+ port=self.port,
340
+ timeout=self.login_timeout,
341
+ backoff_generator=self._backoff_generator,
342
+ )
343
+
344
+ elif self._authenticator == KEY_PAIR_AUTHENTICATOR:
345
+ private_key = self._private_key
346
+ private_key_passphrase = self._private_key_passphrase
347
+
348
+ if self._private_key_file:
349
+ private_key = _get_private_bytes_from_file(
350
+ self._private_key_file,
351
+ self._private_key_file_pwd,
352
+ )
353
+
354
+ self.auth_class = AuthByKeyPair(
355
+ private_key=private_key,
356
+ private_key_passphrase=private_key_passphrase,
357
+ timeout=self.login_timeout,
358
+ backoff_generator=self._backoff_generator,
359
+ )
360
+ elif self._authenticator == OAUTH_AUTHENTICATOR:
361
+ self.auth_class = AuthByOAuth(
362
+ oauth_token=self._token,
363
+ timeout=self.login_timeout,
364
+ backoff_generator=self._backoff_generator,
365
+ )
366
+ elif self._authenticator == OAUTH_AUTHORIZATION_CODE:
367
+ if self._role and (self._oauth_scope == ""):
368
+ # if role is known then let's inject it into scope
369
+ self._oauth_scope = _OAUTH_DEFAULT_SCOPE.format(role=self._role)
370
+ self.auth_class = AuthByOauthCode(
371
+ application=self.application,
372
+ client_id=self._oauth_client_id,
373
+ client_secret=self._oauth_client_secret,
374
+ host=self.host,
375
+ authentication_url=self._oauth_authorization_url.format(
376
+ host=self.host, port=self.port
377
+ ),
378
+ token_request_url=self._oauth_token_request_url.format(
379
+ host=self.host, port=self.port
380
+ ),
381
+ redirect_uri=self._oauth_redirect_uri,
382
+ uri=self._oauth_socket_uri,
383
+ scope=self._oauth_scope,
384
+ pkce_enabled=not self._oauth_disable_pkce,
385
+ token_cache=(
386
+ auth.get_token_cache()
387
+ if self._client_store_temporary_credential
388
+ else None
389
+ ),
390
+ refresh_token_enabled=self._oauth_enable_refresh_tokens,
391
+ external_browser_timeout=self._external_browser_timeout,
392
+ enable_single_use_refresh_tokens=self._oauth_enable_single_use_refresh_tokens,
393
+ )
394
+ elif self._authenticator == OAUTH_CLIENT_CREDENTIALS:
395
+ if self._role and (self._oauth_scope == ""):
396
+ # if role is known then let's inject it into scope
397
+ self._oauth_scope = _OAUTH_DEFAULT_SCOPE.format(role=self._role)
398
+ self.auth_class = AuthByOauthCredentials(
399
+ application=self.application,
400
+ client_id=self._oauth_client_id,
401
+ client_secret=self._oauth_client_secret,
402
+ token_request_url=self._oauth_token_request_url.format(
403
+ host=self.host, port=self.port
404
+ ),
405
+ scope=self._oauth_scope,
406
+ connection=self,
407
+ credentials_in_body=self._oauth_credentials_in_body,
408
+ )
409
+ elif self._authenticator == PROGRAMMATIC_ACCESS_TOKEN:
410
+ self.auth_class = AuthByPAT(self._token)
411
+ elif self._authenticator == PAT_WITH_EXTERNAL_SESSION:
412
+ # TODO: SNOW-2344581: add support for PAT with external session ID for async connection
413
+ raise ProgrammingError(
414
+ msg="PAT with external session ID is not supported for async connection.",
415
+ errno=ER_INVALID_VALUE,
416
+ )
417
+ elif self._authenticator == USR_PWD_MFA_AUTHENTICATOR:
418
+ self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN] = (
419
+ self._client_request_mfa_token if IS_LINUX else True
420
+ )
421
+ if self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN]:
422
+ auth.read_temporary_credentials(
423
+ self.host,
424
+ self.user,
425
+ self._session_parameters,
426
+ )
427
+ self.auth_class = AuthByUsrPwdMfa(
428
+ password=self._password,
429
+ mfa_token=self.rest.mfa_token,
430
+ timeout=self.login_timeout,
431
+ backoff_generator=self._backoff_generator,
432
+ )
433
+ elif self._authenticator == WORKLOAD_IDENTITY_AUTHENTICATOR:
434
+ if isinstance(self._workload_identity_provider, str):
435
+ self._workload_identity_provider = AttestationProvider.from_string(
436
+ self._workload_identity_provider
437
+ )
438
+ if not self._workload_identity_provider:
439
+ Error.errorhandler_wrapper(
440
+ self,
441
+ None,
442
+ ProgrammingError,
443
+ {
444
+ "msg": f"workload_identity_provider must be set to one of {','.join(AttestationProvider.all_string_values())} when authenticator is WORKLOAD_IDENTITY.",
445
+ "errno": ER_INVALID_WIF_SETTINGS,
446
+ },
447
+ )
448
+ if (
449
+ self._workload_identity_impersonation_path
450
+ and self._workload_identity_provider
451
+ not in (
452
+ AttestationProvider.GCP,
453
+ AttestationProvider.AWS,
454
+ )
455
+ ):
456
+ Error.errorhandler_wrapper(
457
+ self,
458
+ None,
459
+ ProgrammingError,
460
+ {
461
+ "msg": "workload_identity_impersonation_path is currently only supported for GCP and AWS.",
462
+ "errno": ER_INVALID_WIF_SETTINGS,
463
+ },
464
+ )
465
+ self.auth_class = AuthByWorkloadIdentity(
466
+ provider=self._workload_identity_provider,
467
+ token=self._token,
468
+ entra_resource=self._workload_identity_entra_resource,
469
+ impersonation_path=self._workload_identity_impersonation_path,
470
+ )
471
+ else:
472
+ # okta URL, e.g., https://<account>.okta.com/
473
+ self.auth_class = AuthByOkta(
474
+ application=self.application,
475
+ timeout=self.login_timeout,
476
+ backoff_generator=self._backoff_generator,
477
+ )
478
+
479
+ await self.authenticate_with_retry(self.auth_class)
480
+
481
+ self._password = None # ensure password won't persist
482
+ await self.auth_class.reset_secrets()
483
+
484
+ self.initialize_query_context_cache()
485
+
486
+ if self.client_session_keep_alive:
487
+ # This will be called after the heartbeat frequency has actually been set.
488
+ # By this point it should have been decided if the heartbeat has to be enabled
489
+ # and what would the heartbeat frequency be
490
+ await self._add_heartbeat()
491
+
492
+ async def _add_heartbeat(self) -> None:
493
+ """Add a periodic heartbeat query in order to keep connection alive."""
494
+ if not self._heartbeat_task:
495
+ self._heartbeat_task = HeartBeatTimer(
496
+ self.client_session_keep_alive_heartbeat_frequency, self._heartbeat_tick
497
+ )
498
+ await self._heartbeat_task.start()
499
+ logger.debug("started heartbeat")
500
+
501
+ async def _heartbeat_tick(self) -> None:
502
+ """Execute a heartbeat if connection isn't closed yet."""
503
+ if not self.is_closed():
504
+ logger.debug("heartbeating!")
505
+ await self.rest._heartbeat()
506
+
507
+ async def _all_async_queries_finished(self) -> bool:
508
+ """Checks whether all async queries started by this Connection have finished executing."""
509
+
510
+ if not self._async_sfqids:
511
+ return True
512
+
513
+ queries = list(reversed(self._async_sfqids.keys()))
514
+
515
+ found_unfinished_query = False
516
+
517
+ async def async_query_check_helper(
518
+ sfq_id: str,
519
+ ) -> bool:
520
+ try:
521
+ nonlocal found_unfinished_query
522
+ return found_unfinished_query or self.is_still_running(
523
+ await self.get_query_status(sfq_id)
524
+ )
525
+ except asyncio.CancelledError:
526
+ pass
527
+
528
+ tasks = [
529
+ asyncio.create_task(async_query_check_helper(sfqid)) for sfqid in queries
530
+ ]
531
+ for task in asyncio.as_completed(tasks):
532
+ if await task:
533
+ found_unfinished_query = True
534
+ break
535
+ for task in tasks:
536
+ task.cancel()
537
+ await asyncio.gather(*tasks)
538
+ return not found_unfinished_query
539
+
540
+ async def _authenticate(self, auth_instance: AuthByPlugin):
541
+ await auth_instance.prepare(
542
+ conn=self,
543
+ authenticator=self._authenticator,
544
+ service_name=self.service_name,
545
+ account=self.account,
546
+ user=self.user,
547
+ password=self._password,
548
+ )
549
+ self._consent_cache_id_token = getattr(
550
+ auth_instance, "consent_cache_id_token", True
551
+ )
552
+
553
+ auth = Auth(self.rest)
554
+ # record start time for computing timeout
555
+ auth_instance._retry_ctx.set_start_time()
556
+ try:
557
+ await auth.authenticate(
558
+ auth_instance=auth_instance,
559
+ account=self.account,
560
+ user=self.user,
561
+ database=self.database,
562
+ schema=self.schema,
563
+ warehouse=self.warehouse,
564
+ role=self.role,
565
+ passcode=self._passcode,
566
+ passcode_in_password=self._passcode_in_password,
567
+ mfa_callback=self._mfa_callback,
568
+ password_callback=self._password_callback,
569
+ session_parameters=self._session_parameters,
570
+ )
571
+ except OperationalError as e:
572
+ logger.debug(
573
+ "Operational Error raised at authentication"
574
+ f"for authenticator: {type(auth_instance).__name__}"
575
+ )
576
+ while True:
577
+ try:
578
+ await auth_instance.handle_timeout(
579
+ authenticator=self._authenticator,
580
+ service_name=self.service_name,
581
+ account=self.account,
582
+ user=self.user,
583
+ password=self._password,
584
+ )
585
+ await auth.authenticate(
586
+ auth_instance=auth_instance,
587
+ account=self.account,
588
+ user=self.user,
589
+ database=self.database,
590
+ schema=self.schema,
591
+ warehouse=self.warehouse,
592
+ role=self.role,
593
+ passcode=self._passcode,
594
+ passcode_in_password=self._passcode_in_password,
595
+ mfa_callback=self._mfa_callback,
596
+ password_callback=self._password_callback,
597
+ session_parameters=self._session_parameters,
598
+ )
599
+ except OperationalError as auth_op:
600
+ if auth_op.errno == ER_FAILED_TO_CONNECT_TO_DB:
601
+ if _CONNECTIVITY_ERR_MSG in e.msg:
602
+ auth_op.msg += f"\n{_CONNECTIVITY_ERR_MSG}"
603
+ raise auth_op from e
604
+ logger.debug("Continuing authenticator specific timeout handling")
605
+ continue
606
+ break
607
+
608
+ async def _cancel_heartbeat(self) -> None:
609
+ """Cancel a heartbeat thread."""
610
+ if self._heartbeat_task:
611
+ await self._heartbeat_task.stop()
612
+ self._heartbeat_task = None
613
+ logger.debug("stopped heartbeat")
614
+
615
+ def _init_connection_parameters(
616
+ self,
617
+ connection_init_kwargs: dict,
618
+ connection_name: str | None = None,
619
+ connections_file_path: pathlib.Path | None = None,
620
+ ) -> dict:
621
+ ret_kwargs = connection_init_kwargs
622
+ self._unsafe_skip_file_permissions_check = ret_kwargs.get(
623
+ "unsafe_skip_file_permissions_check", False
624
+ )
625
+ easy_logging = EasyLoggingConfigPython(
626
+ skip_config_file_permissions_check=self._unsafe_skip_file_permissions_check
627
+ )
628
+ easy_logging.create_log()
629
+ self._lock_sequence_counter = asyncio.Lock()
630
+ self.sequence_counter = 0
631
+ self._errorhandler = Error.default_errorhandler
632
+ self._lock_converter = asyncio.Lock()
633
+ self.messages = []
634
+ self._async_sfqids: dict[str, None] = {}
635
+ self._done_async_sfqids: dict[str, None] = {}
636
+ self._client_param_telemetry_enabled = True
637
+ self._server_param_telemetry_enabled = False
638
+ self._session_parameters: dict[str, str | int | bool] = {}
639
+ logger.info(
640
+ "Snowflake Connector for Python Version: %s, "
641
+ "Python Version: %s, Platform: %s",
642
+ SNOWFLAKE_CONNECTOR_VERSION,
643
+ PYTHON_VERSION,
644
+ PLATFORM,
645
+ )
646
+
647
+ # Placeholder attributes; will be initialized in connect()
648
+ self._http_config: AioHttpConfig | None = None
649
+ self._session_manager: SessionManager | None = None
650
+ self._rest = None
651
+ for name, (value, _) in DEFAULT_CONFIGURATION.items():
652
+ setattr(self, f"_{name}", value)
653
+
654
+ self._heartbeat_task = None
655
+ is_kwargs_empty = not connection_init_kwargs
656
+
657
+ if "application" not in connection_init_kwargs:
658
+ app = self._detect_application()
659
+ if app:
660
+ connection_init_kwargs["application"] = app
661
+
662
+ if "insecure_mode" in connection_init_kwargs:
663
+ warn_message = "The 'insecure_mode' connection property is deprecated. Please use 'disable_ocsp_checks' instead"
664
+ warnings.warn(
665
+ warn_message,
666
+ DeprecationWarning,
667
+ stacklevel=2,
668
+ )
669
+
670
+ if (
671
+ "disable_ocsp_checks" in connection_init_kwargs
672
+ and connection_init_kwargs["disable_ocsp_checks"]
673
+ != connection_init_kwargs["insecure_mode"]
674
+ ):
675
+ logger.warning(
676
+ "The values for 'disable_ocsp_checks' and 'insecure_mode' differ. "
677
+ "Using the value of 'disable_ocsp_checks."
678
+ )
679
+ else:
680
+ self._disable_ocsp_checks = connection_init_kwargs["insecure_mode"]
681
+
682
+ self.converter = None
683
+ self.query_context_cache: QueryContextCache | None = None
684
+ self.query_context_cache_size = 5
685
+ if connections_file_path is not None:
686
+ # Change config file path and force update cache
687
+ for i, s in enumerate(CONFIG_MANAGER._slices):
688
+ if s.section == "connections":
689
+ CONFIG_MANAGER._slices[i] = s._replace(path=connections_file_path)
690
+ CONFIG_MANAGER.read_config(
691
+ skip_file_permissions_check=self._unsafe_skip_file_permissions_check
692
+ )
693
+ break
694
+ if connection_name is not None:
695
+ connections = CONFIG_MANAGER["connections"]
696
+ if connection_name not in connections:
697
+ raise Error(
698
+ f"Invalid connection_name '{connection_name}',"
699
+ f" known ones are {list(connections.keys())}"
700
+ )
701
+ ret_kwargs = {**connections[connection_name], **connection_init_kwargs}
702
+ elif is_kwargs_empty:
703
+ # connection_name is None and kwargs was empty when called
704
+ ret_kwargs = _get_default_connection_params()
705
+ # TODO: SNOW-1770153 on self.__set_error_attributes()
706
+ return ret_kwargs
707
+
708
+ async def _cancel_query(
709
+ self, sql: str, request_id: uuid.UUID
710
+ ) -> dict[str, bool | None]:
711
+ """Cancels the query with the exact SQL query and requestId."""
712
+ logger.debug("_cancel_query sql=[%s], request_id=[%s]", sql, request_id)
713
+ url_parameters = {REQUEST_ID: str(uuid.uuid4())}
714
+
715
+ return await self.rest.request(
716
+ "/queries/v1/abort-request?" + urlencode(url_parameters),
717
+ {
718
+ "sqlText": sql,
719
+ REQUEST_ID: str(request_id),
720
+ },
721
+ )
722
+
723
+ def _close_at_exit(self):
724
+ with suppress(Exception):
725
+ asyncio.run(self.close(retry=False))
726
+
727
+ async def _get_query_status(
728
+ self, sf_qid: str
729
+ ) -> tuple[QueryStatus, dict[str, Any]]:
730
+ """Retrieves the status of query with sf_qid and returns it with the raw response.
731
+
732
+ This is the underlying function used by the public get_status functions.
733
+
734
+ Args:
735
+ sf_qid: Snowflake query id of interest.
736
+
737
+ Raises:
738
+ ValueError: if sf_qid is not a valid UUID string.
739
+ """
740
+ try:
741
+ uuid.UUID(sf_qid)
742
+ except ValueError:
743
+ raise ValueError(f"Invalid UUID: '{sf_qid}'")
744
+ logger.debug(f"get_query_status sf_qid='{sf_qid}'")
745
+
746
+ status = "NO_DATA"
747
+ if self.is_closed():
748
+ return QueryStatus.DISCONNECTED, {"data": {"queries": []}}
749
+ status_resp = await self.rest.request(
750
+ "/monitoring/queries/" + quote(sf_qid), method="get", client="rest"
751
+ )
752
+ if "queries" not in status_resp["data"]:
753
+ return QueryStatus.FAILED_WITH_ERROR, status_resp
754
+ queries = status_resp["data"]["queries"]
755
+ if len(queries) > 0:
756
+ status = queries[0]["status"]
757
+ status_ret = QueryStatus[status]
758
+ return status_ret, status_resp
759
+
760
+ async def _log_telemetry(self, telemetry_data) -> None:
761
+ if self.telemetry_enabled:
762
+ await self._telemetry.try_add_log_to_batch(telemetry_data)
763
+
764
+ async def _log_telemetry_imported_packages(self) -> None:
765
+ if self._log_imported_packages_in_telemetry:
766
+ # filter out duplicates caused by submodules
767
+ # and internal modules with names starting with an underscore
768
+ imported_modules = {
769
+ k.split(".", maxsplit=1)[0]
770
+ for k in list(sys.modules)
771
+ if not k.startswith("_")
772
+ }
773
+ ts = get_time_millis()
774
+ await self._log_telemetry(
775
+ TelemetryData.from_telemetry_data_dict(
776
+ from_dict={
777
+ TelemetryField.KEY_TYPE.value: TelemetryField.IMPORTED_PACKAGES.value,
778
+ TelemetryField.KEY_VALUE.value: str(imported_modules),
779
+ },
780
+ timestamp=ts,
781
+ connection=self,
782
+ )
783
+ )
784
+
785
+ async def _next_sequence_counter(self) -> int:
786
+ """Gets next sequence counter. Used internally."""
787
+ async with self._lock_sequence_counter:
788
+ self.sequence_counter += 1
789
+ logger.debug("sequence counter: %s", self.sequence_counter)
790
+ return self.sequence_counter
791
+
792
+ async def _update_parameters(
793
+ self,
794
+ parameters: dict[str, str | int | bool],
795
+ ) -> None:
796
+ """Update session parameters."""
797
+ async with self._lock_converter:
798
+ self.converter.set_parameters(parameters)
799
+ for name, value in parameters.items():
800
+ self._session_parameters[name] = value
801
+ if PARAMETER_CLIENT_TELEMETRY_ENABLED == name:
802
+ self._server_param_telemetry_enabled = value
803
+ elif PARAMETER_CLIENT_SESSION_KEEP_ALIVE == name:
804
+ # Only set if the local config is None.
805
+ # Always give preference to user config.
806
+ if self.client_session_keep_alive is None:
807
+ self.client_session_keep_alive = value
808
+ elif (
809
+ PARAMETER_CLIENT_SESSION_KEEP_ALIVE_HEARTBEAT_FREQUENCY == name
810
+ and self.client_session_keep_alive_heartbeat_frequency is None
811
+ ):
812
+ # Only set if local value hasn't been set already.
813
+ self.client_session_keep_alive_heartbeat_frequency = value
814
+ elif PARAMETER_SERVICE_NAME == name:
815
+ self.service_name = value
816
+ elif PARAMETER_CLIENT_PREFETCH_THREADS == name:
817
+ self.client_prefetch_threads = value
818
+ elif PARAMETER_ENABLE_STAGE_S3_PRIVATELINK_FOR_US_EAST_1 == name:
819
+ self.enable_stage_s3_privatelink_for_us_east_1 = value
820
+ elif PARAMETER_QUERY_CONTEXT_CACHE_SIZE == name:
821
+ self.query_context_cache_size = value
822
+
823
+ async def _reauthenticate(self):
824
+ return await self._auth_class.reauthenticate(conn=self)
825
+
826
+ @property
827
+ def auth_class(self) -> AuthByPlugin | None:
828
+ return self._auth_class
829
+
830
+ @auth_class.setter
831
+ def auth_class(self, value: AuthByPlugin) -> None:
832
+ if isinstance(value, AuthByPlugin):
833
+ self._auth_class = value
834
+ else:
835
+ raise TypeError("auth_class must subclass AuthByPluginAsync")
836
+
837
+ @property
838
+ def client_prefetch_threads(self) -> int:
839
+ return self._client_prefetch_threads
840
+
841
+ @client_prefetch_threads.setter
842
+ def client_prefetch_threads(self, value) -> None:
843
+ self._client_prefetch_threads = value
844
+
845
+ @property
846
+ def errorhandler(self) -> None:
847
+ # check SNOW-1763103
848
+ raise NotImplementedError(
849
+ "Async Snowflake Python Connector does not support errorhandler. "
850
+ "Please open a feature request issue in github if your want this feature: "
851
+ "https://github.com/snowflakedb/snowflake-connector-python/issues/new/choose."
852
+ )
853
+
854
+ @errorhandler.setter
855
+ def errorhandler(self, value) -> None:
856
+ # check SNOW-1763103
857
+ raise NotImplementedError(
858
+ "Async Snowflake Python Connector does not support errorhandler. "
859
+ "Please open a feature request issue in github if your want this feature: "
860
+ "https://github.com/snowflakedb/snowflake-connector-python/issues/new/choose."
861
+ )
862
+
863
+ @property
864
+ def rest(self) -> SnowflakeRestful | None:
865
+ return self._rest
866
+
867
+ async def authenticate_with_retry(self, auth_instance) -> None:
868
+ # make some changes if needed before real __authenticate
869
+ try:
870
+ await self._authenticate(auth_instance)
871
+ except ReauthenticationRequest as ex:
872
+ # cached id_token expiration error, we have cleaned id_token and try to authenticate again
873
+ logger.debug("ID token expired. Reauthenticating...: %s", ex)
874
+ if type(auth_instance) in (
875
+ AuthByIdToken,
876
+ AuthByOauthCode,
877
+ AuthByOauthCredentials,
878
+ ):
879
+ # Note: SNOW-733835 IDToken auth needs to authenticate through
880
+ # SSO if it has expired
881
+ await self._reauthenticate()
882
+ else:
883
+ await self._authenticate(auth_instance)
884
+
885
+ async def autocommit(self, mode) -> None:
886
+ """Sets autocommit mode to True, or False. Defaults to True."""
887
+ if not self.rest:
888
+ Error.errorhandler_wrapper(
889
+ self,
890
+ None,
891
+ DatabaseError,
892
+ {
893
+ "msg": "Connection is closed",
894
+ "errno": ER_CONNECTION_IS_CLOSED,
895
+ "sqlstate": SQLSTATE_CONNECTION_NOT_EXISTS,
896
+ },
897
+ )
898
+ if not isinstance(mode, bool):
899
+ Error.errorhandler_wrapper(
900
+ self,
901
+ None,
902
+ ProgrammingError,
903
+ {
904
+ "msg": f"Invalid parameter: {mode}",
905
+ "errno": ER_INVALID_VALUE,
906
+ },
907
+ )
908
+ try:
909
+ await self.cursor().execute(f"ALTER SESSION SET autocommit={mode}")
910
+ except Error as e:
911
+ if e.sqlstate == SQLSTATE_FEATURE_NOT_SUPPORTED:
912
+ logger.debug(
913
+ "Autocommit feature is not enabled for this " "connection. Ignored"
914
+ )
915
+
916
+ async def close(self, retry: bool = True) -> None:
917
+ """Closes the connection."""
918
+ # unregister to dereference connection object as it's already closed after the execution
919
+ atexit.unregister(self._close_at_exit)
920
+ try:
921
+ if not self.rest:
922
+ logger.debug("Rest object has been destroyed, cannot close session")
923
+ return
924
+
925
+ # will hang if the application doesn't close the connection and
926
+ # CLIENT_SESSION_KEEP_ALIVE is set, because the heartbeat runs on
927
+ # a separate thread.
928
+ await self._cancel_heartbeat()
929
+
930
+ # close telemetry first, since it needs rest to send remaining data
931
+ logger.debug("closed")
932
+
933
+ if self.telemetry_enabled:
934
+ await self._telemetry.close(retry=retry)
935
+
936
+ if not self._server_session_keep_alive:
937
+ if await self._all_async_queries_finished():
938
+ logger.debug(
939
+ "No async queries seem to be running, deleting session"
940
+ )
941
+ try:
942
+ await self.rest.delete_session(retry=retry)
943
+ except Exception as e:
944
+ logger.debug(
945
+ "Exception encountered in deleting session. ignoring...: %s",
946
+ e,
947
+ )
948
+ else:
949
+ logger.debug(
950
+ "There are {} async queries still running, not deleting session".format(
951
+ len(self._async_sfqids)
952
+ )
953
+ )
954
+ else:
955
+ logger.info(
956
+ "Parameter server_session_keep_alive was set to True - skipping session logout. "
957
+ "If there are any not-finished queries in the current session (session_id: %s) - "
958
+ "they will continue to live in Snowflake and consume credits until they finish. "
959
+ "To cancel them use Monitoring tab in Snowsight or plain SQL.",
960
+ self.session_id,
961
+ )
962
+ await self.rest.close()
963
+ self._rest = None
964
+ if self.query_context_cache:
965
+ self.query_context_cache.clear_cache()
966
+ del self.messages[:]
967
+ logger.debug("Session is closed")
968
+ except Exception as e:
969
+ logger.debug(
970
+ "Exception encountered in closing connection. ignoring...: %s", e
971
+ )
972
+
973
+ async def cmd_query(
974
+ self,
975
+ sql: str,
976
+ sequence_counter: int,
977
+ request_id: uuid.UUID,
978
+ binding_params: None | tuple | dict[str, dict[str, str]] = None,
979
+ binding_stage: str | None = None,
980
+ is_file_transfer: bool = False,
981
+ statement_params: dict[str, str] | None = None,
982
+ is_internal: bool = False,
983
+ describe_only: bool = False,
984
+ _no_results: bool = False,
985
+ _update_current_object: bool = True,
986
+ _no_retry: bool = False,
987
+ timeout: int | None = None,
988
+ dataframe_ast: str | None = None,
989
+ ) -> dict[str, Any]:
990
+ """Executes a query with a sequence counter."""
991
+ logger.debug("_cmd_query")
992
+ data = {
993
+ "sqlText": sql,
994
+ "asyncExec": _no_results,
995
+ "sequenceId": sequence_counter,
996
+ "querySubmissionTime": get_time_millis(),
997
+ }
998
+ if dataframe_ast is not None:
999
+ data["dataframeAst"] = dataframe_ast
1000
+ if statement_params is not None:
1001
+ data["parameters"] = statement_params
1002
+ if is_internal:
1003
+ data["isInternal"] = is_internal
1004
+ if describe_only:
1005
+ data["describeOnly"] = describe_only
1006
+ if binding_stage is not None:
1007
+ # binding stage for bulk array binding
1008
+ data["bindStage"] = binding_stage
1009
+ if binding_params is not None:
1010
+ # binding parameters. This is for qmarks paramstyle.
1011
+ data["bindings"] = binding_params
1012
+ if not _no_results:
1013
+ # not an async query.
1014
+ queryContext = self.get_query_context()
1015
+ # Here queryContextDTO should be a dict object field, same with `parameters` field
1016
+ data["queryContextDTO"] = queryContext
1017
+ client = "sfsql_file_transfer" if is_file_transfer else "sfsql"
1018
+
1019
+ if logger.getEffectiveLevel() <= logging.DEBUG:
1020
+ logger.debug(
1021
+ "sql=[%s], sequence_id=[%s], is_file_transfer=[%s]",
1022
+ self._format_query_for_log(data["sqlText"]),
1023
+ data["sequenceId"],
1024
+ is_file_transfer,
1025
+ )
1026
+
1027
+ url_parameters = {REQUEST_ID: request_id}
1028
+
1029
+ ret = await self.rest.request(
1030
+ "/queries/v1/query-request?" + urlencode(url_parameters),
1031
+ data,
1032
+ client=client,
1033
+ _no_results=_no_results,
1034
+ _include_retry_params=True,
1035
+ _no_retry=_no_retry,
1036
+ timeout=timeout,
1037
+ )
1038
+
1039
+ if ret is None:
1040
+ ret = {"data": {}}
1041
+ if ret.get("data") is None:
1042
+ ret["data"] = {}
1043
+ if _update_current_object:
1044
+ data = ret["data"]
1045
+ if "finalDatabaseName" in data and data["finalDatabaseName"] is not None:
1046
+ self._database = data["finalDatabaseName"]
1047
+ if "finalSchemaName" in data and data["finalSchemaName"] is not None:
1048
+ self._schema = data["finalSchemaName"]
1049
+ if "finalWarehouseName" in data and data["finalWarehouseName"] is not None:
1050
+ self._warehouse = data["finalWarehouseName"]
1051
+ if "finalRoleName" in data:
1052
+ self._role = data["finalRoleName"]
1053
+ if "queryContext" in data and not _no_results:
1054
+ # here the data["queryContext"] field has been automatically converted from JSON into a dict type
1055
+ self.set_query_context(data["queryContext"])
1056
+
1057
+ return ret
1058
+
1059
+ async def commit(self) -> None:
1060
+ """Commits the current transaction."""
1061
+ await self.cursor().execute("COMMIT")
1062
+
1063
+ async def connect(self, **kwargs) -> None:
1064
+ """Establishes connection to Snowflake."""
1065
+ logger.debug("connect")
1066
+ if len(kwargs) > 0:
1067
+ self.__config(**kwargs)
1068
+ else:
1069
+ self.__config(**self._conn_parameters)
1070
+
1071
+ no_proxy_csv_str = (
1072
+ ",".join(str(x) for x in self.no_proxy)
1073
+ if (
1074
+ self.no_proxy is not None
1075
+ and isinstance(self.no_proxy, Iterable)
1076
+ and not isinstance(self.no_proxy, (str, bytes))
1077
+ )
1078
+ else self.no_proxy
1079
+ )
1080
+ self._http_config: AioHttpConfig = AioHttpConfig(
1081
+ connector_factory=SnowflakeSSLConnectorFactory(),
1082
+ use_pooling=not self.disable_request_pooling,
1083
+ proxy_host=self.proxy_host,
1084
+ proxy_port=self.proxy_port,
1085
+ proxy_user=self.proxy_user,
1086
+ proxy_password=self.proxy_password,
1087
+ snowflake_ocsp_mode=self._ocsp_mode(),
1088
+ trust_env=True, # Required for proxy support via environment variables
1089
+ no_proxy=no_proxy_csv_str,
1090
+ )
1091
+ self._session_manager = SessionManagerFactory.get_manager(self._http_config)
1092
+
1093
+ if self.enable_connection_diag:
1094
+ raise NotImplementedError(
1095
+ "Connection diagnostic is not supported in asyncio"
1096
+ )
1097
+ else:
1098
+ await self.__open_connection()
1099
+ self._telemetry = TelemetryClient(self._rest)
1100
+ await self._log_telemetry_imported_packages()
1101
+
1102
+ def cursor(self, cursor_class: type[CursorCls] = SnowflakeCursor) -> CursorCls:
1103
+ logger.debug("cursor")
1104
+ if not self.rest:
1105
+ Error.errorhandler_wrapper(
1106
+ self,
1107
+ None,
1108
+ DatabaseError,
1109
+ {
1110
+ "msg": "Connection is closed.\nPlease establish the connection first by "
1111
+ "explicitly calling `await SnowflakeConnection.connect()` or "
1112
+ "using an async context manager: `async with SnowflakeConnection() as conn`. "
1113
+ "\nEnsure the connection is open before attempting any operations.",
1114
+ "errno": ER_CONNECTION_IS_CLOSED,
1115
+ "sqlstate": SQLSTATE_CONNECTION_NOT_EXISTS,
1116
+ },
1117
+ )
1118
+ return cursor_class(self)
1119
+
1120
+ async def execute_stream(
1121
+ self,
1122
+ stream: StringIO,
1123
+ remove_comments: bool = False,
1124
+ cursor_class: type[SnowflakeCursor] = SnowflakeCursor,
1125
+ **kwargs,
1126
+ ) -> AsyncIterator[SnowflakeCursor, None, None]:
1127
+ """Executes a stream of SQL statements. This is a non-standard convenient method."""
1128
+ split_statements_list = split_statements(
1129
+ stream, remove_comments=remove_comments
1130
+ )
1131
+ # Note: split_statements_list is a list of tuples of sql statements and whether they are put/get
1132
+ non_empty_statements = [e for e in split_statements_list if e[0]]
1133
+ for sql, is_put_or_get in non_empty_statements:
1134
+ cur = self.cursor(cursor_class=cursor_class)
1135
+ await cur.execute(sql, _is_put_get=is_put_or_get, **kwargs)
1136
+ yield cur
1137
+
1138
+ async def execute_string(
1139
+ self,
1140
+ sql_text: str,
1141
+ remove_comments: bool = False,
1142
+ return_cursors: bool = True,
1143
+ cursor_class: type[SnowflakeCursor] = SnowflakeCursor,
1144
+ **kwargs,
1145
+ ) -> Iterable[SnowflakeCursor]:
1146
+ """Executes a SQL text including multiple statements. This is a non-standard convenience method."""
1147
+ stream = StringIO(sql_text)
1148
+ ret = []
1149
+ async for cursor in self.execute_stream(
1150
+ stream, remove_comments=remove_comments, cursor_class=cursor_class, **kwargs
1151
+ ):
1152
+ ret.append(cursor)
1153
+
1154
+ return ret if return_cursors else list()
1155
+
1156
+ async def get_query_status(self, sf_qid: str) -> QueryStatus:
1157
+ """Retrieves the status of query with sf_qid.
1158
+
1159
+ Query status is returned as a QueryStatus.
1160
+
1161
+ Args:
1162
+ sf_qid: Snowflake query id of interest.
1163
+
1164
+ Raises:
1165
+ ValueError: if sf_qid is not a valid UUID string.
1166
+ """
1167
+ status, _ = await self._get_query_status(sf_qid)
1168
+ self._cache_query_status(sf_qid, status)
1169
+ return status
1170
+
1171
+ async def get_query_status_throw_if_error(self, sf_qid: str) -> QueryStatus:
1172
+ """Retrieves the status of query with sf_qid as a QueryStatus and raises an exception if the query terminated with an error.
1173
+
1174
+ Query status is returned as a QueryStatus.
1175
+
1176
+ Args:
1177
+ sf_qid: Snowflake query id of interest.
1178
+
1179
+ Raises:
1180
+ ValueError: if sf_qid is not a valid UUID string.
1181
+ """
1182
+ status, status_resp = await self._get_query_status(sf_qid)
1183
+ self._cache_query_status(sf_qid, status)
1184
+ if self.is_an_error(status):
1185
+ self._process_error_query_status(sf_qid, status_resp)
1186
+ return status
1187
+
1188
+ @staticmethod
1189
+ async def setup_ocsp_privatelink(app, hostname) -> None:
1190
+ hostname = hostname.lower()
1191
+ async with SnowflakeConnection.OCSP_ENV_LOCK:
1192
+ ocsp_cache_server = f"http://ocsp.{hostname}/ocsp_response_cache.json"
1193
+ os.environ["SF_OCSP_RESPONSE_CACHE_SERVER_URL"] = ocsp_cache_server
1194
+ logger.debug("OCSP Cache Server is updated: %s", ocsp_cache_server)
1195
+
1196
+ async def rollback(self) -> None:
1197
+ """Rolls back the current transaction."""
1198
+ await self.cursor().execute("ROLLBACK")
1199
+
1200
+ async def is_valid(self) -> bool:
1201
+ """This function tries to answer the question: Is this connection still good for sending queries?
1202
+ Attempts to validate the connections both on the TCP/IP and Session levels."""
1203
+ logger.debug("validating connection and session")
1204
+ if self.is_closed():
1205
+ logger.debug("connection is already closed and not valid")
1206
+ return False
1207
+
1208
+ try:
1209
+ logger.debug("trying to heartbeat into the session to validate")
1210
+ hb_result = await self.rest._heartbeat()
1211
+ session_valid = hb_result.get("success")
1212
+ logger.debug("session still valid? %s", session_valid)
1213
+ return bool(session_valid)
1214
+ except Exception as e:
1215
+ logger.debug("session could not be validated due to exception: %s", e)
1216
+ return False