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.
- snowflake/connector/__init__.py +148 -0
- snowflake/connector/_common/__init__.py +0 -0
- snowflake/connector/_common/extras.py +134 -0
- snowflake/connector/_common/telemetry.py +221 -0
- snowflake/connector/_common/wif_util.py +92 -0
- snowflake/connector/_core/sf_core_python.cp315-win_amd64.pyd +0 -0
- snowflake/connector/_core/sf_core_python.pyi +79 -0
- snowflake/connector/_internal/__init__.py +6 -0
- snowflake/connector/_internal/_private_key_helper.py +31 -0
- snowflake/connector/_internal/api_client/__init__.py +93 -0
- snowflake/connector/_internal/api_client/bridge.py +41 -0
- snowflake/connector/_internal/api_client/client_api.py +976 -0
- snowflake/connector/_internal/arrow.py +47 -0
- snowflake/connector/_internal/arrow_context.py +240 -0
- snowflake/connector/_internal/arrow_stream_async.py +266 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp311-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp312-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp313-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp314-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp314t-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.cp315-win_amd64.pyd +0 -0
- snowflake/connector/_internal/arrow_stream_iterator.pyi +42 -0
- snowflake/connector/_internal/arrow_stream_utils.py +171 -0
- snowflake/connector/_internal/authenticator_type.py +53 -0
- snowflake/connector/_internal/backward_compatibility.py +245 -0
- snowflake/connector/_internal/binding_converters.py +741 -0
- snowflake/connector/_internal/config_utils.py +71 -0
- snowflake/connector/_internal/connection/__init__.py +39 -0
- snowflake/connector/_internal/connection/connection.py +616 -0
- snowflake/connector/_internal/connection/connection_types.py +13 -0
- snowflake/connector/_internal/connection/constants.py +25 -0
- snowflake/connector/_internal/connection/decorators.py +31 -0
- snowflake/connector/_internal/connection/freezable_proxy.py +104 -0
- snowflake/connector/_internal/connection/queries.py +10 -0
- snowflake/connector/_internal/connection_config_mixin.py +755 -0
- snowflake/connector/_internal/cursor/__init__.py +25 -0
- snowflake/connector/_internal/cursor/base.py +732 -0
- snowflake/connector/_internal/cursor/cursor_types.py +13 -0
- snowflake/connector/_internal/cursor/decorators.py +56 -0
- snowflake/connector/_internal/cursor/query_result.py +202 -0
- snowflake/connector/_internal/cursor/query_result_waiter.py +98 -0
- snowflake/connector/_internal/cursor/result_metadata.py +255 -0
- snowflake/connector/_internal/cursor/result_set_wrapper.py +66 -0
- snowflake/connector/_internal/decorators.py +539 -0
- snowflake/connector/_internal/error_kinds.py +111 -0
- snowflake/connector/_internal/errorcode.py +35 -0
- snowflake/connector/_internal/errorhandler.py +278 -0
- snowflake/connector/_internal/fips.py +28 -0
- snowflake/connector/_internal/logging/__init__.py +52 -0
- snowflake/connector/_internal/logging/config.py +134 -0
- snowflake/connector/_internal/logging/core_logger.py +218 -0
- snowflake/connector/_internal/logging/native_extension_logger.py +144 -0
- snowflake/connector/_internal/logout_config_mapping.py +187 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +57 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.cpp +943 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ArrowTableConverter.hpp +63 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +18 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +118 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +116 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.cpp +323 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamIterator.hpp +133 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.cpp +275 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/CArrowStreamTableIterator.hpp +168 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.cpp +439 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ConverterUtil.hpp +30 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +48 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +76 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +90 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +63 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +62 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +41 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +65 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +54 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +79 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +117 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +54 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +34 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +33 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +18 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +39 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +326 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +138 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.cpp +13278 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/arrow_stream_iterator.pyx +204 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +109 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +125 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1914 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +208 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +128 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +58 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +144 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +160 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +98 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +243 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +207 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +80 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +83 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +201 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +108 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +164 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +926 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +182 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/flatcc.c +3052 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3019 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3354 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +344 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +29305 -0
- snowflake/connector/_internal/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +381 -0
- snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.cpp +108 -0
- snowflake/connector/_internal/nanoarrow_cpp/Logging/logging.hpp +47 -0
- snowflake/connector/_internal/nanoarrow_cpp/scripts/.clang-format +8 -0
- snowflake/connector/_internal/nanoarrow_cpp/scripts/format.sh +8 -0
- snowflake/connector/_internal/protobuf_gen/__init__.py +0 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.py +408 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_pb2.pyi +4487 -0
- snowflake/connector/_internal/protobuf_gen/database_driver_v1_services.py +2088 -0
- snowflake/connector/_internal/protobuf_gen/proto_exception.py +17 -0
- snowflake/connector/_internal/result_batch.py +150 -0
- snowflake/connector/_internal/snowflake_restful.py +222 -0
- snowflake/connector/_internal/snowpark_backcompat_helpers.py +31 -0
- snowflake/connector/_internal/sqlstate.py +11 -0
- snowflake/connector/_internal/statement_utils.py +207 -0
- snowflake/connector/_internal/text_utils.py +112 -0
- snowflake/connector/_internal/type_codes.py +139 -0
- snowflake/connector/_internal/utils.py +65 -0
- snowflake/connector/_internal/write_pandas_operation.py +657 -0
- snowflake/connector/aio/README.md +168 -0
- snowflake/connector/aio/__init__.py +37 -0
- snowflake/connector/aio/connection/__init__.py +17 -0
- snowflake/connector/aio/connection/_connection.py +506 -0
- snowflake/connector/aio/cursor/__init__.py +35 -0
- snowflake/connector/aio/cursor/_base.py +1034 -0
- snowflake/connector/aio/cursor/_dict_cursor.py +78 -0
- snowflake/connector/aio/cursor/_result_set_wrapper.py +35 -0
- snowflake/connector/aio/cursor/_snowflake_cursor.py +72 -0
- snowflake/connector/aio/pandas_tools.py +279 -0
- snowflake/connector/aio/result_batch.py +165 -0
- snowflake/connector/auth/__init__.py +0 -0
- snowflake/connector/auth/workload_identity.py +5 -0
- snowflake/connector/compat.py +22 -0
- snowflake/connector/config_manager.py +392 -0
- snowflake/connector/connection/__init__.py +30 -0
- snowflake/connector/connection/_connection.py +641 -0
- snowflake/connector/connection_config.py +517 -0
- snowflake/connector/constants.py +52 -0
- snowflake/connector/cursor/__init__.py +37 -0
- snowflake/connector/cursor/_base.py +1169 -0
- snowflake/connector/cursor/_chunked_download_reader.py +75 -0
- snowflake/connector/cursor/_dict_cursor.py +78 -0
- snowflake/connector/cursor/_result_set_wrapper.py +35 -0
- snowflake/connector/cursor/_snowflake_cursor.py +72 -0
- snowflake/connector/description.py +7 -0
- snowflake/connector/errors.py +492 -0
- snowflake/connector/network.py +71 -0
- snowflake/connector/pandas_tools.py +191 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +216 -0
- snowflake/connector/telemetry.py +40 -0
- snowflake/connector/time_util.py +11 -0
- snowflake/connector/types.py +134 -0
- snowflake/connector/util_text.py +3 -0
- snowflake/connector/version.py +23 -0
- snowflake_connector_python-5.2.0.dist-info/DELVEWHEEL +2 -0
- snowflake_connector_python-5.2.0.dist-info/METADATA +190 -0
- snowflake_connector_python-5.2.0.dist-info/RECORD +204 -0
- snowflake_connector_python-5.2.0.dist-info/WHEEL +4 -0
- 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
|