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,360 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from logging import getLogger
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
import aiohttp
|
|
12
|
+
|
|
13
|
+
from ..constants import HTTP_HEADER_CONTENT_ENCODING, FileHeader, ResultStatus
|
|
14
|
+
from ..encryption_util import EncryptionMetadata
|
|
15
|
+
from ..gcs_storage_client import SnowflakeGCSRestClient as SnowflakeGCSRestClientSync
|
|
16
|
+
from ._storage_client import SnowflakeStorageClient as SnowflakeStorageClientAsync
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
19
|
+
from ..file_transfer_agent import SnowflakeFileMeta, StorageCredential
|
|
20
|
+
from ._connection import SnowflakeConnection
|
|
21
|
+
|
|
22
|
+
logger = getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
from ..gcs_storage_client import (
|
|
25
|
+
GCS_METADATA_ENCRYPTIONDATAPROP,
|
|
26
|
+
GCS_METADATA_MATDESC_KEY,
|
|
27
|
+
GCS_METADATA_SFC_DIGEST,
|
|
28
|
+
GCS_REGION_ME_CENTRAL_2,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SnowflakeGCSRestClient(SnowflakeStorageClientAsync, SnowflakeGCSRestClientSync):
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
meta: SnowflakeFileMeta,
|
|
36
|
+
credentials: StorageCredential,
|
|
37
|
+
stage_info: dict[str, Any],
|
|
38
|
+
cnx: SnowflakeConnection,
|
|
39
|
+
command: str,
|
|
40
|
+
unsafe_file_write: bool = False,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""Creates a client object with given stage credentials.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
stage_info: Access credentials and info of a stage.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
The client to communicate with GCS.
|
|
49
|
+
"""
|
|
50
|
+
SnowflakeStorageClientAsync.__init__(
|
|
51
|
+
self,
|
|
52
|
+
meta=meta,
|
|
53
|
+
stage_info=stage_info,
|
|
54
|
+
chunk_size=-1,
|
|
55
|
+
credentials=credentials,
|
|
56
|
+
chunked_transfer=False,
|
|
57
|
+
unsafe_file_write=unsafe_file_write,
|
|
58
|
+
)
|
|
59
|
+
self.stage_info = stage_info
|
|
60
|
+
self._command = command
|
|
61
|
+
self.meta = meta
|
|
62
|
+
self._cursor = cnx.cursor()
|
|
63
|
+
# presigned_url in meta is for downloading
|
|
64
|
+
self.presigned_url: str = meta.presigned_url or stage_info.get("presignedUrl")
|
|
65
|
+
self.security_token = credentials.creds.get("GCS_ACCESS_TOKEN")
|
|
66
|
+
self.use_regional_url = (
|
|
67
|
+
"region" in stage_info
|
|
68
|
+
and stage_info["region"].lower() == GCS_REGION_ME_CENTRAL_2
|
|
69
|
+
or "useRegionalUrl" in stage_info
|
|
70
|
+
and stage_info["useRegionalUrl"]
|
|
71
|
+
)
|
|
72
|
+
self.endpoint: str | None = (
|
|
73
|
+
None if "endPoint" not in stage_info else stage_info["endPoint"]
|
|
74
|
+
)
|
|
75
|
+
self.use_virtual_url: bool = (
|
|
76
|
+
"useVirtualUrl" in stage_info and stage_info["useVirtualUrl"]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
async def _has_expired_token(self, response: aiohttp.ClientResponse) -> bool:
|
|
80
|
+
return self.security_token and response.status == 401
|
|
81
|
+
|
|
82
|
+
async def _has_expired_presigned_url(
|
|
83
|
+
self, response: aiohttp.ClientResponse
|
|
84
|
+
) -> bool:
|
|
85
|
+
# Presigned urls can be generated for any xml-api operation
|
|
86
|
+
# offered by GCS. Hence, the error codes expected are similar
|
|
87
|
+
# to xml api.
|
|
88
|
+
# https://cloud.google.com/storage/docs/xml-api/reference-status
|
|
89
|
+
|
|
90
|
+
presigned_url_expired = (not self.security_token) and response.status == 400
|
|
91
|
+
if presigned_url_expired and self.last_err_is_presigned_url:
|
|
92
|
+
logger.debug("Presigned url expiration error two times in a row.")
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
self.last_err_is_presigned_url = presigned_url_expired
|
|
95
|
+
return presigned_url_expired
|
|
96
|
+
|
|
97
|
+
async def _upload_chunk(self, chunk_id: int, chunk: bytes) -> None:
|
|
98
|
+
meta = self.meta
|
|
99
|
+
|
|
100
|
+
content_encoding = ""
|
|
101
|
+
if meta.dst_compression_type is not None:
|
|
102
|
+
content_encoding = meta.dst_compression_type.name.lower()
|
|
103
|
+
|
|
104
|
+
# We set the contentEncoding to blank for GZIP files. We don't
|
|
105
|
+
# want GCS to think our gzip files are gzips because it makes
|
|
106
|
+
# them download uncompressed, and none of the other providers do
|
|
107
|
+
# that. There's essentially no way for us to prevent that
|
|
108
|
+
# behavior. Bad Google.
|
|
109
|
+
if content_encoding and content_encoding == "gzip":
|
|
110
|
+
content_encoding = ""
|
|
111
|
+
|
|
112
|
+
gcs_headers = {
|
|
113
|
+
HTTP_HEADER_CONTENT_ENCODING: content_encoding,
|
|
114
|
+
GCS_METADATA_SFC_DIGEST: meta.sha256_digest,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if self.encryption_metadata:
|
|
118
|
+
gcs_headers.update(
|
|
119
|
+
{
|
|
120
|
+
GCS_METADATA_ENCRYPTIONDATAPROP: json.dumps(
|
|
121
|
+
{
|
|
122
|
+
"EncryptionMode": "FullBlob",
|
|
123
|
+
"WrappedContentKey": {
|
|
124
|
+
"KeyId": "symmKey1",
|
|
125
|
+
"EncryptedKey": self.encryption_metadata.key,
|
|
126
|
+
"Algorithm": "AES_CBC_256",
|
|
127
|
+
},
|
|
128
|
+
"EncryptionAgent": {
|
|
129
|
+
"Protocol": "1.0",
|
|
130
|
+
"EncryptionAlgorithm": "AES_CBC_256",
|
|
131
|
+
},
|
|
132
|
+
"ContentEncryptionIV": self.encryption_metadata.iv,
|
|
133
|
+
"KeyWrappingMetadata": {"EncryptionLibrary": "Java 5.3.0"},
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
GCS_METADATA_MATDESC_KEY: self.encryption_metadata.matdesc,
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def generate_url_and_rest_args() -> (
|
|
141
|
+
tuple[str, dict[str, dict[str | Any, str | None] | bytes]]
|
|
142
|
+
):
|
|
143
|
+
if not self.presigned_url:
|
|
144
|
+
upload_url = self.generate_file_url(
|
|
145
|
+
self.stage_info["location"],
|
|
146
|
+
meta.dst_file_name.lstrip("/"),
|
|
147
|
+
self.use_regional_url,
|
|
148
|
+
(
|
|
149
|
+
None
|
|
150
|
+
if "region" not in self.stage_info
|
|
151
|
+
else self.stage_info["region"]
|
|
152
|
+
),
|
|
153
|
+
self.endpoint,
|
|
154
|
+
self.use_virtual_url,
|
|
155
|
+
)
|
|
156
|
+
access_token = self.security_token
|
|
157
|
+
else:
|
|
158
|
+
upload_url = self.presigned_url
|
|
159
|
+
access_token: str | None = None
|
|
160
|
+
if access_token:
|
|
161
|
+
gcs_headers.update({"Authorization": f"Bearer {access_token}"})
|
|
162
|
+
rest_args = {"headers": gcs_headers, "data": chunk}
|
|
163
|
+
return upload_url, rest_args
|
|
164
|
+
|
|
165
|
+
response = await self._send_request_with_retry(
|
|
166
|
+
"PUT", generate_url_and_rest_args, chunk_id
|
|
167
|
+
)
|
|
168
|
+
response.raise_for_status()
|
|
169
|
+
meta.gcs_file_header_digest = gcs_headers[GCS_METADATA_SFC_DIGEST]
|
|
170
|
+
meta.gcs_file_header_content_length = meta.upload_size
|
|
171
|
+
meta.gcs_file_header_encryption_metadata = json.loads(
|
|
172
|
+
gcs_headers.get(GCS_METADATA_ENCRYPTIONDATAPROP, "null")
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
async def download_chunk(self, chunk_id: int) -> None:
|
|
176
|
+
meta = self.meta
|
|
177
|
+
|
|
178
|
+
def generate_url_and_rest_args() -> (
|
|
179
|
+
tuple[str, dict[str, dict[str, str] | bool]]
|
|
180
|
+
):
|
|
181
|
+
gcs_headers = {}
|
|
182
|
+
if not self.presigned_url:
|
|
183
|
+
download_url = self.generate_file_url(
|
|
184
|
+
self.stage_info["location"],
|
|
185
|
+
meta.src_file_name.lstrip("/"),
|
|
186
|
+
self.use_regional_url,
|
|
187
|
+
(
|
|
188
|
+
None
|
|
189
|
+
if "region" not in self.stage_info
|
|
190
|
+
else self.stage_info["region"]
|
|
191
|
+
),
|
|
192
|
+
self.endpoint,
|
|
193
|
+
self.use_virtual_url,
|
|
194
|
+
)
|
|
195
|
+
access_token = self.security_token
|
|
196
|
+
gcs_headers["Authorization"] = f"Bearer {access_token}"
|
|
197
|
+
else:
|
|
198
|
+
download_url = self.presigned_url
|
|
199
|
+
rest_args = {"headers": gcs_headers}
|
|
200
|
+
return download_url, rest_args
|
|
201
|
+
|
|
202
|
+
response = await self._send_request_with_retry(
|
|
203
|
+
"GET", generate_url_and_rest_args, chunk_id
|
|
204
|
+
)
|
|
205
|
+
response.raise_for_status()
|
|
206
|
+
|
|
207
|
+
self.write_downloaded_chunk(chunk_id, await response.read())
|
|
208
|
+
|
|
209
|
+
encryption_metadata = None
|
|
210
|
+
|
|
211
|
+
if response.headers.get(GCS_METADATA_ENCRYPTIONDATAPROP, None):
|
|
212
|
+
encryptiondata = json.loads(
|
|
213
|
+
response.headers[GCS_METADATA_ENCRYPTIONDATAPROP]
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
if encryptiondata:
|
|
217
|
+
encryption_metadata = EncryptionMetadata(
|
|
218
|
+
key=encryptiondata["WrappedContentKey"]["EncryptedKey"],
|
|
219
|
+
iv=encryptiondata["ContentEncryptionIV"],
|
|
220
|
+
matdesc=(
|
|
221
|
+
response.headers[GCS_METADATA_MATDESC_KEY]
|
|
222
|
+
if GCS_METADATA_MATDESC_KEY in response.headers
|
|
223
|
+
else None
|
|
224
|
+
),
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
meta.gcs_file_header_digest = response.headers.get(GCS_METADATA_SFC_DIGEST)
|
|
228
|
+
meta.gcs_file_header_content_length = len(await response.read())
|
|
229
|
+
meta.gcs_file_header_encryption_metadata = encryption_metadata
|
|
230
|
+
|
|
231
|
+
async def finish_download(self) -> None:
|
|
232
|
+
await SnowflakeStorageClientAsync.finish_download(self)
|
|
233
|
+
# Sadly, we can only determine the src file size after we've
|
|
234
|
+
# downloaded it, unlike the other cloud providers where the
|
|
235
|
+
# metadata can be read beforehand.
|
|
236
|
+
self.meta.src_file_size = os.path.getsize(self.full_dst_file_name)
|
|
237
|
+
|
|
238
|
+
async def _update_presigned_url(self) -> None:
|
|
239
|
+
"""Updates the file metas with presigned urls if any.
|
|
240
|
+
|
|
241
|
+
Currently only the file metas generated for PUT/GET on a GCP account need the presigned urls.
|
|
242
|
+
"""
|
|
243
|
+
logger.debug("Updating presigned url")
|
|
244
|
+
|
|
245
|
+
# Rewrite the command such that a new PUT call is made for each file
|
|
246
|
+
# represented by the regex (if present) separately. This is the only
|
|
247
|
+
# way to get the presigned url for that file.
|
|
248
|
+
file_path_to_be_replaced = self._get_local_file_path_from_put_command()
|
|
249
|
+
|
|
250
|
+
if not file_path_to_be_replaced:
|
|
251
|
+
# This prevents GET statements to proceed
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
# At this point the connector has already figured out and
|
|
255
|
+
# validated that the local file exists and has also decided
|
|
256
|
+
# upon the destination file name and the compression type.
|
|
257
|
+
# The only thing that's left to do is to get the presigned
|
|
258
|
+
# url for the destination file. If the command originally
|
|
259
|
+
# referred to a single file, then the presigned url got in
|
|
260
|
+
# that case is simply ignore, since the file name is not what
|
|
261
|
+
# we want.
|
|
262
|
+
|
|
263
|
+
# GS only looks at the file name at the end of local file
|
|
264
|
+
# path to figure out the remote object name. Hence the prefix
|
|
265
|
+
# for local path is not necessary in the reconstructed command.
|
|
266
|
+
file_path_to_replace_with = self.meta.dst_file_name
|
|
267
|
+
command_with_single_file = self._command
|
|
268
|
+
command_with_single_file = command_with_single_file.replace(
|
|
269
|
+
file_path_to_be_replaced, file_path_to_replace_with
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
logger.debug("getting presigned url for %s", file_path_to_replace_with)
|
|
273
|
+
ret = await self._cursor._execute_helper(command_with_single_file)
|
|
274
|
+
|
|
275
|
+
stage_info = ret.get("data", dict()).get("stageInfo", dict())
|
|
276
|
+
self.meta.presigned_url = stage_info.get("presignedUrl")
|
|
277
|
+
self.presigned_url = stage_info.get("presignedUrl")
|
|
278
|
+
|
|
279
|
+
async def get_file_header(self, filename: str) -> FileHeader | None:
|
|
280
|
+
"""Gets the remote file's metadata.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
filename: Not applicable to GCS.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
The file header, with expected properties populated or None, based on how the request goes with the
|
|
287
|
+
storage provider.
|
|
288
|
+
|
|
289
|
+
Notes:
|
|
290
|
+
Sometimes this method is called to verify that the file has indeed been uploaded. In cases of presigned
|
|
291
|
+
url, we have no way of verifying that, except with the http status code of 200 which we have already
|
|
292
|
+
confirmed and set the meta.result_status = UPLOADED/DOWNLOADED.
|
|
293
|
+
"""
|
|
294
|
+
meta = self.meta
|
|
295
|
+
if (
|
|
296
|
+
meta.result_status == ResultStatus.UPLOADED
|
|
297
|
+
or meta.result_status == ResultStatus.DOWNLOADED
|
|
298
|
+
):
|
|
299
|
+
return FileHeader(
|
|
300
|
+
digest=meta.gcs_file_header_digest,
|
|
301
|
+
content_length=meta.gcs_file_header_content_length,
|
|
302
|
+
encryption_metadata=meta.gcs_file_header_encryption_metadata,
|
|
303
|
+
)
|
|
304
|
+
elif self.presigned_url:
|
|
305
|
+
meta.result_status = ResultStatus.NOT_FOUND_FILE
|
|
306
|
+
else:
|
|
307
|
+
|
|
308
|
+
def generate_url_and_authenticated_headers():
|
|
309
|
+
url = self.generate_file_url(
|
|
310
|
+
self.stage_info["location"],
|
|
311
|
+
filename.lstrip("/"),
|
|
312
|
+
self.use_regional_url,
|
|
313
|
+
(
|
|
314
|
+
None
|
|
315
|
+
if "region" not in self.stage_info
|
|
316
|
+
else self.stage_info["region"]
|
|
317
|
+
),
|
|
318
|
+
self.endpoint,
|
|
319
|
+
self.use_virtual_url,
|
|
320
|
+
)
|
|
321
|
+
gcs_headers = {"Authorization": f"Bearer {self.security_token}"}
|
|
322
|
+
rest_args = {"headers": gcs_headers}
|
|
323
|
+
return url, rest_args
|
|
324
|
+
|
|
325
|
+
retry_id = "HEAD"
|
|
326
|
+
self.retry_count[retry_id] = 0
|
|
327
|
+
response = await self._send_request_with_retry(
|
|
328
|
+
"HEAD", generate_url_and_authenticated_headers, retry_id
|
|
329
|
+
)
|
|
330
|
+
if response.status == 404:
|
|
331
|
+
meta.result_status = ResultStatus.NOT_FOUND_FILE
|
|
332
|
+
return None
|
|
333
|
+
elif response.status == 200:
|
|
334
|
+
digest = response.headers.get(GCS_METADATA_SFC_DIGEST, None)
|
|
335
|
+
content_length = int(response.headers.get("content-length", "0"))
|
|
336
|
+
|
|
337
|
+
encryption_metadata = EncryptionMetadata("", "", "")
|
|
338
|
+
if response.headers.get(GCS_METADATA_ENCRYPTIONDATAPROP, None):
|
|
339
|
+
encryption_data = json.loads(
|
|
340
|
+
response.headers[GCS_METADATA_ENCRYPTIONDATAPROP]
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
if encryption_data:
|
|
344
|
+
encryption_metadata = EncryptionMetadata(
|
|
345
|
+
key=encryption_data["WrappedContentKey"]["EncryptedKey"],
|
|
346
|
+
iv=encryption_data["ContentEncryptionIV"],
|
|
347
|
+
matdesc=(
|
|
348
|
+
response.headers[GCS_METADATA_MATDESC_KEY]
|
|
349
|
+
if GCS_METADATA_MATDESC_KEY in response.headers
|
|
350
|
+
else None
|
|
351
|
+
),
|
|
352
|
+
)
|
|
353
|
+
meta.result_status = ResultStatus.UPLOADED
|
|
354
|
+
return FileHeader(
|
|
355
|
+
digest=digest,
|
|
356
|
+
content_length=content_length,
|
|
357
|
+
encryption_metadata=encryption_metadata,
|
|
358
|
+
)
|
|
359
|
+
response.raise_for_status()
|
|
360
|
+
return None
|