snowflake-connector-python 4.4.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/connector/__init__.py +118 -0
- snowflake/connector/_query_context_cache.py +276 -0
- snowflake/connector/_sql_util.py +48 -0
- snowflake/connector/_utils.py +353 -0
- snowflake/connector/aio/README.md +88 -0
- snowflake/connector/aio/__init__.py +163 -0
- snowflake/connector/aio/_azure_storage_client.py +227 -0
- snowflake/connector/aio/_bind_upload_agent.py +69 -0
- snowflake/connector/aio/_connection.py +1216 -0
- snowflake/connector/aio/_cursor.py +1402 -0
- snowflake/connector/aio/_description.py +5 -0
- snowflake/connector/aio/_direct_file_operation_utils.py +88 -0
- snowflake/connector/aio/_file_transfer_agent.py +316 -0
- snowflake/connector/aio/_gcs_storage_client.py +360 -0
- snowflake/connector/aio/_network.py +860 -0
- snowflake/connector/aio/_ocsp_asn1crypto.py +51 -0
- snowflake/connector/aio/_ocsp_snowflake.py +608 -0
- snowflake/connector/aio/_pandas_tools.py +561 -0
- snowflake/connector/aio/_result_batch.py +442 -0
- snowflake/connector/aio/_result_set.py +309 -0
- snowflake/connector/aio/_s3_storage_client.py +460 -0
- snowflake/connector/aio/_session_manager.py +588 -0
- snowflake/connector/aio/_storage_client.py +331 -0
- snowflake/connector/aio/_telemetry.py +97 -0
- snowflake/connector/aio/_time_util.py +57 -0
- snowflake/connector/aio/_wif_util.py +324 -0
- snowflake/connector/aio/auth/__init__.py +52 -0
- snowflake/connector/aio/auth/_auth.py +406 -0
- snowflake/connector/aio/auth/_by_plugin.py +131 -0
- snowflake/connector/aio/auth/_default.py +28 -0
- snowflake/connector/aio/auth/_idtoken.py +54 -0
- snowflake/connector/aio/auth/_keypair.py +60 -0
- snowflake/connector/aio/auth/_no_auth.py +31 -0
- snowflake/connector/aio/auth/_oauth.py +27 -0
- snowflake/connector/aio/auth/_oauth_code.py +117 -0
- snowflake/connector/aio/auth/_oauth_credentials.py +100 -0
- snowflake/connector/aio/auth/_okta.py +247 -0
- snowflake/connector/aio/auth/_pat.py +27 -0
- snowflake/connector/aio/auth/_usrpwdmfa.py +30 -0
- snowflake/connector/aio/auth/_webbrowser.py +405 -0
- snowflake/connector/aio/auth/_workload_identity.py +60 -0
- snowflake/connector/arrow_context.py +211 -0
- snowflake/connector/auth/__init__.py +53 -0
- snowflake/connector/auth/_auth.py +669 -0
- snowflake/connector/auth/_http_server.py +257 -0
- snowflake/connector/auth/_oauth_base.py +472 -0
- snowflake/connector/auth/by_plugin.py +219 -0
- snowflake/connector/auth/default.py +36 -0
- snowflake/connector/auth/idtoken.py +72 -0
- snowflake/connector/auth/keypair.py +225 -0
- snowflake/connector/auth/no_auth.py +39 -0
- snowflake/connector/auth/oauth.py +49 -0
- snowflake/connector/auth/oauth_code.py +490 -0
- snowflake/connector/auth/oauth_credentials.py +71 -0
- snowflake/connector/auth/okta.py +339 -0
- snowflake/connector/auth/pat.py +40 -0
- snowflake/connector/auth/usrpwdmfa.py +69 -0
- snowflake/connector/auth/webbrowser.py +514 -0
- snowflake/connector/auth/workload_identity.py +110 -0
- snowflake/connector/azure_storage_client.py +278 -0
- snowflake/connector/backoff_policies.py +141 -0
- snowflake/connector/bind_upload_agent.py +89 -0
- snowflake/connector/cache.py +696 -0
- snowflake/connector/compat.py +127 -0
- snowflake/connector/config_manager.py +553 -0
- snowflake/connector/connection.py +2671 -0
- snowflake/connector/connection_diagnostic.py +793 -0
- snowflake/connector/constants.py +460 -0
- snowflake/connector/converter.py +809 -0
- snowflake/connector/converter_issue23517.py +87 -0
- snowflake/connector/converter_null.py +14 -0
- snowflake/connector/converter_snowsql.py +205 -0
- snowflake/connector/crl.py +919 -0
- snowflake/connector/crl_cache.py +734 -0
- snowflake/connector/cursor.py +2099 -0
- snowflake/connector/dbapi.py +53 -0
- snowflake/connector/description.py +21 -0
- snowflake/connector/direct_file_operation_utils.py +88 -0
- snowflake/connector/encryption_util.py +220 -0
- snowflake/connector/errorcode.py +94 -0
- snowflake/connector/errors.py +666 -0
- snowflake/connector/externals_utils/__init__.py +0 -0
- snowflake/connector/externals_utils/externals_setup.py +30 -0
- snowflake/connector/feature.py +4 -0
- snowflake/connector/file_compression_type.py +118 -0
- snowflake/connector/file_lock.py +72 -0
- snowflake/connector/file_transfer_agent.py +1244 -0
- snowflake/connector/file_util.py +153 -0
- snowflake/connector/gcs_storage_client.py +476 -0
- snowflake/connector/gzip_decoder.py +85 -0
- snowflake/connector/interval_util.py +26 -0
- snowflake/connector/local_storage_client.py +90 -0
- snowflake/connector/log_configuration.py +62 -0
- snowflake/connector/logging_utils/__init__.py +0 -0
- snowflake/connector/logging_utils/filters.py +72 -0
- snowflake/connector/minicore/__init__.py +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core.a +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core_static.a +0 -0
- snowflake/connector/minicore/linux_aarch64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_aarch64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/macos_aarch64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/macos_x86_64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core.dll +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core_static.lib +0 -0
- snowflake/connector/nanoarrow_arrow_iterator.cp314-win_amd64.pyd +0 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +570 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1140 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +138 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +262 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
- snowflake/connector/network.py +1227 -0
- snowflake/connector/ocsp_asn1crypto.py +447 -0
- snowflake/connector/ocsp_snowflake.py +1939 -0
- snowflake/connector/options.py +179 -0
- snowflake/connector/os_details.py +88 -0
- snowflake/connector/pandas_tools.py +734 -0
- snowflake/connector/platform_detection.py +555 -0
- snowflake/connector/proxy.py +28 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +917 -0
- snowflake/connector/result_set.py +340 -0
- snowflake/connector/s3_storage_client.py +614 -0
- snowflake/connector/secret_detector.py +181 -0
- snowflake/connector/session_manager.py +650 -0
- snowflake/connector/sf_dirs.py +64 -0
- snowflake/connector/sfbinaryformat.py +35 -0
- snowflake/connector/sfdatetime.py +345 -0
- snowflake/connector/snow_logging.py +144 -0
- snowflake/connector/sqlstate.py +9 -0
- snowflake/connector/ssd_internal_keys.py +30 -0
- snowflake/connector/ssl_wrap_socket.py +281 -0
- snowflake/connector/storage_client.py +486 -0
- snowflake/connector/telemetry.py +254 -0
- snowflake/connector/telemetry_oob.py +544 -0
- snowflake/connector/test_util.py +30 -0
- snowflake/connector/time_util.py +159 -0
- snowflake/connector/token_cache.py +457 -0
- snowflake/connector/tool/__init__.py +0 -0
- snowflake/connector/tool/dump_certs.py +57 -0
- snowflake/connector/tool/dump_ocsp_response.py +139 -0
- snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
- snowflake/connector/tool/probe_connection.py +69 -0
- snowflake/connector/url_util.py +55 -0
- snowflake/connector/util_text.py +320 -0
- snowflake/connector/vendored/__init__.py +3 -0
- snowflake/connector/vendored/requests/LICENSE +175 -0
- snowflake/connector/vendored/requests/__init__.py +184 -0
- snowflake/connector/vendored/requests/__version__.py +14 -0
- snowflake/connector/vendored/requests/_internal_utils.py +50 -0
- snowflake/connector/vendored/requests/adapters.py +696 -0
- snowflake/connector/vendored/requests/api.py +157 -0
- snowflake/connector/vendored/requests/auth.py +314 -0
- snowflake/connector/vendored/requests/certs.py +17 -0
- snowflake/connector/vendored/requests/compat.py +106 -0
- snowflake/connector/vendored/requests/cookies.py +561 -0
- snowflake/connector/vendored/requests/exceptions.py +151 -0
- snowflake/connector/vendored/requests/help.py +134 -0
- snowflake/connector/vendored/requests/hooks.py +33 -0
- snowflake/connector/vendored/requests/models.py +1039 -0
- snowflake/connector/vendored/requests/packages.py +23 -0
- snowflake/connector/vendored/requests/sessions.py +831 -0
- snowflake/connector/vendored/requests/status_codes.py +128 -0
- snowflake/connector/vendored/requests/structures.py +99 -0
- snowflake/connector/vendored/requests/utils.py +1086 -0
- snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
- snowflake/connector/vendored/urllib3/__init__.py +211 -0
- snowflake/connector/vendored/urllib3/_base_connection.py +165 -0
- snowflake/connector/vendored/urllib3/_collections.py +487 -0
- snowflake/connector/vendored/urllib3/_request_methods.py +278 -0
- snowflake/connector/vendored/urllib3/_version.py +34 -0
- snowflake/connector/vendored/urllib3/connection.py +1108 -0
- snowflake/connector/vendored/urllib3/connectionpool.py +1178 -0
- snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/__init__.py +17 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/connection.py +260 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/emscripten_fetch_worker.js +110 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/fetch.py +726 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/request.py +22 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/response.py +277 -0
- snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +564 -0
- snowflake/connector/vendored/urllib3/contrib/socks.py +228 -0
- snowflake/connector/vendored/urllib3/exceptions.py +335 -0
- snowflake/connector/vendored/urllib3/fields.py +341 -0
- snowflake/connector/vendored/urllib3/filepost.py +89 -0
- snowflake/connector/vendored/urllib3/http2/__init__.py +53 -0
- snowflake/connector/vendored/urllib3/http2/connection.py +356 -0
- snowflake/connector/vendored/urllib3/http2/probe.py +87 -0
- snowflake/connector/vendored/urllib3/poolmanager.py +651 -0
- snowflake/connector/vendored/urllib3/py.typed +2 -0
- snowflake/connector/vendored/urllib3/response.py +1480 -0
- snowflake/connector/vendored/urllib3/util/__init__.py +42 -0
- snowflake/connector/vendored/urllib3/util/connection.py +137 -0
- snowflake/connector/vendored/urllib3/util/proxy.py +43 -0
- snowflake/connector/vendored/urllib3/util/request.py +263 -0
- snowflake/connector/vendored/urllib3/util/response.py +101 -0
- snowflake/connector/vendored/urllib3/util/retry.py +549 -0
- snowflake/connector/vendored/urllib3/util/ssl_.py +527 -0
- snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
- snowflake/connector/vendored/urllib3/util/ssltransport.py +271 -0
- snowflake/connector/vendored/urllib3/util/timeout.py +275 -0
- snowflake/connector/vendored/urllib3/util/url.py +469 -0
- snowflake/connector/vendored/urllib3/util/util.py +42 -0
- snowflake/connector/vendored/urllib3/util/wait.py +124 -0
- snowflake/connector/version.py +3 -0
- snowflake/connector/wif_util.py +434 -0
- snowflake_connector_python-4.4.0.dist-info/DELVEWHEEL +2 -0
- snowflake_connector_python-4.4.0.dist-info/METADATA +1591 -0
- snowflake_connector_python-4.4.0.dist-info/RECORD +302 -0
- snowflake_connector_python-4.4.0.dist-info/WHEEL +5 -0
- snowflake_connector_python-4.4.0.dist-info/entry_points.txt +4 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/LICENSE.txt +202 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/NOTICE +8 -0
- snowflake_connector_python-4.4.0.dist-info/top_level.txt +1 -0
- snowflake_connector_python.libs/msvcp140-0f885b509a685d2bbfa652fed26b5fb3.dll +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import importlib
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import platform
|
|
8
|
+
import string
|
|
9
|
+
import threading
|
|
10
|
+
import time
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from inspect import stack
|
|
13
|
+
from random import choice
|
|
14
|
+
from threading import Timer
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
from snowflake.connector.description import ISA, OPERATING_SYSTEM, OS_VERSION
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TempObjectType(Enum):
|
|
23
|
+
TABLE = "TABLE"
|
|
24
|
+
VIEW = "VIEW"
|
|
25
|
+
STAGE = "STAGE"
|
|
26
|
+
FUNCTION = "FUNCTION"
|
|
27
|
+
FILE_FORMAT = "FILE_FORMAT"
|
|
28
|
+
QUERY_TAG = "QUERY_TAG"
|
|
29
|
+
COLUMN = "COLUMN"
|
|
30
|
+
PROCEDURE = "PROCEDURE"
|
|
31
|
+
TABLE_FUNCTION = "TABLE_FUNCTION"
|
|
32
|
+
DYNAMIC_TABLE = "DYNAMIC_TABLE"
|
|
33
|
+
AGGREGATE_FUNCTION = "AGGREGATE_FUNCTION"
|
|
34
|
+
CTE = "CTE"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
TEMP_OBJECT_NAME_PREFIX = "SNOWPARK_TEMP_"
|
|
38
|
+
ALPHANUMERIC = string.digits + string.ascii_lowercase
|
|
39
|
+
TEMPORARY_STRING = "TEMP"
|
|
40
|
+
SCOPED_TEMPORARY_STRING = "SCOPED TEMPORARY"
|
|
41
|
+
_PYTHON_SNOWPARK_USE_SCOPED_TEMP_OBJECTS_STRING = (
|
|
42
|
+
"PYTHON_SNOWPARK_USE_SCOPED_TEMP_OBJECTS"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
REQUEST_ID_STATEMENT_PARAM_NAME = "requestId"
|
|
46
|
+
|
|
47
|
+
# Default server side cap on Degree of Parallelism for file transfer
|
|
48
|
+
# This default value is set to 2^30 (~ 10^9), such that it will not
|
|
49
|
+
# throttle regular sessions.
|
|
50
|
+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER = 1 << 30
|
|
51
|
+
# Variable name of server DoP cap for file transfer
|
|
52
|
+
_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER = (
|
|
53
|
+
"snowflake_server_dop_cap_for_file_transfer"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def generate_random_alphanumeric(length: int = 10) -> str:
|
|
58
|
+
return "".join(choice(ALPHANUMERIC) for _ in range(length))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def random_name_for_temp_object(object_type: TempObjectType) -> str:
|
|
62
|
+
return f"{TEMP_OBJECT_NAME_PREFIX}{object_type.value}_{generate_random_alphanumeric().upper()}"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_temp_type_for_object(use_scoped_temp_objects: bool) -> str:
|
|
66
|
+
return SCOPED_TEMPORARY_STRING if use_scoped_temp_objects else TEMPORARY_STRING
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def is_uuid4(str_or_uuid: str | UUID) -> bool:
|
|
70
|
+
"""Check whether provided string str is a valid UUID version4."""
|
|
71
|
+
if isinstance(str_or_uuid, UUID):
|
|
72
|
+
return str_or_uuid.version == 4
|
|
73
|
+
|
|
74
|
+
if not isinstance(str_or_uuid, str):
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
uuid_str = str(UUID(str_or_uuid, version=4))
|
|
79
|
+
except ValueError:
|
|
80
|
+
return False
|
|
81
|
+
return uuid_str == str_or_uuid
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _snowflake_max_parallelism_for_file_transfer(connection):
|
|
85
|
+
"""Returns the server side cap on max parallelism for file transfer for the given connection."""
|
|
86
|
+
return getattr(
|
|
87
|
+
connection,
|
|
88
|
+
f"_{_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER}",
|
|
89
|
+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class _TrackedQueryCancellationTimer(Timer):
|
|
94
|
+
def __init__(self, interval, function, args=None, kwargs=None):
|
|
95
|
+
super().__init__(interval, function, args, kwargs)
|
|
96
|
+
self.executed = False
|
|
97
|
+
|
|
98
|
+
def run(self):
|
|
99
|
+
super().run()
|
|
100
|
+
self.executed = True
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_application_path() -> str:
|
|
104
|
+
"""Get the path of the application script using the connector."""
|
|
105
|
+
try:
|
|
106
|
+
outermost_frame = stack()[-1]
|
|
107
|
+
return outermost_frame.filename
|
|
108
|
+
except Exception:
|
|
109
|
+
return "unknown"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
_SPCS_TOKEN_ENV_VAR_NAME = "SF_SPCS_TOKEN_PATH"
|
|
113
|
+
_SPCS_TOKEN_DEFAULT_PATH = "/snowflake/session/spcs_token"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_spcs_token() -> str | None:
|
|
117
|
+
"""Return the SPCS token read from the configured path, or None.
|
|
118
|
+
|
|
119
|
+
The path is determined by the SF_SPCS_TOKEN_PATH environment variable,
|
|
120
|
+
falling back to ``/snowflake/session/spcs_token`` when unset.
|
|
121
|
+
|
|
122
|
+
Any I/O errors or missing/empty files are treated as \"no token\" and
|
|
123
|
+
will not cause authentication to fail.
|
|
124
|
+
"""
|
|
125
|
+
path = os.getenv(_SPCS_TOKEN_ENV_VAR_NAME) or _SPCS_TOKEN_DEFAULT_PATH
|
|
126
|
+
try:
|
|
127
|
+
if not os.path.isfile(path):
|
|
128
|
+
return None
|
|
129
|
+
with open(path, encoding="utf-8") as f:
|
|
130
|
+
token = f.read().strip()
|
|
131
|
+
if not token:
|
|
132
|
+
return None
|
|
133
|
+
return token
|
|
134
|
+
except Exception as exc: # pragma: no cover - best-effort logging only
|
|
135
|
+
logger.debug("Failed to read SPCS token from %s: %s", path, exc)
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class _NanoarrowLoader:
|
|
140
|
+
def __init__(self):
|
|
141
|
+
self._error: Exception | None = None
|
|
142
|
+
|
|
143
|
+
def set_load_error(self, err: Exception):
|
|
144
|
+
self._error = err
|
|
145
|
+
|
|
146
|
+
def get_load_error(self) -> str:
|
|
147
|
+
return str(self._error)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class _CoreLoader:
|
|
151
|
+
def __init__(self):
|
|
152
|
+
self._version: bytes | None = None
|
|
153
|
+
self._error: Exception | None = None
|
|
154
|
+
self._path: str | None = None
|
|
155
|
+
self._load_time: float | None = None
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def _detect_os() -> str:
|
|
159
|
+
"""Detect the operating system."""
|
|
160
|
+
system = platform.system().lower()
|
|
161
|
+
if system == "linux":
|
|
162
|
+
return "linux"
|
|
163
|
+
elif system == "darwin":
|
|
164
|
+
return "macos"
|
|
165
|
+
elif system == "windows":
|
|
166
|
+
return "windows"
|
|
167
|
+
elif system == "aix":
|
|
168
|
+
return "aix"
|
|
169
|
+
else:
|
|
170
|
+
return "unknown"
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def _detect_arch() -> str:
|
|
174
|
+
"""Detect the CPU architecture."""
|
|
175
|
+
machine = platform.machine().lower()
|
|
176
|
+
if machine in ("x86_64", "amd64"):
|
|
177
|
+
return "x86_64"
|
|
178
|
+
elif machine in ("aarch64", "arm64"):
|
|
179
|
+
return "aarch64"
|
|
180
|
+
elif machine in ("i686", "i386", "x86"):
|
|
181
|
+
return "i686"
|
|
182
|
+
elif machine == "ppc64":
|
|
183
|
+
return "ppc64"
|
|
184
|
+
else:
|
|
185
|
+
return "unknown"
|
|
186
|
+
|
|
187
|
+
@staticmethod
|
|
188
|
+
def _detect_libc() -> str:
|
|
189
|
+
"""Detect libc type on Linux (glibc vs musl)."""
|
|
190
|
+
lib, _ = platform.libc_ver()
|
|
191
|
+
if lib == "glibc":
|
|
192
|
+
return "glibc"
|
|
193
|
+
return "musl"
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _get_platform_subdir() -> str:
|
|
197
|
+
"""Get the platform-specific subdirectory name."""
|
|
198
|
+
os_name = _CoreLoader._detect_os()
|
|
199
|
+
arch = _CoreLoader._detect_arch()
|
|
200
|
+
|
|
201
|
+
if os_name == "linux":
|
|
202
|
+
libc = _CoreLoader._detect_libc()
|
|
203
|
+
return f"linux_{arch}_{libc}"
|
|
204
|
+
elif os_name == "macos":
|
|
205
|
+
return f"macos_{arch}"
|
|
206
|
+
elif os_name == "windows":
|
|
207
|
+
return f"windows_{arch}"
|
|
208
|
+
elif os_name == "aix":
|
|
209
|
+
return f"aix_{arch}"
|
|
210
|
+
|
|
211
|
+
raise OSError(f"Mini core binary for {os_name} {arch} not found")
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _get_lib_name() -> str:
|
|
215
|
+
"""Get the library filename for the current platform."""
|
|
216
|
+
os_name = _CoreLoader._detect_os()
|
|
217
|
+
if os_name == "windows":
|
|
218
|
+
return "sf_mini_core.dll"
|
|
219
|
+
elif os_name == "macos":
|
|
220
|
+
return "libsf_mini_core.dylib"
|
|
221
|
+
elif os_name == "aix":
|
|
222
|
+
return "libsf_mini_core.a"
|
|
223
|
+
else:
|
|
224
|
+
# Linux and other Unix-like systems
|
|
225
|
+
return "libsf_mini_core.so"
|
|
226
|
+
|
|
227
|
+
@staticmethod
|
|
228
|
+
def _get_core_path():
|
|
229
|
+
"""Get the path to the minicore library for the current platform."""
|
|
230
|
+
subdir = _CoreLoader._get_platform_subdir()
|
|
231
|
+
lib_name = _CoreLoader._get_lib_name()
|
|
232
|
+
|
|
233
|
+
files = importlib.resources.files("snowflake.connector.minicore")
|
|
234
|
+
|
|
235
|
+
return files.joinpath(subdir, lib_name)
|
|
236
|
+
|
|
237
|
+
@staticmethod
|
|
238
|
+
def _register_functions(core: ctypes.CDLL):
|
|
239
|
+
core.sf_core_full_version.argtypes = []
|
|
240
|
+
core.sf_core_full_version.restype = ctypes.c_char_p
|
|
241
|
+
|
|
242
|
+
@staticmethod
|
|
243
|
+
def _load_minicore(path: str) -> ctypes.CDLL:
|
|
244
|
+
# This context manager is the safe way to get a
|
|
245
|
+
# file path from importlib.resources. It handles cases
|
|
246
|
+
# where the file is inside a zip and needs to be extracted
|
|
247
|
+
# to a temporary location.
|
|
248
|
+
with importlib.resources.as_file(path) as lib_path:
|
|
249
|
+
core = ctypes.CDLL(str(lib_path))
|
|
250
|
+
return core
|
|
251
|
+
|
|
252
|
+
def get_present_binaries(self) -> str:
|
|
253
|
+
present_binaries = []
|
|
254
|
+
try:
|
|
255
|
+
minicore_files = importlib.resources.files("snowflake.connector.minicore")
|
|
256
|
+
# Iterate through all items in the minicore module
|
|
257
|
+
for item in minicore_files.iterdir():
|
|
258
|
+
# Skip non-platform directories like __pycache__
|
|
259
|
+
if item.is_dir() and not item.name.startswith("__"):
|
|
260
|
+
# This is a platform subdirectory
|
|
261
|
+
platform_name = item.name
|
|
262
|
+
try:
|
|
263
|
+
# List all files in this subdirectory
|
|
264
|
+
for binary_file in item.iterdir():
|
|
265
|
+
if binary_file.is_file():
|
|
266
|
+
# Store as "platform/filename"
|
|
267
|
+
present_binaries.append(
|
|
268
|
+
f"{platform_name}/{binary_file.name}"
|
|
269
|
+
)
|
|
270
|
+
except Exception as e:
|
|
271
|
+
logger.debug(f"Error listing binaries in {platform_name}: {e}")
|
|
272
|
+
except Exception as e:
|
|
273
|
+
logger.debug(f"Error populating present binaries: {e}")
|
|
274
|
+
|
|
275
|
+
return ",".join(present_binaries)
|
|
276
|
+
|
|
277
|
+
def _is_core_disabled(self) -> bool:
|
|
278
|
+
value = str(os.getenv("SNOWFLAKE_DISABLE_MINICORE", None)).lower()
|
|
279
|
+
return value in ["1", "true"]
|
|
280
|
+
|
|
281
|
+
def _load(self) -> None:
|
|
282
|
+
start_time = time.perf_counter()
|
|
283
|
+
try:
|
|
284
|
+
path = self._get_core_path()
|
|
285
|
+
self._path = str(path)
|
|
286
|
+
core = self._load_minicore(path)
|
|
287
|
+
self._register_functions(core)
|
|
288
|
+
self._version = core.sf_core_full_version()
|
|
289
|
+
self._error = None
|
|
290
|
+
except Exception as err:
|
|
291
|
+
self._error = err
|
|
292
|
+
end_time = time.perf_counter()
|
|
293
|
+
# Store load time in milliseconds (with sub-millisecond precision)
|
|
294
|
+
self._load_time = (end_time - start_time) * 1000
|
|
295
|
+
|
|
296
|
+
def load(self):
|
|
297
|
+
"""Spawn a separate thread to load the minicore library (non-blocking)."""
|
|
298
|
+
if self._is_core_disabled():
|
|
299
|
+
self._error = "mini-core-disabled"
|
|
300
|
+
return
|
|
301
|
+
self._error = "still-loading"
|
|
302
|
+
thread = threading.Thread(target=self._load, daemon=True)
|
|
303
|
+
thread.start()
|
|
304
|
+
|
|
305
|
+
def get_load_error(self) -> str:
|
|
306
|
+
return str(self._error)
|
|
307
|
+
|
|
308
|
+
def get_core_version(self) -> str | None:
|
|
309
|
+
if self._version:
|
|
310
|
+
try:
|
|
311
|
+
return self._version.decode("utf-8")
|
|
312
|
+
except Exception:
|
|
313
|
+
pass
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
def get_file_name(self) -> str:
|
|
317
|
+
return self._path
|
|
318
|
+
|
|
319
|
+
def get_load_time(self) -> float | None:
|
|
320
|
+
"""Return the time it took to load the minicore binary in milliseconds."""
|
|
321
|
+
return self._load_time
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
_core_loader = _CoreLoader()
|
|
325
|
+
_nanoarrow_loader = _NanoarrowLoader()
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def build_minicore_usage_for_session() -> dict[str, str | None]:
|
|
329
|
+
return {
|
|
330
|
+
"ISA": ISA,
|
|
331
|
+
"CORE_VERSION": _core_loader.get_core_version(),
|
|
332
|
+
"CORE_FILE_NAME": _core_loader.get_file_name(),
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def build_minicore_usage_for_telemetry() -> dict[str, str | None]:
|
|
337
|
+
return {
|
|
338
|
+
"OS": OPERATING_SYSTEM,
|
|
339
|
+
"OS_VERSION": OS_VERSION,
|
|
340
|
+
"CORE_LOAD_ERROR": _core_loader.get_load_error(),
|
|
341
|
+
"CORE_BINARIES_PRESENT": _core_loader.get_present_binaries(),
|
|
342
|
+
"CORE_LOAD_TIME": _core_loader.get_load_time(),
|
|
343
|
+
**build_minicore_usage_for_session(),
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def build_nanoarrow_usage_for_telemetry() -> dict[str, str | None]:
|
|
348
|
+
return {
|
|
349
|
+
"OS": OPERATING_SYSTEM,
|
|
350
|
+
"OS_VERSION": OS_VERSION,
|
|
351
|
+
"NANOARROW_LOAD_ERROR": _nanoarrow_loader.get_load_error(),
|
|
352
|
+
"ISA": ISA,
|
|
353
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Notice
|
|
2
|
+
|
|
3
|
+
**This component is a Preview feature provided for experimental purposes only.
|
|
4
|
+
It is provided "AS IS" and without warranty of any kind. This module is not
|
|
5
|
+
supported by Snowflake Support. Use of this code is at your own risk and it
|
|
6
|
+
is not intended for production environments.**
|
|
7
|
+
|
|
8
|
+
## Features NOT Supported
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
- ❌ `conn.errorhandler` (get/set) - no support for async errorhandlers
|
|
12
|
+
- ❌ `enable_connection_diag=True` - no connection diagnostic
|
|
13
|
+
- ❌ `authenticator='PAT_WITH_EXTERNAL_SESSION'` - not supported
|
|
14
|
+
- ❌ `mfa_callback` / `password_callback` - not supported
|
|
15
|
+
- ❌ `_probe_connection=True` - no connection diagnostic
|
|
16
|
+
- ❌ Raw binary response handling - not supported
|
|
17
|
+
- ❌ CRL (Certificate Revocation List) - not supported (only OCSP is supported)
|
|
18
|
+
|
|
19
|
+
## Installation & Import
|
|
20
|
+
|
|
21
|
+
Using aio version requires additional installation of `aiohttp` dependency.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
# Same package, different import
|
|
25
|
+
from snowflake.connector.aio import connect, SnowflakeConnection, DictCursor
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Connection Patterns
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
# Pattern 1: Async context manager (recommended)
|
|
34
|
+
async with connect(user='...', password='...', account='...') as conn:
|
|
35
|
+
# Use connection
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Pattern 2: Direct await
|
|
40
|
+
conn = await connect(user='...', password='...', account='...')
|
|
41
|
+
await conn.close()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Pattern 3: Manual
|
|
45
|
+
conn = SnowflakeConnection(user='...', password='...', account='...')
|
|
46
|
+
await conn.connect()
|
|
47
|
+
await conn.close()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Basic Operations Comparison
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
| Operation | Sync | Async |
|
|
55
|
+
|-----------|------|-------|
|
|
56
|
+
| **Connect** | `conn = connect(...)` | `conn = await connect(...)` |
|
|
57
|
+
| **Create cursor** | `cur = conn.cursor()` | `cur = conn.cursor()` *(same)* |
|
|
58
|
+
| **Execute** | `cur.execute(sql)` | `await cur.execute(sql)` |
|
|
59
|
+
| **Fetch one** | `cur.fetchone()` | `await cur.fetchone()` |
|
|
60
|
+
| **Fetch many** | `cur.fetchmany(n)` | `await cur.fetchmany(n)` |
|
|
61
|
+
| **Fetch all** | `cur.fetchall()` | `await cur.fetchall()` |
|
|
62
|
+
| **Iterate** | `for row in cur:` | `async for row in cur:` |
|
|
63
|
+
| **Commit** | `conn.commit()` | `await conn.commit()` |
|
|
64
|
+
| **Rollback** | `conn.rollback()` | `await conn.rollback()` |
|
|
65
|
+
| **Close** | `conn.close()` | `await conn.close()` |
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Quick Examples
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### Simple Query
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import asyncio
|
|
76
|
+
from snowflake.connector.aio import connect
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def query_data():
|
|
80
|
+
async with connect(user='...', password='...', account='...') as conn:
|
|
81
|
+
async with conn.cursor() as cur:
|
|
82
|
+
await cur.execute("SELECT * FROM table WHERE id < %s", (100,))
|
|
83
|
+
async for row in cur:
|
|
84
|
+
print(row)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
asyncio.run(query_data())
|
|
88
|
+
```
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import Any, Coroutine, Generator, Protocol, TypeVar, runtime_checkable
|
|
5
|
+
|
|
6
|
+
from ._connection import SnowflakeConnection
|
|
7
|
+
from ._cursor import DictCursor, SnowflakeCursor
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
SnowflakeConnection,
|
|
11
|
+
SnowflakeCursor,
|
|
12
|
+
DictCursor,
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
# ============================================================================
|
|
16
|
+
# DESIGN NOTES:
|
|
17
|
+
#
|
|
18
|
+
# Pattern similar to aiohttp.ClientSession.request() which similarly returns
|
|
19
|
+
# an object that can be both awaited and used as an async context manager.
|
|
20
|
+
#
|
|
21
|
+
# The async connect function uses a wrapper to support both:
|
|
22
|
+
# 1. Direct awaiting: conn = await connect(...)
|
|
23
|
+
# 2. Async context manager: async with connect(...) as conn:
|
|
24
|
+
#
|
|
25
|
+
# connect: A function decorated with @wraps(SnowflakeConnection.__init__) that
|
|
26
|
+
# preserves metadata for IDE support, type checking, and introspection.
|
|
27
|
+
# Returns a _AsyncConnectContextManager instance when called.
|
|
28
|
+
#
|
|
29
|
+
# _AsyncConnectContextManager: Implements __await__ and __aenter__/__aexit__
|
|
30
|
+
# to support both patterns on the same awaitable.
|
|
31
|
+
#
|
|
32
|
+
# The @wraps decorator ensures that connect() has the same signature and
|
|
33
|
+
# documentation as SnowflakeConnection.__init__, making it behave identically
|
|
34
|
+
# to the sync snowflake.connector.connect function from an introspection POV.
|
|
35
|
+
#
|
|
36
|
+
# Metadata preservation is critical for IDE autocomplete, static type checkers,
|
|
37
|
+
# and documentation generation to work correctly on the async connect function.
|
|
38
|
+
# ============================================================================
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
T = TypeVar("T")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@runtime_checkable
|
|
45
|
+
class HybridCoroutineContextManager(Protocol[T]):
|
|
46
|
+
"""Protocol for a hybrid coroutine that is also an async context manager.
|
|
47
|
+
|
|
48
|
+
Combines the full coroutine protocol (PEP 492) with async context manager
|
|
49
|
+
protocol (PEP 343/492), allowing code that expects either interface to work
|
|
50
|
+
seamlessly with instances of this protocol.
|
|
51
|
+
|
|
52
|
+
This is used when external code needs to manage the coroutine lifecycle
|
|
53
|
+
(e.g., timeout handlers, async schedulers) or use it as a context manager.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# Full Coroutine Protocol (PEP 492)
|
|
57
|
+
def send(self, __arg: Any) -> Any:
|
|
58
|
+
"""Send a value into the coroutine."""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
def throw(
|
|
62
|
+
self,
|
|
63
|
+
__typ: type[BaseException],
|
|
64
|
+
__val: BaseException | None = None,
|
|
65
|
+
__tb: Any = None,
|
|
66
|
+
) -> Any:
|
|
67
|
+
"""Throw an exception into the coroutine."""
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
def close(self) -> None:
|
|
71
|
+
"""Close the coroutine."""
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
def __await__(self) -> Generator[Any, None, T]:
|
|
75
|
+
"""Return awaitable generator."""
|
|
76
|
+
...
|
|
77
|
+
|
|
78
|
+
def __iter__(self) -> Generator[Any, None, T]:
|
|
79
|
+
"""Iterate over the coroutine."""
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
# Async Context Manager Protocol (PEP 343)
|
|
83
|
+
async def __aenter__(self) -> T:
|
|
84
|
+
"""Async context manager entry."""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
async def __aexit__(
|
|
88
|
+
self,
|
|
89
|
+
__exc_type: type[BaseException] | None,
|
|
90
|
+
__exc_val: BaseException | None,
|
|
91
|
+
__exc_tb: Any,
|
|
92
|
+
) -> bool | None:
|
|
93
|
+
"""Async context manager exit."""
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class _AsyncConnectContextManager(HybridCoroutineContextManager[SnowflakeConnection]):
|
|
98
|
+
"""Hybrid wrapper that enables both awaiting and async context manager usage.
|
|
99
|
+
|
|
100
|
+
Allows both patterns:
|
|
101
|
+
- conn = await connect(...)
|
|
102
|
+
- async with connect(...) as conn:
|
|
103
|
+
|
|
104
|
+
Implements the full coroutine protocol for maximum compatibility.
|
|
105
|
+
Satisfies the HybridCoroutineContextManager protocol.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
__slots__ = ("_coro", "_conn")
|
|
109
|
+
|
|
110
|
+
def __init__(self, coro: Coroutine[Any, Any, SnowflakeConnection]) -> None:
|
|
111
|
+
self._coro = coro
|
|
112
|
+
self._conn: SnowflakeConnection | None = None
|
|
113
|
+
|
|
114
|
+
def send(self, arg: Any) -> Any:
|
|
115
|
+
"""Send a value into the wrapped coroutine."""
|
|
116
|
+
return self._coro.send(arg)
|
|
117
|
+
|
|
118
|
+
def throw(self, *args: Any, **kwargs: Any) -> Any:
|
|
119
|
+
"""Throw an exception into the wrapped coroutine."""
|
|
120
|
+
return self._coro.throw(*args, **kwargs)
|
|
121
|
+
|
|
122
|
+
def close(self) -> None:
|
|
123
|
+
"""Close the wrapped coroutine."""
|
|
124
|
+
return self._coro.close()
|
|
125
|
+
|
|
126
|
+
def __await__(self) -> Generator[Any, None, SnowflakeConnection]:
|
|
127
|
+
"""Enable await connect(...)"""
|
|
128
|
+
return self._coro.__await__()
|
|
129
|
+
|
|
130
|
+
def __iter__(self) -> Generator[Any, None, SnowflakeConnection]:
|
|
131
|
+
"""Make the wrapper iterable like a coroutine."""
|
|
132
|
+
return self.__await__()
|
|
133
|
+
|
|
134
|
+
# This approach requires idempotent __aenter__ of SnowflakeConnection class - so check if connected and do not repeat connecting
|
|
135
|
+
async def __aenter__(self) -> SnowflakeConnection:
|
|
136
|
+
"""Enable async with connect(...) as conn:"""
|
|
137
|
+
self._conn = await self._coro
|
|
138
|
+
return await self._conn.__aenter__()
|
|
139
|
+
|
|
140
|
+
async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
|
|
141
|
+
"""Exit async context manager."""
|
|
142
|
+
if self._conn is not None:
|
|
143
|
+
return await self._conn.__aexit__(exc_type, exc, tb)
|
|
144
|
+
else:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@wraps(SnowflakeConnection.__init__)
|
|
149
|
+
def connect(**kwargs: Any) -> HybridCoroutineContextManager[SnowflakeConnection]:
|
|
150
|
+
"""Create and connect to a Snowflake connection asynchronously.
|
|
151
|
+
|
|
152
|
+
Returns an awaitable that can also be used as an async context manager.
|
|
153
|
+
Supports both patterns:
|
|
154
|
+
- conn = await connect(...)
|
|
155
|
+
- async with connect(...) as conn:
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
async def _connect_coro() -> SnowflakeConnection:
|
|
159
|
+
conn = SnowflakeConnection(**kwargs)
|
|
160
|
+
await conn.connect()
|
|
161
|
+
return conn
|
|
162
|
+
|
|
163
|
+
return _AsyncConnectContextManager(_connect_coro())
|