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,278 @@
|
|
|
1
|
+
"""PEP 249 error-handler routing via ``ErrorHandlerMixin``.
|
|
2
|
+
|
|
3
|
+
How to raise errors in the driver:
|
|
4
|
+
- Classes (Connection, Cursor, ResultBatch): inherit ``ErrorHandlerMixin``.
|
|
5
|
+
Public methods are wrapped automatically via ``__init_subclass__``.
|
|
6
|
+
Then use plain ``raise``.
|
|
7
|
+
- Free functions with a ``conn`` argument (e.g. ``write_pandas``): wrap the body
|
|
8
|
+
in ``try/except Error`` and call ``route_exception(conn, None, exc)``.
|
|
9
|
+
|
|
10
|
+
This wrapping is also where ``wrapper_error`` telemetry is collected (see
|
|
11
|
+
``_report_wrapper_error`` / ``_report_wrapper_error_async``): every wrapped
|
|
12
|
+
call that catches an exception reports it, tagged with its own method name,
|
|
13
|
+
but only the outermost frame in a call chain hands the error to the PEP 249
|
|
14
|
+
errorhandler, so PEP 249 routing still fires exactly once.
|
|
15
|
+
|
|
16
|
+
Hot-path methods may use ``@simplified_error_handling`` instead of the mixin wrap:
|
|
17
|
+
failures still go through ``_reraise_via_errorhandler``, but the success path
|
|
18
|
+
skips the ContextVar round-trip.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import functools
|
|
24
|
+
import inspect
|
|
25
|
+
|
|
26
|
+
from collections.abc import Callable
|
|
27
|
+
from contextvars import ContextVar
|
|
28
|
+
from typing import TYPE_CHECKING, Any, NoReturn, TypeVar, cast
|
|
29
|
+
|
|
30
|
+
from ..errors import Error, ErrorDetails
|
|
31
|
+
from .decorators import _schedule_async_telemetry, _telemetry_client_if_enabled
|
|
32
|
+
from .logging import get_logger
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from ..aio.connection import Connection as AsyncConnection
|
|
37
|
+
from ..aio.cursor import SnowflakeCursorBase as AsyncSnowflakeCursorBase
|
|
38
|
+
from ..connection import Connection
|
|
39
|
+
from ..cursor import SnowflakeCursorBase
|
|
40
|
+
|
|
41
|
+
logger = get_logger(__name__)
|
|
42
|
+
|
|
43
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
44
|
+
|
|
45
|
+
# Set on an Error that has already been through ``route_exception`` / the
|
|
46
|
+
# default handler, so a @simplified_error_handling hot path does not PEP 249-route
|
|
47
|
+
# twice when an inner wrapped method already did.
|
|
48
|
+
_ROUTED_ATTR = "_sf_errorhandler_routed"
|
|
49
|
+
_SIMPLIFIED_ERROR_HANDLING_ATTR = "_simplified_error_handling"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def simplified_error_handling(func: F) -> F:
|
|
53
|
+
"""Route failures without the mixin ContextVar round-trip on the success path.
|
|
54
|
+
|
|
55
|
+
Skips ``ErrorHandlerMixin`` auto-wrapping and installs a cheap ``try/except``
|
|
56
|
+
that calls ``_reraise_via_errorhandler`` (PEP 249 routing + ``wrapper_error`` telemetry).
|
|
57
|
+
"""
|
|
58
|
+
if inspect.iscoroutinefunction(func):
|
|
59
|
+
|
|
60
|
+
@functools.wraps(func)
|
|
61
|
+
async def async_wrapper(self: ErrorHandlerMixin, *args: Any, **kwargs: Any) -> Any:
|
|
62
|
+
try:
|
|
63
|
+
return await func(self, *args, **kwargs)
|
|
64
|
+
except Exception as exc:
|
|
65
|
+
await self._reraise_via_errorhandler_async(func, exc)
|
|
66
|
+
|
|
67
|
+
wrapper: Callable[..., Any] = async_wrapper
|
|
68
|
+
else:
|
|
69
|
+
|
|
70
|
+
@functools.wraps(func)
|
|
71
|
+
def sync_wrapper(self: ErrorHandlerMixin, *args: Any, **kwargs: Any) -> Any:
|
|
72
|
+
try:
|
|
73
|
+
return func(self, *args, **kwargs)
|
|
74
|
+
except Exception as exc:
|
|
75
|
+
self._reraise_via_errorhandler(func, exc)
|
|
76
|
+
|
|
77
|
+
wrapper = sync_wrapper
|
|
78
|
+
|
|
79
|
+
setattr(wrapper, _SIMPLIFIED_ERROR_HANDLING_ATTR, True)
|
|
80
|
+
return cast(F, wrapper)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _mark_errorhandler_routed(exc: BaseException) -> None:
|
|
84
|
+
setattr(exc, _ROUTED_ATTR, True)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def route_exception(
|
|
88
|
+
connection: Connection | AsyncConnection | None,
|
|
89
|
+
cursor: SnowflakeCursorBase | AsyncSnowflakeCursorBase | None,
|
|
90
|
+
exc: Error,
|
|
91
|
+
) -> NoReturn:
|
|
92
|
+
"""Route an ``Error`` through the PEP 249 errorhandler chain, then re-raise.
|
|
93
|
+
|
|
94
|
+
The handler may observe, log, or replace the error (by raising a different
|
|
95
|
+
exception), but it cannot suppress it — the original is always re-raised.
|
|
96
|
+
"""
|
|
97
|
+
_mark_errorhandler_routed(exc)
|
|
98
|
+
error_value = _error_to_value(exc)
|
|
99
|
+
Error.hand_to_other_handler(connection, cursor, type(exc), error_value)
|
|
100
|
+
raise exc
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ErrorHandlerMixin:
|
|
104
|
+
"""Mixin that routes ``Error`` exceptions from public methods through PEP 249 errorhandler.
|
|
105
|
+
|
|
106
|
+
Inherit this class and override ``_errorhandler_connection`` and/or
|
|
107
|
+
``_errorhandler_cursor`` to supply context. Public methods are wrapped
|
|
108
|
+
automatically at class creation time via ``__init_subclass__``.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
|
112
|
+
super().__init_subclass__(**kwargs)
|
|
113
|
+
_apply_errorhandler(cls)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def _errorhandler_connection(self) -> Connection | AsyncConnection | None:
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def _errorhandler_cursor(self) -> SnowflakeCursorBase | AsyncSnowflakeCursorBase | None:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
def _reraise_via_errorhandler(self, method: Callable[..., Any], exc: BaseException) -> NoReturn:
|
|
124
|
+
"""Report ``wrapper_error`` telemetry and PEP 249-route *exc* unless already routed.
|
|
125
|
+
|
|
126
|
+
Used by ``@simplified_error_handling`` instead of paying a ContextVar
|
|
127
|
+
round-trip on every successful call.
|
|
128
|
+
"""
|
|
129
|
+
_report_wrapper_error(self, method, exc)
|
|
130
|
+
if isinstance(exc, Error) and not _errorhandler_active.get() and not getattr(exc, _ROUTED_ATTR, False):
|
|
131
|
+
route_exception(self._errorhandler_connection, self._errorhandler_cursor, exc)
|
|
132
|
+
raise exc
|
|
133
|
+
|
|
134
|
+
async def _reraise_via_errorhandler_async(self, method: Callable[..., Any], exc: BaseException) -> NoReturn:
|
|
135
|
+
"""Async counterpart of :meth:`_reraise_via_errorhandler`."""
|
|
136
|
+
await _report_wrapper_error_async(self, method, exc)
|
|
137
|
+
if isinstance(exc, Error) and not _errorhandler_active.get() and not getattr(exc, _ROUTED_ATTR, False):
|
|
138
|
+
route_exception(self._errorhandler_connection, self._errorhandler_cursor, exc)
|
|
139
|
+
raise exc
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _apply_errorhandler(cls: type) -> None:
|
|
143
|
+
"""Wrap public methods of *cls* with error-handler routing."""
|
|
144
|
+
for name in list(vars(cls)):
|
|
145
|
+
# private/dunder — not part of the public API surface
|
|
146
|
+
if name.startswith("_"):
|
|
147
|
+
continue
|
|
148
|
+
attr = vars(cls)[name]
|
|
149
|
+
if getattr(attr, _SIMPLIFIED_ERROR_HANDLING_ATTR, False):
|
|
150
|
+
continue
|
|
151
|
+
# descriptors — not regular instance methods
|
|
152
|
+
if isinstance(attr, (property, classmethod, staticmethod)):
|
|
153
|
+
continue
|
|
154
|
+
# class-level constants or non-callable attributes
|
|
155
|
+
if not callable(attr):
|
|
156
|
+
continue
|
|
157
|
+
# generators/async generators yield lazily; errors surface at iteration
|
|
158
|
+
# time, not call time — the inner calls they drive are wrapped individually.
|
|
159
|
+
if inspect.isgeneratorfunction(attr) or inspect.isasyncgenfunction(attr):
|
|
160
|
+
continue
|
|
161
|
+
if inspect.iscoroutinefunction(attr):
|
|
162
|
+
setattr(cls, name, _wrap_async_method(attr))
|
|
163
|
+
else:
|
|
164
|
+
setattr(cls, name, _wrap_method(attr))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Prevents double-routing when a wrapped public method calls another.
|
|
168
|
+
# Global (not per-object):
|
|
169
|
+
# if conn A's method somehow triggers conn B's method in the same context, conn B's errors won't be routed.
|
|
170
|
+
# This is acceptable because a connection method should never call into another connection
|
|
171
|
+
# and per-object tracking would add overhead on every call for a scenario that should not occur.
|
|
172
|
+
_errorhandler_active: ContextVar[bool] = ContextVar("_errorhandler_active", default=False)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _report_wrapper_error(self: Any, method: Callable[..., Any], exc: BaseException) -> None:
|
|
176
|
+
"""Send ``wrapper_error`` telemetry for *exc*."""
|
|
177
|
+
try:
|
|
178
|
+
# circular-import: telemetry.py imports errorhandler helpers; defer this import
|
|
179
|
+
# to call time so the module-level import graph doesn't cycle.
|
|
180
|
+
from .._common.telemetry import AsyncTelemetryClient
|
|
181
|
+
|
|
182
|
+
error_source = f"{type(self).__name__}.{method.__name__}"
|
|
183
|
+
client = _telemetry_client_if_enabled(self)
|
|
184
|
+
if client is None:
|
|
185
|
+
return
|
|
186
|
+
if isinstance(client, AsyncTelemetryClient):
|
|
187
|
+
# A sync method on an async-flavored class (e.g. a non-coroutine method on
|
|
188
|
+
# AsyncConnection/AsyncCursorBase) still carries an AsyncTelemetryClient.
|
|
189
|
+
_schedule_async_telemetry(client.send_wrapper_error(type(exc).__name__, error_source))
|
|
190
|
+
else:
|
|
191
|
+
client.send_wrapper_error(type(exc).__name__, error_source)
|
|
192
|
+
except Exception:
|
|
193
|
+
logger.debug("Failed to send wrapper_error telemetry")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
async def _report_wrapper_error_async(self: Any, method: Callable[..., Any], exc: BaseException) -> None:
|
|
197
|
+
"""Async counterpart of :func:`_report_wrapper_error`."""
|
|
198
|
+
try:
|
|
199
|
+
# circular-import: telemetry.py imports errorhandler helpers; defer this import
|
|
200
|
+
# to call time so the module-level import graph doesn't cycle.
|
|
201
|
+
from .._common.telemetry import AsyncTelemetryClient
|
|
202
|
+
|
|
203
|
+
error_source = f"{type(self).__name__}.{method.__name__}"
|
|
204
|
+
client = _telemetry_client_if_enabled(self)
|
|
205
|
+
if client is None:
|
|
206
|
+
return
|
|
207
|
+
if isinstance(client, AsyncTelemetryClient):
|
|
208
|
+
await client.send_wrapper_error(type(exc).__name__, error_source)
|
|
209
|
+
else:
|
|
210
|
+
client.send_wrapper_error(type(exc).__name__, error_source)
|
|
211
|
+
except Exception:
|
|
212
|
+
logger.debug("Failed to send wrapper_error telemetry")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _wrap_method(method: Callable) -> Callable:
|
|
216
|
+
"""Wrap a method to report ``wrapper_error`` telemetry and route ``Error`` through the errorhandler chain."""
|
|
217
|
+
|
|
218
|
+
@functools.wraps(method)
|
|
219
|
+
def wrapper(self: ErrorHandlerMixin, *args: Any, **kwargs: Any) -> Any:
|
|
220
|
+
nested = _errorhandler_active.get()
|
|
221
|
+
if not nested:
|
|
222
|
+
token = _errorhandler_active.set(True)
|
|
223
|
+
try:
|
|
224
|
+
return method(self, *args, **kwargs)
|
|
225
|
+
except Exception as exc:
|
|
226
|
+
_report_wrapper_error(self, method, exc)
|
|
227
|
+
if not nested and isinstance(exc, Error):
|
|
228
|
+
route_exception(
|
|
229
|
+
self._errorhandler_connection,
|
|
230
|
+
self._errorhandler_cursor,
|
|
231
|
+
exc,
|
|
232
|
+
)
|
|
233
|
+
raise
|
|
234
|
+
finally:
|
|
235
|
+
if not nested:
|
|
236
|
+
_errorhandler_active.reset(token)
|
|
237
|
+
|
|
238
|
+
return wrapper
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _wrap_async_method(method: Callable) -> Callable:
|
|
242
|
+
"""Async counterpart of :func:`_wrap_method`."""
|
|
243
|
+
|
|
244
|
+
@functools.wraps(method)
|
|
245
|
+
async def wrapper(self: ErrorHandlerMixin, *args: Any, **kwargs: Any) -> Any:
|
|
246
|
+
nested = _errorhandler_active.get()
|
|
247
|
+
if not nested:
|
|
248
|
+
token = _errorhandler_active.set(True)
|
|
249
|
+
try:
|
|
250
|
+
return await method(self, *args, **kwargs)
|
|
251
|
+
except Exception as exc:
|
|
252
|
+
await _report_wrapper_error_async(self, method, exc)
|
|
253
|
+
if not nested and isinstance(exc, Error):
|
|
254
|
+
route_exception(
|
|
255
|
+
self._errorhandler_connection,
|
|
256
|
+
self._errorhandler_cursor,
|
|
257
|
+
exc,
|
|
258
|
+
)
|
|
259
|
+
raise
|
|
260
|
+
finally:
|
|
261
|
+
if not nested:
|
|
262
|
+
_errorhandler_active.reset(token)
|
|
263
|
+
|
|
264
|
+
return wrapper
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _error_to_value(exc: Error) -> ErrorDetails:
|
|
268
|
+
"""Deconstruct an ``Error`` into the dict expected by ``hand_to_other_handler``."""
|
|
269
|
+
return {
|
|
270
|
+
"msg": exc.raw_msg,
|
|
271
|
+
"errno": exc.errno,
|
|
272
|
+
"sqlstate": exc.sqlstate,
|
|
273
|
+
"sfqid": exc.sfqid,
|
|
274
|
+
"query": exc.query,
|
|
275
|
+
"request_id": exc.request_id,
|
|
276
|
+
"parameter": exc.parameter,
|
|
277
|
+
"validation_code": exc.validation_code,
|
|
278
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""FIPS status for this process.
|
|
2
|
+
|
|
3
|
+
``snowflake.connector`` re-exports :class:`FipsStatus` and :func:`get_fips_status`.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import NamedTuple
|
|
9
|
+
|
|
10
|
+
from .api_client.client_api import core_driver
|
|
11
|
+
from .decorators import pep249
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FipsStatus(NamedTuple):
|
|
15
|
+
"""Whether this process is the FIPS driver.
|
|
16
|
+
|
|
17
|
+
``is_fips`` is true when this binary was built with ``fips`` and its linked
|
|
18
|
+
TLS provider is in FIPS mode. A standard build returns false.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
is_fips: bool
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@pep249
|
|
25
|
+
def get_fips_status() -> FipsStatus:
|
|
26
|
+
"""Report whether this process is the FIPS driver without opening a connection."""
|
|
27
|
+
response = core_driver.driver_get_fips_status()
|
|
28
|
+
return FipsStatus(is_fips=response.is_fips)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Logging for the snowflake.connector module.
|
|
2
|
+
|
|
3
|
+
This package owns **configuration** of the ``snowflake.connector`` and
|
|
4
|
+
``snowflake.connector._core`` stdlib loggers (``setup_logging`` and the internal
|
|
5
|
+
``_get_*_stdlib_logger`` accessors), including the ``sf_core`` FFI callback
|
|
6
|
+
logger, plus the public :func:`get_logger` entry point that wrapper code uses.
|
|
7
|
+
|
|
8
|
+
Round-trip logging (:class:`.core_logger.CoreLogger`, which sends wrapper logs
|
|
9
|
+
to sf_core over a direct FFI call and receives them back through the FFI
|
|
10
|
+
callback) lives in :mod:`.core_logger` so its FFI import stays off this
|
|
11
|
+
module's load path. See ``docs/logging/logging-architecture.md``.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import functools
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from .config import (
|
|
21
|
+
CONNECTOR_LOGGER_NAME,
|
|
22
|
+
SF_CORE_LOGGER_NAME,
|
|
23
|
+
_get_connector_stdlib_logger,
|
|
24
|
+
_get_sf_core_stdlib_logger,
|
|
25
|
+
_needs_handler,
|
|
26
|
+
setup_logging,
|
|
27
|
+
)
|
|
28
|
+
from .native_extension_logger import NativeExtensionLogger, get_native_extension_logger
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from .core_logger import CoreLogger
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@functools.cache
|
|
36
|
+
def get_logger(name: str) -> CoreLogger:
|
|
37
|
+
from .core_logger import CoreLogger
|
|
38
|
+
|
|
39
|
+
return CoreLogger(name)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"CONNECTOR_LOGGER_NAME",
|
|
44
|
+
"SF_CORE_LOGGER_NAME",
|
|
45
|
+
"NativeExtensionLogger",
|
|
46
|
+
"_get_connector_stdlib_logger",
|
|
47
|
+
"_get_sf_core_stdlib_logger",
|
|
48
|
+
"_needs_handler",
|
|
49
|
+
"get_logger",
|
|
50
|
+
"get_native_extension_logger",
|
|
51
|
+
"setup_logging",
|
|
52
|
+
]
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Logging configuration for snowflake.connector."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Logger names
|
|
9
|
+
CONNECTOR_LOGGER_NAME = "snowflake.connector"
|
|
10
|
+
SF_CORE_LOGGER_NAME = "snowflake.connector._core"
|
|
11
|
+
|
|
12
|
+
# Set up loggers once at module load with NullHandler (standard library practice
|
|
13
|
+
# per https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library).
|
|
14
|
+
# Propagation is left ON so that external log capture (e.g. pytest caplog, root-level
|
|
15
|
+
# handlers configured by the application) works out of the box -- matching
|
|
16
|
+
# the behavior of snowflake-connector-python.
|
|
17
|
+
# When setup_logging() is called explicitly, propagation is turned OFF on the
|
|
18
|
+
# loggers that receive a dedicated handler to prevent duplicate output.
|
|
19
|
+
_sf_core_logger = logging.getLogger(SF_CORE_LOGGER_NAME)
|
|
20
|
+
_sf_core_logger.addHandler(logging.NullHandler())
|
|
21
|
+
|
|
22
|
+
_connector_logger = logging.getLogger(CONNECTOR_LOGGER_NAME)
|
|
23
|
+
_connector_logger.addHandler(logging.NullHandler())
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _needs_handler(logger: logging.Logger) -> bool:
|
|
27
|
+
"""Return True if the logger has no handlers or only NullHandler(s)."""
|
|
28
|
+
if not logger.handlers:
|
|
29
|
+
return True
|
|
30
|
+
return all(isinstance(h, logging.NullHandler) for h in logger.handlers)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def setup_logging(
|
|
34
|
+
level: int = logging.INFO,
|
|
35
|
+
sf_core_level: int = logging.INFO,
|
|
36
|
+
format_string: str | None = None,
|
|
37
|
+
stream: object | None = None,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Configure basic logging for the snowflake.connector module.
|
|
40
|
+
|
|
41
|
+
Propagation behaviour
|
|
42
|
+
---------------------
|
|
43
|
+
By default (before this function is called) both loggers have
|
|
44
|
+
``propagate=True``. This means log records bubble up to the root
|
|
45
|
+
logger so that application-level handlers and test frameworks such as
|
|
46
|
+
``pytest caplog`` capture connector output without any extra
|
|
47
|
+
configuration.
|
|
48
|
+
|
|
49
|
+
When this function adds a dedicated StreamHandler to a logger it also
|
|
50
|
+
sets ``propagate=False`` on that logger to prevent every message from
|
|
51
|
+
appearing twice — once via the dedicated handler and once via the root
|
|
52
|
+
handler chain.
|
|
53
|
+
|
|
54
|
+
**The propagate flag is only changed when a handler is actually added.**
|
|
55
|
+
If the logger already has a non-NullHandler (meaning the caller has
|
|
56
|
+
configured it themselves), this function leaves ``propagate`` and the
|
|
57
|
+
existing handler untouched and only updates the logger's *level*.
|
|
58
|
+
This respects application-level logging configuration while still
|
|
59
|
+
honouring the requested verbosity.
|
|
60
|
+
|
|
61
|
+
Summary:
|
|
62
|
+
* No prior handler → adds StreamHandler, sets propagate=False.
|
|
63
|
+
* Prior non-Null handler exists → updates level only, propagate unchanged.
|
|
64
|
+
* Called multiple times with no prior handler → second call is a no-op
|
|
65
|
+
for handler/propagation (handler already present from the first call).
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
level: Logging level for the snowflake.connector logger.
|
|
69
|
+
Defaults to logging.INFO.
|
|
70
|
+
sf_core_level: Logging level for the sf_core logger.
|
|
71
|
+
Defaults to logging.INFO.
|
|
72
|
+
format_string: Custom format string for log messages.
|
|
73
|
+
If None, uses a default format.
|
|
74
|
+
stream: Stream to write logs to. If None, uses sys.stderr.
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
>>> from snowflake.connector._internal.logging import setup_logging
|
|
78
|
+
>>> import logging
|
|
79
|
+
>>> setup_logging(level=logging.DEBUG, sf_core_level=logging.DEBUG)
|
|
80
|
+
"""
|
|
81
|
+
if format_string is None:
|
|
82
|
+
format_string = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
83
|
+
|
|
84
|
+
formatter = logging.Formatter(format_string)
|
|
85
|
+
handler = logging.StreamHandler(stream) # type: ignore [arg-type]
|
|
86
|
+
handler.setFormatter(formatter)
|
|
87
|
+
|
|
88
|
+
_connector_logger.setLevel(level)
|
|
89
|
+
if _needs_handler(_connector_logger):
|
|
90
|
+
_connector_logger.addHandler(handler)
|
|
91
|
+
_connector_logger.propagate = False
|
|
92
|
+
|
|
93
|
+
_sf_core_logger.setLevel(sf_core_level)
|
|
94
|
+
if _needs_handler(_sf_core_logger):
|
|
95
|
+
_sf_core_logger.addHandler(handler)
|
|
96
|
+
_sf_core_logger.propagate = False
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _get_connector_stdlib_logger() -> logging.Logger:
|
|
100
|
+
"""Return the package stdlib logger used by logging infrastructure.
|
|
101
|
+
|
|
102
|
+
Internal — not for wrapper contributor use. Call :func:`logging.get_logger`
|
|
103
|
+
to obtain a :class:`~.core_logger.CoreLogger` for module logging.
|
|
104
|
+
"""
|
|
105
|
+
return _connector_logger
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _get_sf_core_stdlib_logger() -> logging.Logger:
|
|
109
|
+
"""Return the stdlib logger that receives core-originated FFI callback events.
|
|
110
|
+
|
|
111
|
+
Internal — used by :mod:`~.api_client` callback dispatch only.
|
|
112
|
+
Wrapper code should use :func:`logging.get_logger` instead.
|
|
113
|
+
"""
|
|
114
|
+
return _sf_core_logger
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class LoggingConfiguration:
|
|
118
|
+
"""Process-wide logging knobs — currently just troubleshooting mode."""
|
|
119
|
+
|
|
120
|
+
_instance: LoggingConfiguration | None = None
|
|
121
|
+
|
|
122
|
+
def __init__(self, *, troubleshooting_enabled: bool) -> None:
|
|
123
|
+
self._troubleshooting_enabled = troubleshooting_enabled
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def initialize(cls, *, troubleshooting_enabled: bool) -> LoggingConfiguration:
|
|
127
|
+
"""Create the process-wide instance. Call once after ``sf_core_python.init``."""
|
|
128
|
+
if cls._instance is None:
|
|
129
|
+
cls._instance = cls(troubleshooting_enabled=troubleshooting_enabled)
|
|
130
|
+
return cls._instance
|
|
131
|
+
|
|
132
|
+
def is_troubleshooting_enabled(self) -> bool:
|
|
133
|
+
"""Return whether wrapper logs should bypass the ``CoreLogger`` pre-filter."""
|
|
134
|
+
return self._troubleshooting_enabled
|