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,218 @@
1
+ """Round-trip logging: Python -> core -> Python.
2
+
3
+ :class:`CoreLogger` is a drop-in replacement for a module ``logging.Logger``.
4
+ Wrapper logs are sent to sf_core over a direct PyO3 call so every tracing layer
5
+ (file, OTLP, Snowflake in-band telemetry) sees them, then come back through the
6
+ log callback onto the originating module logger. See
7
+ ``docs/logging/logging-architecture.md``.
8
+
9
+ This lives in its own module (rather than in :mod:`config`) so the extension
10
+ binding ``sf_core_python.log_event`` can be imported at module top level.
11
+ ``logging.config`` is imported at package load, before ``api_client`` — which
12
+ itself imports ``logging`` — is ready; keeping ``CoreLogger`` here avoids that
13
+ import cycle. :func:`logging.get_logger` imports this module lazily, once the
14
+ package is up.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import logging
20
+ import sys
21
+ import traceback
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ from snowflake.connector._core import sf_core_python
26
+
27
+ from .config import LoggingConfiguration
28
+
29
+
30
+ if TYPE_CHECKING:
31
+ from typing import Any
32
+
33
+ # sf_core_python.log_event return codes (see python_bridge ``log_event``).
34
+ _CORE_DELIVERED = 0 # event accepted by the tracing pipeline
35
+
36
+
37
+ def _py_level_to_callback(level: int) -> int:
38
+ """Map a stdlib logging level to the sf_core callback level encoding."""
39
+ if level >= logging.ERROR:
40
+ return 0
41
+ if level >= logging.WARNING:
42
+ return 1
43
+ if level >= logging.INFO:
44
+ return 2
45
+ return 3 # DEBUG - finest level supported
46
+
47
+
48
+ class CoreLogger:
49
+ """Drop-in replacement for a module ``logging.Logger`` that routes records
50
+ through sf_core.
51
+
52
+ The wrapped stdlib logger remains the single source of truth for levels:
53
+ :meth:`is_enabled_for` gates every core call, so a filtered message costs
54
+ nothing. When troubleshooting mode is active the pre-filter is bypassed
55
+ and all events reach the core pipeline regardless of the stdlib level.
56
+ """
57
+
58
+ def __init__(self, name: str) -> None:
59
+ self._name = name
60
+ self._py_logger = logging.getLogger(name)
61
+
62
+ @property
63
+ def name(self) -> str:
64
+ return self._name
65
+
66
+ def is_enabled_for(self, level: int) -> bool:
67
+ return self._is_level_enabled(level)
68
+
69
+ def _is_level_enabled(self, py_level: int) -> bool:
70
+ cfg = LoggingConfiguration._instance
71
+ return (cfg is not None and cfg.is_troubleshooting_enabled()) or self._py_logger.isEnabledFor(py_level)
72
+
73
+ def _format_message(self, msg: str, args: tuple[object, ...], exc_info: Any) -> str:
74
+ try:
75
+ formatted = msg % args if args else msg
76
+ except Exception:
77
+ # A mismatched format string / args is a caller bug; logging must
78
+ # never raise into user code (same contract as the stdlib logger we
79
+ # replace, which swallows format errors in ``record.getMessage``).
80
+ # Still emit something useful rather than dropping the record.
81
+ formatted = f"{msg} {args!r}"
82
+ if exc_info:
83
+ if exc_info is True:
84
+ exc_info = sys.exc_info()
85
+ if isinstance(exc_info, BaseException):
86
+ exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
87
+ if exc_info and exc_info[0] is not None:
88
+ formatted += "".join(traceback.format_exception(*exc_info))
89
+ return formatted
90
+
91
+ def _emit(
92
+ self,
93
+ py_level: int,
94
+ msg: str,
95
+ args: tuple[object, ...],
96
+ *,
97
+ exc_info: Any = False,
98
+ stacklevel: int = 1,
99
+ ) -> None:
100
+ """Emit a Python-originated log, resolving the caller's location.
101
+
102
+ Used by the public ``debug``/``info``/… methods, where the call site is
103
+ a Python stack frame.
104
+ """
105
+ if not self._is_level_enabled(py_level):
106
+ return
107
+ # frame 0 is _emit, frame 1 is the public CoreLogger method (info/log/...)
108
+ # stacklevel counts frames above that method
109
+ frame = sys._getframe(1 + stacklevel)
110
+ self._dispatch(
111
+ py_level,
112
+ self._format_message(msg, args, exc_info),
113
+ frame.f_code.co_filename,
114
+ frame.f_lineno,
115
+ frame.f_code.co_name,
116
+ )
117
+
118
+ def _emit_with_location(
119
+ self,
120
+ py_level: int,
121
+ msg: str,
122
+ args: tuple[object, ...],
123
+ *,
124
+ exc_info: Any = False,
125
+ file: str,
126
+ line: int,
127
+ function: str,
128
+ ) -> None:
129
+ """Emit a log with a caller-supplied source location.
130
+
131
+ Used by native extensions, which pass explicit C++ file/function/line
132
+ instead of a resolvable Python stack frame.
133
+ """
134
+ if not self._is_level_enabled(py_level):
135
+ return
136
+ self._dispatch(py_level, self._format_message(msg, args, exc_info), file, line, function)
137
+
138
+ def _dispatch(
139
+ self,
140
+ py_level: int,
141
+ message: str,
142
+ source_file: str,
143
+ source_line: int,
144
+ source_function: str,
145
+ ) -> None:
146
+ """Send a fully-resolved record to sf_core, falling back to the stdlib
147
+ logger when the pipeline is not live.
148
+ """
149
+ try:
150
+ status = sf_core_python.log_event(
151
+ level=_py_level_to_callback(py_level),
152
+ message=message,
153
+ file=source_file,
154
+ line=source_line,
155
+ function=source_function,
156
+ logger_name=self._name,
157
+ )
158
+ except Exception:
159
+ # Extension unusable (e.g. torn down during interpreter shutdown). Logging
160
+ # must never raise into user code (same contract as
161
+ # ``logging.Handler.handle`` and :func:`logging.safe_log`); treat as
162
+ # not delivered and fall back below.
163
+ status = None
164
+
165
+ if status == _CORE_DELIVERED:
166
+ return
167
+
168
+ # sf_core is not up yet (early-import events, before ``sf_core_python.init``
169
+ # marks the pipeline live) or the extension is gone: emit straight onto
170
+ # the stdlib logger so the record is not lost. The extension return
171
+ # code — not a Python-side flag — is the source of truth for whether
172
+ # it is live.
173
+ record = self._py_logger.makeRecord(
174
+ self._name,
175
+ py_level,
176
+ source_file,
177
+ source_line,
178
+ message,
179
+ (),
180
+ None,
181
+ source_function,
182
+ )
183
+ self._py_logger.handle(record)
184
+
185
+ def debug(self, msg: str, *args: object, exc_info: Any = False) -> None:
186
+ self._emit(logging.DEBUG, msg, args, exc_info=exc_info)
187
+
188
+ def info(self, msg: str, *args: object, exc_info: Any = False) -> None:
189
+ self._emit(logging.INFO, msg, args, exc_info=exc_info)
190
+
191
+ def warning(self, msg: str, *args: object, exc_info: Any = False) -> None:
192
+ self._emit(logging.WARNING, msg, args, exc_info=exc_info)
193
+
194
+ def error(self, msg: str, *args: object, exc_info: Any = False) -> None:
195
+ self._emit(logging.ERROR, msg, args, exc_info=exc_info)
196
+
197
+ def exception(self, msg: str, *args: object) -> None:
198
+ self._emit(logging.ERROR, msg, args, exc_info=True)
199
+
200
+ def log(self, level: int, msg: str, *args: object, exc_info: Any = False, stacklevel: int = 1) -> None:
201
+ self._emit(level, msg, args, exc_info=exc_info, stacklevel=stacklevel)
202
+
203
+ def safe_log(self, level: int, msg: str, *args: object, exc_info: bool = False) -> None:
204
+ """Best-effort log call — never raises.
205
+
206
+ Use on cleanup paths that run during interpreter shutdown (``atexit``,
207
+ ``__del__``) where the ``logging`` module itself may be partially torn
208
+ down and the sf_core extension may already be gone. Bypasses the round-trip
209
+ and logs straight onto the stdlib logger. ``stacklevel=2`` points the
210
+ record at the caller, not at this method.
211
+
212
+ For all other call sites prefer the standard ``logger.<level>(...)``
213
+ methods so genuine logging misconfiguration is not silently hidden.
214
+ """
215
+ try:
216
+ self._py_logger.log(level, msg, *args, exc_info=exc_info, stacklevel=2)
217
+ except Exception:
218
+ pass
@@ -0,0 +1,144 @@
1
+ """Logger wrapper used by bundled native extensions (nanoarrow C++).
2
+
3
+ The extension imports this module via pybind (see
4
+ ``_internal/nanoarrow_cpp/Logging/logging.cpp``) and calls
5
+ ``NativeExtensionLogger.log()`` so it can pass C++-side file / function / line
6
+ information through :class:`.core_logger.CoreLogger`, which routes every log
7
+ through sf_core.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ import warnings
14
+
15
+ from typing import Any
16
+
17
+ from .core_logger import CoreLogger
18
+
19
+
20
+ def get_native_extension_logger(name: str) -> NativeExtensionLogger:
21
+ return NativeExtensionLogger(CoreLogger(name))
22
+
23
+
24
+ class NativeExtensionLogger:
25
+ """Thin wrapper around :class:`.core_logger.CoreLogger` for native code.
26
+
27
+ Native extensions pass explicit file, function, and line metadata from C++
28
+ rather than relying on Python stack frames.
29
+ """
30
+
31
+ def __init__(self, core_logger: CoreLogger) -> None:
32
+ self._logger = core_logger
33
+
34
+ def debug(
35
+ self,
36
+ msg: str,
37
+ path_name: str | None = None,
38
+ func_name: str | None = None,
39
+ *args: Any,
40
+ **kwargs: Any,
41
+ ) -> None:
42
+ self.log(logging.DEBUG, msg, *args, path_name=path_name, func_name=func_name, **kwargs)
43
+
44
+ def info(
45
+ self,
46
+ msg: str,
47
+ path_name: str | None = None,
48
+ func_name: str | None = None,
49
+ *args: Any,
50
+ **kwargs: Any,
51
+ ) -> None:
52
+ self.log(logging.INFO, msg, *args, path_name=path_name, func_name=func_name, **kwargs)
53
+
54
+ def warning(
55
+ self,
56
+ msg: str,
57
+ path_name: str | None = None,
58
+ func_name: str | None = None,
59
+ *args: Any,
60
+ **kwargs: Any,
61
+ ) -> None:
62
+ self.log(logging.WARNING, msg, *args, path_name=path_name, func_name=func_name, **kwargs)
63
+
64
+ def warn(
65
+ self,
66
+ msg: str,
67
+ path_name: str | None = None,
68
+ func_name: str | None = None,
69
+ *args: Any,
70
+ **kwargs: Any,
71
+ ) -> None:
72
+ warnings.warn(
73
+ "The 'warn' method is deprecated, use 'warning' instead",
74
+ DeprecationWarning,
75
+ stacklevel=2,
76
+ )
77
+ self.warning(msg, *args, path_name=path_name, func_name=func_name, **kwargs) # type: ignore[misc]
78
+
79
+ def error(
80
+ self,
81
+ msg: str,
82
+ path_name: str | None = None,
83
+ func_name: str | None = None,
84
+ *args: Any,
85
+ **kwargs: Any,
86
+ ) -> None:
87
+ self.log(logging.ERROR, msg, *args, path_name=path_name, func_name=func_name, **kwargs)
88
+
89
+ def exception(
90
+ self,
91
+ msg: str,
92
+ path_name: str | None = None,
93
+ func_name: str | None = None,
94
+ *args: Any,
95
+ exc_info: bool = True,
96
+ **kwargs: Any,
97
+ ) -> None:
98
+ self.error(msg, *args, path_name=path_name, func_name=func_name, exc_info=exc_info, **kwargs) # type: ignore[misc]
99
+
100
+ def critical(
101
+ self,
102
+ msg: str,
103
+ path_name: str | None = None,
104
+ func_name: str | None = None,
105
+ *args: Any,
106
+ **kwargs: Any,
107
+ ) -> None:
108
+ self.log(logging.CRITICAL, msg, *args, path_name=path_name, func_name=func_name, **kwargs)
109
+
110
+ fatal = critical
111
+
112
+ def log(
113
+ self,
114
+ level: int,
115
+ msg: str,
116
+ *args: Any,
117
+ path_name: str | None = None,
118
+ func_name: str | None = None,
119
+ line_num: int = 0,
120
+ **kwargs: Any,
121
+ ) -> None:
122
+ """Generalized log method for native extension callers.
123
+
124
+ Args:
125
+ level: Logging level.
126
+ msg: Logging message.
127
+ path_name: Absolute or relative path of the file where the logger gets called.
128
+ func_name: Function inside which the logger gets called.
129
+ line_num: Line number at which the logger gets called.
130
+ """
131
+ if not isinstance(level, int):
132
+ if logging.raiseExceptions: # type: ignore[unreachable]
133
+ raise TypeError("level must be an integer")
134
+ return
135
+ exc_info = kwargs.pop("exc_info", False)
136
+ self._logger._emit_with_location(
137
+ level,
138
+ msg,
139
+ args,
140
+ exc_info=exc_info,
141
+ file=path_name or "",
142
+ line=line_num,
143
+ function=func_name or "",
144
+ )
@@ -0,0 +1,187 @@
1
+ """Logout configuration for the Python wrapper (SNOW-2314152).
2
+
3
+ LogoutConfig carries resolved logout settings with Python-specific defaults.
4
+ remap_keep_alive_for_backward_compat applies the Phase 2 (SNOW-2314152) backward-compat remap.
5
+ """
6
+
7
+ import warnings
8
+
9
+ from dataclasses import dataclass
10
+ from enum import StrEnum
11
+ from typing import Any
12
+
13
+
14
+ class LogoutOptionKeys(StrEnum):
15
+ """Core API option key strings for logout configuration.
16
+
17
+ These correspond to the option keys accepted by Core's
18
+ connection_set_option_* RPCs for logout behavior.
19
+ """
20
+
21
+ SERVER_SESSION_KEEP_ALIVE = "server_session_keep_alive"
22
+ ENABLE_SERVER_SESSION_KEEP_ALIVE_AUTO_DETECTION = "enable_server_session_keep_alive_auto_detection"
23
+ LOGOUT_ERROR_STRATEGY = "logout_error_strategy"
24
+ LOGOUT_TOTAL_TIMEOUT_SECONDS = "logout_total_timeout_seconds"
25
+ LOGOUT_MAX_ATTEMPTS = "logout_max_attempts"
26
+ LOGOUT_REQUEST_TIMEOUT_SECONDS = "logout_request_timeout_seconds"
27
+
28
+
29
+ class ErrorStrategy(StrEnum):
30
+ """Error handling strategy for logout.
31
+
32
+ These map directly to Core's ErrorStrategy enum variants.
33
+ """
34
+
35
+ BEST_EFFORT = "best_effort"
36
+ STRICT = "strict"
37
+
38
+
39
+ _UNSET = object() # Sentinel to distinguish "not provided" from explicit values
40
+
41
+
42
+ @dataclass
43
+ class LogoutConfig:
44
+ """Final logout configuration for Core API.
45
+
46
+ Attributes:
47
+ server_session_keep_alive: Final value for Core (already mapped)
48
+ enable_server_session_keep_alive_auto_detection: Final value for Core (None = treat as False in Core)
49
+ error_strategy: Error handling strategy string ("best_effort" or "strict")
50
+ logout_total_timeout_seconds: Total timeout budget for logout operation (all retries)
51
+ max_attempts: Maximum total attempts (NOT retry count: 1 = no retries, 3 = 2 retries)
52
+ logout_request_timeout_seconds: Per-request socket timeout (None = no per-request limit)
53
+ """
54
+
55
+ server_session_keep_alive: bool | None
56
+ enable_server_session_keep_alive_auto_detection: bool | None
57
+ error_strategy: ErrorStrategy = ErrorStrategy.BEST_EFFORT
58
+ logout_total_timeout_seconds: int | None = None # Core default: 15s
59
+ max_attempts: int | None = None # Core default: 3
60
+ logout_request_timeout_seconds: int | None = None # Core default: None (total budget only)
61
+
62
+ @classmethod
63
+ def from_kwargs(cls, kwargs: dict) -> "LogoutConfig":
64
+ """Pop logout params from kwargs, apply defaults and backward-compat mapping.
65
+
66
+ Mutates kwargs in-place (pops logout-specific keys).
67
+ """
68
+ from snowflake.connector.errors import ProgrammingError
69
+
70
+ keep_alive = kwargs.pop("server_session_keep_alive", None)
71
+ if keep_alive is not None and not isinstance(keep_alive, bool):
72
+ raise ProgrammingError(f"server_session_keep_alive must be bool, got {type(keep_alive).__name__}")
73
+
74
+ auto_detection = _extract_auto_detection_param(kwargs)
75
+ keep_alive = remap_keep_alive_for_backward_compat(keep_alive, auto_detection)
76
+
77
+ return cls(
78
+ server_session_keep_alive=keep_alive,
79
+ enable_server_session_keep_alive_auto_detection=auto_detection,
80
+ )
81
+
82
+ def to_option_dict(self) -> dict[str, "bool | int | str"]:
83
+ """Convert to a dict suitable for ``_build_config_settings`` + ``connection_set_options``.
84
+
85
+ ``None`` fields are omitted so Core uses its own defaults for those keys.
86
+ """
87
+ options: dict[str, bool | int | str] = {}
88
+ if self.server_session_keep_alive is not None:
89
+ options[LogoutOptionKeys.SERVER_SESSION_KEEP_ALIVE] = self.server_session_keep_alive
90
+ if self.enable_server_session_keep_alive_auto_detection is not None:
91
+ options[LogoutOptionKeys.ENABLE_SERVER_SESSION_KEEP_ALIVE_AUTO_DETECTION] = (
92
+ self.enable_server_session_keep_alive_auto_detection
93
+ )
94
+ options[LogoutOptionKeys.LOGOUT_ERROR_STRATEGY] = self.error_strategy.value
95
+ if self.logout_total_timeout_seconds is not None:
96
+ options[LogoutOptionKeys.LOGOUT_TOTAL_TIMEOUT_SECONDS] = self.logout_total_timeout_seconds
97
+ if self.max_attempts is not None:
98
+ options[LogoutOptionKeys.LOGOUT_MAX_ATTEMPTS] = self.max_attempts
99
+ if self.logout_request_timeout_seconds is not None:
100
+ options[LogoutOptionKeys.LOGOUT_REQUEST_TIMEOUT_SECONDS] = self.logout_request_timeout_seconds
101
+ return options
102
+
103
+
104
+ def _extract_auto_detection_param(kwargs: dict) -> bool | None:
105
+ """Pop and parse enable_server_session_keep_alive_auto_detection from kwargs.
106
+
107
+ If not provided, defaults to True and emits a FutureWarning:
108
+ the default will change to None in a future version (SNOW-2314152).
109
+ """
110
+ from snowflake.connector.errors import ProgrammingError
111
+
112
+ raw = kwargs.pop("enable_server_session_keep_alive_auto_detection", _UNSET)
113
+ if raw is _UNSET:
114
+ warnings.warn(
115
+ "enable_server_session_keep_alive_auto_detection was not set and defaults "
116
+ "to True. In a future version, the default will change to None. "
117
+ "Please provide an explicit value: "
118
+ "True = check for running async queries before logout (queries are preserved); "
119
+ "False/None = always send logout on close (async queries may be terminated by server). "
120
+ "Logout behavior can also be overridden with server_session_keep_alive. "
121
+ "See the connection parameter docs for more info.",
122
+ FutureWarning,
123
+ stacklevel=6,
124
+ )
125
+ return True
126
+ if raw is not None and not isinstance(raw, bool):
127
+ raise ProgrammingError(
128
+ f"enable_server_session_keep_alive_auto_detection must be bool or None, got {type(raw).__name__}"
129
+ )
130
+ return raw
131
+
132
+
133
+ def remap_keep_alive_for_backward_compat(
134
+ server_session_keep_alive: bool | None,
135
+ enable_auto_detection: bool | None,
136
+ ) -> bool | None:
137
+ """Phase 2 backward-compat remap for server_session_keep_alive (SNOW-2314152).
138
+
139
+ Old Python driver: server_session_keep_alive=False (default) always checked
140
+ _async_sfqids before logout. Phase 2 (SNOW-2314152) preserves this: False + True → None makes
141
+ Core check the registry (same behavior). Phase 3 (SNOW-2314152): False will mean "force logout".
142
+
143
+ Truth table:
144
+ - False + auto_detection=True → None (Core checks registry) + deprecation warning
145
+ - False + auto_detection=False → False (no remap, no warning — same meaning in Phase 3 (SNOW-2314152))
146
+ - True / None → pass through unchanged
147
+ """
148
+ if server_session_keep_alive is False and enable_auto_detection:
149
+ warnings.warn(
150
+ "server_session_keep_alive=False currently respects auto-detection "
151
+ "(async query registry is checked before logout). In a future version, "
152
+ "False will mean 'always logout' without registry check. "
153
+ "To keep current behavior, use server_session_keep_alive=None with "
154
+ "enable_server_session_keep_alive_auto_detection=True.",
155
+ FutureWarning,
156
+ stacklevel=5,
157
+ )
158
+ return None
159
+ return server_session_keep_alive
160
+
161
+
162
+ def logout_config_options_modifier(options: dict[str, Any]) -> dict[str, Any]:
163
+ """``ConnectionConfig.to_options`` modifier that re-applies legacy LogoutConfig logic.
164
+
165
+ The generated :class:`ConnectionConfig` exposes the logout-related fields as
166
+ plain optional values, so a user-supplied ``server_session_keep_alive=False``
167
+ would be forwarded verbatim to the Rust core and the Python-only
168
+ ``best_effort`` / auto-detection defaults would be lost.
169
+
170
+ This modifier reconstructs the previous ``Connection._parse_kwargs`` behaviour:
171
+
172
+ * Pops ``server_session_keep_alive`` and
173
+ ``enable_server_session_keep_alive_auto_detection`` from *options*.
174
+ * Builds a :class:`LogoutConfig`, which:
175
+ - Defaults ``enable_server_session_keep_alive_auto_detection`` to ``True``
176
+ (with a ``FutureWarning``) when the user did not provide a value.
177
+ - Applies the Phase 2 ``False + True → None`` remap for
178
+ ``server_session_keep_alive`` (with a ``FutureWarning``).
179
+ - Defaults ``error_strategy`` to ``ErrorStrategy.BEST_EFFORT``.
180
+ * Merges the resolved values back into *options*.
181
+
182
+ Designed to be passed as one of ``options_modifiers`` to
183
+ :meth:`ConnectionConfig.to_options` / :meth:`ConnectionConfig.to_proto_options`.
184
+ """
185
+ config = LogoutConfig.from_kwargs(options)
186
+ options.update(config.to_option_dict())
187
+ return options
@@ -0,0 +1,57 @@
1
+ #include "ArrayConverter.hpp"
2
+
3
+ #include <memory>
4
+
5
+ #include "CArrowIterator.hpp"
6
+ #include "ConverterUtil.hpp"
7
+ #include "SnowflakeType.hpp"
8
+
9
+ namespace sf {
10
+ Logger* ArrayConverter::logger = new Logger("snowflake.connector.ArrayConverter");
11
+
12
+ void ArrayConverter::generateError(const std::string& msg) const {
13
+ logger->error(__FILE__, __func__, __LINE__, msg.c_str());
14
+ PyErr_SetString(PyExc_Exception, msg.c_str());
15
+ }
16
+
17
+ ArrayConverter::ArrayConverter(ArrowSchemaView* schemaView, ArrowArrayView* array,
18
+ PyObject* context, bool useNumpy) {
19
+ m_array = array;
20
+
21
+ if (schemaView->schema->n_children != 1) {
22
+ std::string errorInfo = Logger::formatString(
23
+ "[Snowflake Exception] invalid arrow schema for array items expected 1 "
24
+ "schema child, but got %d",
25
+ schemaView->schema->n_children);
26
+ this->generateError(errorInfo);
27
+ return;
28
+ }
29
+
30
+ ArrowSchema* item_schema = schemaView->schema->children[0];
31
+ ArrowArrayView* item_array = array->children[0];
32
+ m_item_converter = getConverterFromSchema(item_schema, item_array, context, useNumpy, logger);
33
+ }
34
+
35
+ PyObject* ArrayConverter::toPyObject(int64_t rowIndex) const {
36
+ if (ArrowArrayViewIsNull(m_array, rowIndex)) {
37
+ Py_RETURN_NONE;
38
+ }
39
+
40
+ // Array item offsets are stored in the second array buffers
41
+ // Infer start an end of this rows slice by looking at the
42
+ // current and next offset. If there isn't another offset use
43
+ // the end of the array instead.
44
+ int start = m_array->buffer_views[1].data.as_int32[rowIndex];
45
+ int end = m_array->children[0]->length;
46
+ if (rowIndex + 1 < m_array->length) {
47
+ end = m_array->buffer_views[1].data.as_int32[rowIndex + 1];
48
+ }
49
+
50
+ PyObject* list = PyList_New(end - start);
51
+ for (int i = start; i < end; i++) {
52
+ PyList_SetItem(list, i - start, m_item_converter->toPyObject(i));
53
+ }
54
+ return list;
55
+ }
56
+
57
+ } // namespace sf
@@ -0,0 +1,29 @@
1
+ #ifndef PC_ARRAYCONVERTER_HPP
2
+ #define PC_ARRAYCONVERTER_HPP
3
+
4
+ #include <memory>
5
+
6
+ #include "IColumnConverter.hpp"
7
+ #include "logging.hpp"
8
+ #include "nanoarrow.h"
9
+ #include "nanoarrow.hpp"
10
+
11
+ namespace sf {
12
+
13
+ class ArrayConverter : public IColumnConverter {
14
+ public:
15
+ explicit ArrayConverter(ArrowSchemaView* schemaView, ArrowArrayView* array, PyObject* context,
16
+ bool useNumpy);
17
+
18
+ PyObject* toPyObject(int64_t rowIndex) const override;
19
+
20
+ private:
21
+ void generateError(const std::string& msg) const;
22
+
23
+ ArrowArrayView* m_array;
24
+ std::shared_ptr<sf::IColumnConverter> m_item_converter;
25
+ static Logger* logger;
26
+ };
27
+
28
+ } // namespace sf
29
+ #endif // PC_ARRAYCONVERTER_HPP