snowflake-connector-python 5.2.0__cp315-cp315-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 (204) hide show
  1. snowflake/connector/__init__.py +148 -0
  2. snowflake/connector/_common/__init__.py +0 -0
  3. snowflake/connector/_common/extras.py +134 -0
  4. snowflake/connector/_common/telemetry.py +221 -0
  5. snowflake/connector/_common/wif_util.py +92 -0
  6. snowflake/connector/_core/sf_core_python.cp315-win_amd64.pyd +0 -0
  7. snowflake/connector/_core/sf_core_python.pyi +79 -0
  8. snowflake/connector/_internal/__init__.py +6 -0
  9. snowflake/connector/_internal/_private_key_helper.py +31 -0
  10. snowflake/connector/_internal/api_client/__init__.py +93 -0
  11. snowflake/connector/_internal/api_client/bridge.py +41 -0
  12. snowflake/connector/_internal/api_client/client_api.py +976 -0
  13. snowflake/connector/_internal/arrow.py +47 -0
  14. snowflake/connector/_internal/arrow_context.py +240 -0
  15. snowflake/connector/_internal/arrow_stream_async.py +266 -0
  16. snowflake/connector/_internal/arrow_stream_iterator.cp311-win_amd64.pyd +0 -0
  17. snowflake/connector/_internal/arrow_stream_iterator.cp312-win_amd64.pyd +0 -0
  18. snowflake/connector/_internal/arrow_stream_iterator.cp313-win_amd64.pyd +0 -0
  19. snowflake/connector/_internal/arrow_stream_iterator.cp314-win_amd64.pyd +0 -0
  20. snowflake/connector/_internal/arrow_stream_iterator.cp314t-win_amd64.pyd +0 -0
  21. snowflake/connector/_internal/arrow_stream_iterator.cp315-win_amd64.pyd +0 -0
  22. snowflake/connector/_internal/arrow_stream_iterator.pyi +42 -0
  23. snowflake/connector/_internal/arrow_stream_utils.py +171 -0
  24. snowflake/connector/_internal/authenticator_type.py +53 -0
  25. snowflake/connector/_internal/backward_compatibility.py +245 -0
  26. snowflake/connector/_internal/binding_converters.py +741 -0
  27. snowflake/connector/_internal/config_utils.py +71 -0
  28. snowflake/connector/_internal/connection/__init__.py +39 -0
  29. snowflake/connector/_internal/connection/connection.py +616 -0
  30. snowflake/connector/_internal/connection/connection_types.py +13 -0
  31. snowflake/connector/_internal/connection/constants.py +25 -0
  32. snowflake/connector/_internal/connection/decorators.py +31 -0
  33. snowflake/connector/_internal/connection/freezable_proxy.py +104 -0
  34. snowflake/connector/_internal/connection/queries.py +10 -0
  35. snowflake/connector/_internal/connection_config_mixin.py +755 -0
  36. snowflake/connector/_internal/cursor/__init__.py +25 -0
  37. snowflake/connector/_internal/cursor/base.py +732 -0
  38. snowflake/connector/_internal/cursor/cursor_types.py +13 -0
  39. snowflake/connector/_internal/cursor/decorators.py +56 -0
  40. snowflake/connector/_internal/cursor/query_result.py +202 -0
  41. snowflake/connector/_internal/cursor/query_result_waiter.py +98 -0
  42. snowflake/connector/_internal/cursor/result_metadata.py +255 -0
  43. snowflake/connector/_internal/cursor/result_set_wrapper.py +66 -0
  44. snowflake/connector/_internal/decorators.py +539 -0
  45. snowflake/connector/_internal/error_kinds.py +111 -0
  46. snowflake/connector/_internal/errorcode.py +35 -0
  47. snowflake/connector/_internal/errorhandler.py +278 -0
  48. snowflake/connector/_internal/fips.py +28 -0
  49. snowflake/connector/_internal/logging/__init__.py +52 -0
  50. snowflake/connector/_internal/logging/config.py +134 -0
  51. snowflake/connector/_internal/logging/core_logger.py +218 -0
  52. snowflake/connector/_internal/logging/native_extension_logger.py +144 -0
  53. snowflake/connector/_internal/logout_config_mapping.py +187 -0
  54. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +57 -0
  55. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  56. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.cpp +943 -0
  57. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.hpp +63 -0
  58. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +18 -0
  59. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  60. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  61. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  62. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +118 -0
  63. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +116 -0
  64. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.cpp +323 -0
  65. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.hpp +133 -0
  66. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.cpp +275 -0
  67. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.hpp +168 -0
  68. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.cpp +439 -0
  69. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.hpp +30 -0
  70. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +48 -0
  71. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  72. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +76 -0
  73. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  74. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +90 -0
  75. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +63 -0
  76. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +62 -0
  77. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  78. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +29 -0
  79. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  80. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  81. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  82. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +41 -0
  83. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +65 -0
  84. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +54 -0
  85. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  86. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +79 -0
  87. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  88. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +52 -0
  89. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  90. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  91. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +117 -0
  92. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +54 -0
  93. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +34 -0
  94. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +33 -0
  95. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  96. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +18 -0
  97. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  98. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +39 -0
  99. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  100. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +326 -0
  101. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +138 -0
  102. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  103. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  104. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  105. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.cpp +13278 -0
  106. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.pyx +204 -0
  107. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +109 -0
  108. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +125 -0
  109. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  110. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1914 -0
  111. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +208 -0
  112. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +128 -0
  113. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  114. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +58 -0
  115. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +144 -0
  116. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  117. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  118. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  119. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +160 -0
  120. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +98 -0
  121. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +243 -0
  122. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  123. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +207 -0
  124. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +80 -0
  125. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +83 -0
  126. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  127. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  128. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +201 -0
  129. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +108 -0
  130. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  131. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  132. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  133. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  134. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  135. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +164 -0
  136. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +926 -0
  137. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +182 -0
  138. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  139. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  140. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc.c +3052 -0
  141. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3019 -0
  142. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3354 -0
  143. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +344 -0
  144. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +29305 -0
  145. snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +381 -0
  146. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.cpp +108 -0
  147. snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.hpp +47 -0
  148. snowflake/connector/_internal/nanoarrow_cpp/scripts/.clang-format +8 -0
  149. snowflake/connector/_internal/nanoarrow_cpp/scripts/format.sh +8 -0
  150. snowflake/connector/_internal/protobuf_gen/__init__.py +0 -0
  151. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.py +408 -0
  152. snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.pyi +4487 -0
  153. snowflake/connector/_internal/protobuf_gen/database_driver_v1_services.py +2088 -0
  154. snowflake/connector/_internal/protobuf_gen/proto_exception.py +17 -0
  155. snowflake/connector/_internal/result_batch.py +150 -0
  156. snowflake/connector/_internal/snowflake_restful.py +222 -0
  157. snowflake/connector/_internal/snowpark_backcompat_helpers.py +31 -0
  158. snowflake/connector/_internal/sqlstate.py +11 -0
  159. snowflake/connector/_internal/statement_utils.py +207 -0
  160. snowflake/connector/_internal/text_utils.py +112 -0
  161. snowflake/connector/_internal/type_codes.py +139 -0
  162. snowflake/connector/_internal/utils.py +65 -0
  163. snowflake/connector/_internal/write_pandas_operation.py +657 -0
  164. snowflake/connector/aio/README.md +168 -0
  165. snowflake/connector/aio/__init__.py +37 -0
  166. snowflake/connector/aio/connection/__init__.py +17 -0
  167. snowflake/connector/aio/connection/_connection.py +506 -0
  168. snowflake/connector/aio/cursor/__init__.py +35 -0
  169. snowflake/connector/aio/cursor/_base.py +1034 -0
  170. snowflake/connector/aio/cursor/_dict_cursor.py +78 -0
  171. snowflake/connector/aio/cursor/_result_set_wrapper.py +35 -0
  172. snowflake/connector/aio/cursor/_snowflake_cursor.py +72 -0
  173. snowflake/connector/aio/pandas_tools.py +279 -0
  174. snowflake/connector/aio/result_batch.py +165 -0
  175. snowflake/connector/auth/__init__.py +0 -0
  176. snowflake/connector/auth/workload_identity.py +5 -0
  177. snowflake/connector/compat.py +22 -0
  178. snowflake/connector/config_manager.py +392 -0
  179. snowflake/connector/connection/__init__.py +30 -0
  180. snowflake/connector/connection/_connection.py +641 -0
  181. snowflake/connector/connection_config.py +517 -0
  182. snowflake/connector/constants.py +52 -0
  183. snowflake/connector/cursor/__init__.py +37 -0
  184. snowflake/connector/cursor/_base.py +1169 -0
  185. snowflake/connector/cursor/_chunked_download_reader.py +75 -0
  186. snowflake/connector/cursor/_dict_cursor.py +78 -0
  187. snowflake/connector/cursor/_result_set_wrapper.py +35 -0
  188. snowflake/connector/cursor/_snowflake_cursor.py +72 -0
  189. snowflake/connector/description.py +7 -0
  190. snowflake/connector/errors.py +492 -0
  191. snowflake/connector/network.py +71 -0
  192. snowflake/connector/pandas_tools.py +191 -0
  193. snowflake/connector/py.typed +0 -0
  194. snowflake/connector/result_batch.py +216 -0
  195. snowflake/connector/telemetry.py +40 -0
  196. snowflake/connector/time_util.py +11 -0
  197. snowflake/connector/types.py +134 -0
  198. snowflake/connector/util_text.py +3 -0
  199. snowflake/connector/version.py +23 -0
  200. snowflake_connector_python-5.2.0.dist-info/DELVEWHEEL +2 -0
  201. snowflake_connector_python-5.2.0.dist-info/METADATA +190 -0
  202. snowflake_connector_python-5.2.0.dist-info/RECORD +204 -0
  203. snowflake_connector_python-5.2.0.dist-info/WHEEL +4 -0
  204. snowflake_connector_python.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
@@ -0,0 +1,641 @@
1
+ """PEP 249 Connection implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import atexit
6
+ import logging
7
+ import os
8
+ import platform
9
+ import threading
10
+ import warnings
11
+
12
+ from collections.abc import Callable, Generator, Iterable, Iterator
13
+ from functools import cached_property
14
+ from io import StringIO
15
+ from typing import Any, TypeVar, cast, overload
16
+
17
+ from .._common.telemetry import TelemetryClient as _InternalTelemetryClient
18
+ from .._internal.api_client.client_api import core_driver
19
+ from .._internal.config_utils import create_config_settings_from_dict
20
+ from .._internal.connection import (
21
+ APPLICATION_NAME,
22
+ COMMIT_SQL,
23
+ CURRENT_VERSION_SQL,
24
+ ROLLBACK_SQL,
25
+ SET_AUTOCOMMIT_SQL,
26
+ SET_CLIENT_PREFETCH_THREADS_SQL,
27
+ ConnectionMixin,
28
+ clamp_client_prefetch_threads,
29
+ requires_open,
30
+ validate_query_id,
31
+ )
32
+ from .._internal.connection.freezable_proxy import ConnectionInfoProxy, SessionParametersProxy
33
+ from .._internal.decorators import api_telemetry, backward_compatibility, internal_api, pep249
34
+ from .._internal.errorcode import ER_INVALID_VALUE, ER_INVALID_WIF_SETTINGS
35
+ from .._internal.logging import get_logger
36
+ from .._internal.logout_config_mapping import (
37
+ LogoutOptionKeys,
38
+ logout_config_options_modifier,
39
+ )
40
+ from .._internal.protobuf_gen.database_driver_v1_pb2 import (
41
+ VALIDATION_CODE_CONFLICTING_WIF_PARAMETERS,
42
+ ConnectionHandle,
43
+ DatabaseHandle,
44
+ WrapperIdentity,
45
+ )
46
+ from .._internal.protobuf_gen.database_driver_v1_services import (
47
+ ConnectionGetQueryStatusResponse,
48
+ )
49
+ from .._internal.snowflake_restful import SnowflakeRestful
50
+ from .._internal.text_utils import split_statements
51
+ from .._internal.utils import get_application_path
52
+ from ..connection_config import ConnectionConfig
53
+ from ..constants import QueryStatus
54
+ from ..cursor import CursorInstance, CursorType, DictCursor, SnowflakeCursor, SnowflakeCursorBase
55
+ from ..errors import Error, ProgrammingError
56
+ from ..version import __version__
57
+
58
+
59
+ logger = get_logger(__name__)
60
+
61
+ _CursorClsT = TypeVar("_CursorClsT", bound=SnowflakeCursorBase)
62
+
63
+
64
+ # Both WIF cross-param guards in sf_core's validate_settings emit a dedicated
65
+ # ValidationCode, so the wrapper can key on the code alone without matching
66
+ # parameter names or message text.
67
+ def _is_wif_conflict(exc: ProgrammingError) -> bool:
68
+ return exc.validation_code == VALIDATION_CODE_CONFLICTING_WIF_PARAMETERS
69
+
70
+
71
+ class Connection(ConnectionMixin):
72
+ """Connection objects represent a database connection."""
73
+
74
+ _session_parameters: SessionParametersProxy
75
+ _connection_info: ConnectionInfoProxy
76
+ _default_cursor_class = SnowflakeCursor
77
+
78
+ # ------------------------------------------------------------------
79
+ # Initialization
80
+ # ------------------------------------------------------------------
81
+
82
+ @api_telemetry
83
+ def __init__(
84
+ self,
85
+ *,
86
+ connection_name: str | None = None,
87
+ connections_file_path: str | os.PathLike[str] | None = None,
88
+ config: ConnectionConfig | None = None,
89
+ **kwargs: Any,
90
+ ) -> None:
91
+ """
92
+ Initialize a new connection object.
93
+
94
+ ``connection_name``, ``connections_file_path`` and ``config`` are
95
+ keyword-only to preserve the previous calling contract — the legacy
96
+ ``__init__`` was ``(self, **kwargs)`` so any positional argument was
97
+ a ``TypeError``. Keeping these keyword-only guarantees that an
98
+ accidental positional call fails fast instead of being silently
99
+ bound to one of the new parameters.
100
+
101
+ Args:
102
+ connection_name: Named connection to load from TOML configuration files
103
+ connections_file_path: Path to the connections configuration file the named
104
+ profile — or, when no other connection option is given, the default
105
+ profile — is read from, instead of the standard config location
106
+ config: Pre-built ConnectionConfig object (mutually exclusive with kwargs)
107
+ **kwargs: Additional connection parameters
108
+ """
109
+ super().__init__(
110
+ connection_name=connection_name,
111
+ connections_file_path=connections_file_path,
112
+ config=config,
113
+ **kwargs,
114
+ )
115
+
116
+ # Backward-compat: ``auto_cleanup`` is a Python-only flag controlling whether
117
+ # ``__del__`` / atexit should auto-close a leaked connection. The legacy
118
+ # snowflake-connector-python driver exposed it as ``conn.auto_cleanup`` and
119
+ # defaulted to ``True``; preserve both here. ``self.config.auto_cleanup``
120
+ # is ``None`` when the caller did not provide a value, which we map to
121
+ # the legacy default ``True``. The field is in ``_PYTHON_ONLY`` on
122
+ # ``ConnectionConfig`` so it is never forwarded to the Rust core.
123
+ self.auto_cleanup: bool = True if self.config.auto_cleanup is None else bool(self.config.auto_cleanup)
124
+
125
+ # Controls whether `query % params` is applied even when params is
126
+ # empty (e.g. {} or ()). When True, doubled percents (`%%`) are
127
+ self.db_handle: DatabaseHandle | None = core_driver.database_new().db_handle
128
+ core_driver.database_init(db_handle=self.db_handle)
129
+ self.conn_handle: ConnectionHandle | None = core_driver.connection_new().conn_handle
130
+
131
+ # The LogoutConfig modifier re-applies the legacy Python wrapper
132
+ # behaviour (default ``enable_server_session_keep_alive_auto_detection=True``
133
+ # with FutureWarning, ``False+True → None`` keep-alive remap, default
134
+ # ``logout_error_strategy=best_effort``) on top of the generated
135
+ # ConnectionConfig fields. See ``logout_config_options_modifier`` for
136
+ # the full contract.
137
+ options = self.config.to_proto_options(
138
+ options_modifiers=[logout_config_options_modifier],
139
+ )
140
+
141
+ if options:
142
+ response = core_driver.connection_set_options(
143
+ conn_handle=self.conn_handle,
144
+ options=options,
145
+ no_connection_details=self.config._no_connection_details,
146
+ connections_file_path=self.config.connections_file_path,
147
+ )
148
+ for warning in response.warnings:
149
+ warnings.warn(warning.message, stacklevel=2)
150
+
151
+ # Set session parameters if provided (before connection_init)
152
+ session_params = self.config.session_parameters
153
+ if session_params:
154
+ core_driver.connection_set_session_parameters(conn_handle=self.conn_handle, parameters=session_params)
155
+
156
+ # Initialise close-lifecycle state before ``_connect()`` so that the
157
+ # ``__del__`` / atexit fail-safes always observe a sane object even
158
+ # if connection_init raises. ``_connect()`` deliberately does NOT
159
+ # touch these — re-initialising them there would also reset the
160
+ # close lock if ``_connect()`` were ever called more than once.
161
+ self._closed = False
162
+ self._close_lock = threading.Lock()
163
+
164
+ self._connect()
165
+
166
+ self._session_parameters = SessionParametersProxy(self.conn_handle)
167
+ self._connection_info = ConnectionInfoProxy(self.conn_handle)
168
+
169
+ # ------------------------------------------------------------------
170
+ # Connection setup
171
+ # ------------------------------------------------------------------
172
+
173
+ def _connect(self) -> None:
174
+ """Establish the connection to Snowflake via the Rust core."""
175
+ try:
176
+ if self.config.mfa_callback is None:
177
+ self._initialize_core_connection()
178
+ else:
179
+ self._initialize_core_connection_with_mfa_callback(self.config.mfa_callback)
180
+ except ProgrammingError as e:
181
+ # The WIF cross-param guards fire in sf_core only via connection_init
182
+ # (ConnectionConfig::build -> validate_settings), surfaced as errno
183
+ # ER_INVALID_VALUE. Re-map to ER_INVALID_WIF_SETTINGS for legacy parity.
184
+ if _is_wif_conflict(e):
185
+ raise ProgrammingError(
186
+ msg=str(e),
187
+ errno=ER_INVALID_WIF_SETTINGS,
188
+ parameter=e.parameter,
189
+ validation_code=e.validation_code,
190
+ ) from e
191
+ raise
192
+ self._telemetry_client = _InternalTelemetryClient(
193
+ conn_handle=cast(ConnectionHandle, self.conn_handle),
194
+ )
195
+
196
+ if self._should_auto_cleanup():
197
+ atexit.register(self._close_at_process_exit)
198
+
199
+ def _initialize_core_connection(self) -> None:
200
+ core_driver.connection_init(
201
+ conn_handle=self.conn_handle, # type: ignore[arg-type]
202
+ db_handle=self.db_handle, # type: ignore[arg-type]
203
+ wrapper_identity=WrapperIdentity(
204
+ driver_name=APPLICATION_NAME,
205
+ driver_version=__version__,
206
+ language_runtime=platform.python_implementation(),
207
+ language_version=platform.python_version(),
208
+ language_compiler=platform.python_compiler(),
209
+ application_path=get_application_path(),
210
+ ),
211
+ )
212
+
213
+ def _initialize_core_connection_with_mfa_callback(self, mfa_callback: Callable[[], Iterator[None]]) -> None:
214
+ callback = mfa_callback()
215
+ completed = threading.Event()
216
+ errors: list[Exception] = []
217
+
218
+ def initialize() -> None:
219
+ try:
220
+ self._initialize_core_connection()
221
+ except Exception as error:
222
+ errors.append(error)
223
+ finally:
224
+ completed.set()
225
+
226
+ init_task = threading.Thread(target=initialize)
227
+ init_task.start()
228
+ try:
229
+ while not completed.is_set():
230
+ try:
231
+ next(callback)
232
+ except StopIteration:
233
+ completed.wait()
234
+ break
235
+ finally:
236
+ init_task.join()
237
+ if errors:
238
+ raise errors[0]
239
+
240
+ # ------------------------------------------------------------------
241
+ # Lifecycle
242
+ # ------------------------------------------------------------------
243
+
244
+ @pep249
245
+ @api_telemetry
246
+ def close(self, retry: bool = True) -> None:
247
+ """
248
+ Close the connection, send logout, and release handles.
249
+
250
+ Args:
251
+ retry: If False, overrides max_attempts to 1 (no retries) before closing.
252
+ If True (default), uses init-time configuration.
253
+
254
+ Thread-safety: the lock guards only the handle swap (nanoseconds, no I/O).
255
+ All FFI calls use local handle copies outside the lock, so concurrent
256
+ close() calls are safe — the second caller gets None handles and skips.
257
+ """
258
+ atexit.unregister(self._close_at_process_exit)
259
+
260
+ # Fast path — Core query, no lock. Core marks is_closed=true via AtomicBool
261
+ # at the START of connection_close (before HTTP logout), so this returns True
262
+ # even while another thread's logout is still in-flight.
263
+ if self.is_closed():
264
+ self._close_telemetry_client()
265
+ return
266
+
267
+ self._session_parameters.freeze()
268
+ self._connection_info.freeze()
269
+
270
+ # Lock guards ONLY the handle swap — prevents concurrent double-release.
271
+ with self._close_lock:
272
+ del self._messages[:]
273
+ conn_handle, self.conn_handle = self.conn_handle, None
274
+ db_handle, self.db_handle = self.db_handle, None
275
+ self._close_telemetry_client()
276
+
277
+ # All I/O outside the lock, using local handle copies.
278
+ # try/finally ensures handles are always released — on success, Strict
279
+ # failure, or set_options failure.
280
+ try:
281
+ if conn_handle:
282
+ if not retry:
283
+ core_driver.connection_set_options(
284
+ conn_handle=conn_handle,
285
+ options=create_config_settings_from_dict({LogoutOptionKeys.LOGOUT_MAX_ATTEMPTS: 1}),
286
+ )
287
+
288
+ core_driver.connection_close(conn_handle=conn_handle)
289
+ finally:
290
+ if conn_handle:
291
+ self._release_connection_handle(conn_handle)
292
+ if db_handle:
293
+ self._release_database_handle(db_handle)
294
+
295
+ def _try_close(self) -> None:
296
+ """Best-effort close for __del__ and atexit — never raises."""
297
+ try:
298
+ if not self.is_closed():
299
+ self.close(retry=False)
300
+ except Exception:
301
+ logger.safe_log(logging.DEBUG, "close() failed during cleanup", exc_info=True)
302
+
303
+ def _should_auto_cleanup(self) -> bool:
304
+ """Whether this connection should auto-close on GC/exit.
305
+
306
+ Uses getattr with False as fallback (NOT the default value of auto_cleanup,
307
+ which is True). False here is a GC fail-safe: if __del__ fires on a
308
+ half-initialized object (exception during __init__), we must NOT attempt
309
+ cleanup on an object whose Core handles were never created.
310
+ """
311
+ return getattr(self, "auto_cleanup", False)
312
+
313
+ def __del__(self) -> None:
314
+ if self._should_auto_cleanup():
315
+ self._try_close()
316
+
317
+ def _close_at_process_exit(self) -> None:
318
+ """
319
+ Cleanup handler called by atexit when process exits.
320
+
321
+ If close() was called successfully, this handler should have been unregistered
322
+ and should NOT run. If it runs for an already-closed connection, that indicates
323
+ a potential bug (unregister failed, race condition, or multiple registrations).
324
+
325
+ The entire body is wrapped in try/except because during interpreter shutdown,
326
+ any call (FFI, logging, warnings) may fail due to torn-down module state.
327
+ """
328
+ try:
329
+ if self.is_closed():
330
+ logger.debug(
331
+ "atexit handler ran for already-closed connection. "
332
+ "This may indicate atexit.unregister() failed or a race condition occurred."
333
+ )
334
+ return
335
+
336
+ # Connection is leaked (not explicitly closed) — emit FutureWarning.
337
+ # Auto-cleanup will be disabled by default in a future version (SNOW-2314152).
338
+ try:
339
+ warnings.warn(
340
+ "Connection was not explicitly closed before process exit. "
341
+ "Auto-cleanup at exit will be disabled by default in a future version. "
342
+ "Please explicitly call connection.close() or use context manager.",
343
+ FutureWarning,
344
+ stacklevel=2,
345
+ )
346
+ except Exception:
347
+ pass # Interpreter shutting down; warning emission is best-effort
348
+
349
+ self._try_close()
350
+ except Exception:
351
+ logger.safe_log(
352
+ logging.WARNING,
353
+ "_close_at_process_exit failed during interpreter shutdown",
354
+ exc_info=True,
355
+ )
356
+
357
+ # ------------------------------------------------------------------
358
+ # Transactions
359
+ # ------------------------------------------------------------------
360
+
361
+ @pep249
362
+ @api_telemetry
363
+ @requires_open
364
+ def commit(self) -> None:
365
+ """Commit any pending transaction to the database."""
366
+ cur = self.cursor()
367
+ try:
368
+ cur.execute(COMMIT_SQL)
369
+ finally:
370
+ cur.close()
371
+
372
+ @pep249
373
+ @api_telemetry
374
+ @requires_open
375
+ def rollback(self) -> None:
376
+ """Roll back to the start of any pending transaction."""
377
+ cur = self.cursor()
378
+ try:
379
+ cur.execute(ROLLBACK_SQL)
380
+ finally:
381
+ cur.close()
382
+
383
+ # ------------------------------------------------------------------
384
+ # Context manager
385
+ # ------------------------------------------------------------------
386
+
387
+ def __enter__(self) -> Connection:
388
+ """
389
+ Enter the runtime context for the connection.
390
+
391
+ Returns:
392
+ Connection: Self
393
+ """
394
+ return self
395
+
396
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
397
+ """Exit the runtime context. Commit on success / rollback on exception if autocommit is OFF."""
398
+ try:
399
+ if not self.is_closed() and not self._autocommit:
400
+ if exc_type is None:
401
+ self.commit()
402
+ else:
403
+ try:
404
+ self.rollback()
405
+ except Exception:
406
+ logger.warning("Rollback failed during exception handling", exc_info=True)
407
+ finally:
408
+ self.close()
409
+
410
+ # ------------------------------------------------------------------
411
+ # Autocommit
412
+ # ------------------------------------------------------------------
413
+
414
+ @requires_open
415
+ @api_telemetry
416
+ def set_autocommit(self, autocommit: bool) -> None:
417
+ """Set the autocommit mode. Executes ALTER SESSION SET autocommit on the server."""
418
+ # FIXME: set autocommit via core
419
+ if not isinstance(autocommit, bool):
420
+ raise ProgrammingError(msg=f"Invalid autocommit parameter: {autocommit!r}", errno=ER_INVALID_VALUE)
421
+ cur = self.cursor()
422
+ try:
423
+ cur.execute(SET_AUTOCOMMIT_SQL.format(autocommit=str(autocommit).lower()))
424
+ except Error as e:
425
+ logger.warning("Autocommit feature is not enabled for this connection. Ignored: %s", e)
426
+ finally:
427
+ cur.close()
428
+
429
+ @pep249
430
+ @api_telemetry
431
+ def autocommit(self, value: bool) -> None:
432
+ """Set autocommit mode."""
433
+ self.set_autocommit(value)
434
+
435
+ # ------------------------------------------------------------------
436
+ # Client prefetch threads
437
+ # ------------------------------------------------------------------
438
+
439
+ @requires_open
440
+ @api_telemetry
441
+ def set_client_prefetch_threads(self, value: int) -> None:
442
+ """Set the number of concurrent chunk-prefetch threads.
443
+
444
+ Executes ``ALTER SESSION SET CLIENT_PREFETCH_THREADS`` so the change
445
+ takes effect on subsequent result-set fetches — matching the legacy
446
+ connector's immediate, locally-effective setter — rather than only
447
+ updating local config, which the core's chunk downloader never reads
448
+ back from after connect.
449
+ """
450
+ value = clamp_client_prefetch_threads(value)
451
+ self.config.client_prefetch_threads = value
452
+ cur = self.cursor()
453
+ try:
454
+ cur.execute(SET_CLIENT_PREFETCH_THREADS_SQL.format(value=value))
455
+ finally:
456
+ cur.close()
457
+
458
+ @property
459
+ @api_telemetry
460
+ def client_prefetch_threads(self) -> int | None:
461
+ """The number of threads used to prefetch query result data."""
462
+ return self.config.client_prefetch_threads
463
+
464
+ @client_prefetch_threads.setter
465
+ @api_telemetry
466
+ def client_prefetch_threads(self, value: int) -> None:
467
+ """Set client_prefetch_threads; applies immediately via ``ALTER SESSION SET``."""
468
+ self.set_client_prefetch_threads(value)
469
+
470
+ # ------------------------------------------------------------------
471
+ # Connection state
472
+ # ------------------------------------------------------------------
473
+
474
+ @api_telemetry
475
+ def is_closed(self) -> bool:
476
+ """
477
+ Check if the connection is closed.
478
+
479
+ Queries Core's authoritative state. If the handle has been released
480
+ (connection_release after close), the query fails — treated as closed
481
+ since a released handle means close() already completed.
482
+ """
483
+ try:
484
+ response = core_driver.connection_is_closed(conn_handle=self.conn_handle) # type: ignore[arg-type]
485
+ return bool(response.is_closed)
486
+ except Exception:
487
+ return True
488
+
489
+ @api_telemetry
490
+ def is_valid(self) -> bool:
491
+ """Check whether the connection is still usable for sending queries.
492
+
493
+ Validates both the network transport and the Snowflake session by sending a heartbeat to the server.
494
+ """
495
+ if self.is_closed():
496
+ return False
497
+ try:
498
+ response = core_driver.connection_heartbeat(conn_handle=self.conn_handle) # type: ignore[arg-type]
499
+ return bool(response.valid)
500
+ except Exception:
501
+ return False
502
+
503
+ # ------------------------------------------------------------------
504
+ # Cursors
505
+ # ------------------------------------------------------------------
506
+
507
+ @overload
508
+ def cursor(self, cursor_class: None = None) -> SnowflakeCursor: ...
509
+
510
+ @overload
511
+ def cursor(self, cursor_class: type[_CursorClsT]) -> _CursorClsT: ...
512
+
513
+ @pep249
514
+ @api_telemetry
515
+ @requires_open
516
+ def cursor(self, cursor_class: type[SnowflakeCursorBase] | None = None) -> Any:
517
+ """Return a new Cursor object using the connection.
518
+
519
+ Args:
520
+ cursor_class: The class to instantiate. Defaults to the
521
+ connection's ``SnowflakeCursor``; pass ``DictCursor`` to get
522
+ results as dictionaries.
523
+
524
+ Returns:
525
+ A new cursor object.
526
+ """
527
+ return self._instantiate_cursor(cursor_class)
528
+
529
+ # ------------------------------------------------------------------
530
+ # Multi-statement execution
531
+ # ------------------------------------------------------------------
532
+
533
+ @api_telemetry
534
+ def execute_string(
535
+ self,
536
+ sql_text: str,
537
+ remove_comments: bool = False,
538
+ return_cursors: bool = True,
539
+ cursor_class: CursorType = SnowflakeCursor,
540
+ **kwargs: Any,
541
+ ) -> Iterable[CursorInstance]:
542
+ """Execute a SQL text including multiple statements. This is a non-standard convenience method."""
543
+ stream = StringIO(sql_text)
544
+ stream_generator = self.execute_stream(
545
+ stream,
546
+ remove_comments=remove_comments,
547
+ cursor_class=cursor_class,
548
+ **kwargs,
549
+ )
550
+ if return_cursors:
551
+ return list(stream_generator)
552
+ for _ in stream_generator:
553
+ pass
554
+ return []
555
+
556
+ @api_telemetry
557
+ def execute_stream(
558
+ self,
559
+ stream: StringIO,
560
+ remove_comments: bool = False,
561
+ cursor_class: CursorType = SnowflakeCursor,
562
+ **kwargs: Any,
563
+ ) -> Generator[CursorInstance, None, None]:
564
+ """Execute a stream of SQL statements. This is a non-standard convenient method."""
565
+ for sql, is_put_or_get in split_statements(stream, remove_comments=remove_comments):
566
+ if not sql:
567
+ continue
568
+ cur = self.cursor(cursor_class=cursor_class)
569
+ cur.execute(sql, _is_put_get=is_put_or_get, **kwargs)
570
+ yield cur
571
+
572
+ # ------------------------------------------------------------------
573
+ # Internal API
574
+ # ------------------------------------------------------------------
575
+
576
+ @property
577
+ @internal_api
578
+ @backward_compatibility
579
+ def rest(self) -> SnowflakeRestful:
580
+ """Internal :class:`SnowflakeRestful` instance exposed for backward compatibility."""
581
+ return SnowflakeRestful(connection=self)
582
+
583
+ @property
584
+ @internal_api
585
+ @backward_compatibility
586
+ def _telemetry(self) -> _InternalTelemetryClient:
587
+ return self._telemetry_client
588
+
589
+ @property
590
+ def _errorhandler_connection(self) -> Connection:
591
+ return self
592
+
593
+ # ------------------------------------------------------------------
594
+ # Server metadata
595
+ # ------------------------------------------------------------------
596
+
597
+ @cached_property
598
+ @api_telemetry
599
+ def snowflake_version(self) -> str:
600
+ """The current Snowflake server version string."""
601
+ with self.cursor(DictCursor) as cur:
602
+ cur.execute(CURRENT_VERSION_SQL)
603
+ row: dict[str, Any] = cur.fetchone() # type: ignore[assignment]
604
+ return str(row["VERSION"]).split(" ")[0]
605
+
606
+ # ------------------------------------------------------------------
607
+ # Query status
608
+ # ------------------------------------------------------------------
609
+
610
+ @api_telemetry
611
+ def get_query_status(self, sf_qid: str) -> QueryStatus:
612
+ """Retrieve the status of query with sf_qid."""
613
+ status, _ = self._get_query_status_with_response(sf_qid)
614
+ return status
615
+
616
+ @api_telemetry
617
+ def get_query_status_throw_if_error(self, sf_qid: str) -> QueryStatus:
618
+ """Retrieve the status of query with sf_qid and raises an exception if the query terminated with an error."""
619
+ status, response = self._get_query_status_with_response(sf_qid)
620
+ if self.is_an_error(status):
621
+ message = response.error_message if response.HasField("error_message") else f"Query {sf_qid} failed"
622
+ errno = response.error_code if response.HasField("error_code") else -1
623
+ raise ProgrammingError(msg=message, errno=errno, sfqid=sf_qid)
624
+ return status
625
+
626
+ def _get_query_status_with_response(self, sf_qid: str) -> tuple[QueryStatus, ConnectionGetQueryStatusResponse]:
627
+ """Fetch query status from the server and map the status name to a QueryStatus enum value."""
628
+ validate_query_id(sf_qid)
629
+ if self.is_closed():
630
+ return QueryStatus.DISCONNECTED, ConnectionGetQueryStatusResponse()
631
+ response = core_driver.connection_get_query_status(conn_handle=self.conn_handle, query_id=sf_qid) # type: ignore[arg-type]
632
+ try:
633
+ status = QueryStatus[response.status_name]
634
+ except KeyError:
635
+ logger.warning("Unknown query status %r; treating as NO_DATA", response.status_name)
636
+ status = QueryStatus.NO_DATA
637
+ return status, response
638
+
639
+
640
+ # Backward compatibility alias
641
+ SnowflakeConnection = Connection