snowflake-connector-python 4.0.0__tar.gz → 4.1.0__tar.gz
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_python-4.0.0 → snowflake_connector_python-4.1.0}/DESCRIPTION.md +10 -1
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/PKG-INFO +19 -10
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/setup.cfg +8 -8
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/_auth.py +30 -2
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/_http_server.py +44 -7
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/_oauth_base.py +16 -2
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/oauth_code.py +8 -3
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/webbrowser.py +16 -8
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/azure_storage_client.py +4 -4
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/connection.py +105 -4
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/connection_diagnostic.py +2 -2
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/constants.py +3 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/crl.py +158 -67
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +2 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/network.py +12 -5
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/ocsp_snowflake.py +5 -4
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/pandas_tools.py +1 -1
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/platform_detection.py +153 -65
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/result_batch.py +11 -5
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/session_manager.py +119 -48
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/ssl_wrap_socket.py +7 -3
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/storage_client.py +5 -3
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/telemetry.py +4 -4
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/telemetry_oob.py +1 -1
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/token_cache.py +37 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/util_text.py +4 -2
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/version.py +1 -1
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/wif_util.py +2 -2
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/PKG-INFO +19 -10
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/requires.txt +8 -8
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/CONTRIBUTING.md +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/LICENSE.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/MANIFEST.in +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/NOTICE +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/README.md +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/SECURITY.md +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/pyproject.toml +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/setup.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/_query_context_cache.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/_sql_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/_utils.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/arrow_context.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/by_plugin.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/default.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/idtoken.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/keypair.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/no_auth.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/oauth.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/oauth_credentials.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/okta.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/pat.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/usrpwdmfa.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/auth/workload_identity.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/backoff_policies.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/bind_upload_agent.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/cache.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/compat.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/config_manager.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/converter.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/converter_issue23517.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/converter_null.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/converter_snowsql.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/crl_cache.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/cursor.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/dbapi.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/description.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/direct_file_operation_utils.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/encryption_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/errorcode.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/errors.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/externals_utils/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/externals_utils/externals_setup.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/feature.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/file_compression_type.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/file_lock.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/file_transfer_agent.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/file_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/gcs_storage_client.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/gzip_decoder.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/interval_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/local_storage_client.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/log_configuration.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/logging_utils/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/logging_utils/filters.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/ocsp_asn1crypto.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/options.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/proxy.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/py.typed +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/result_set.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/s3_storage_client.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/secret_detector.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/sf_dirs.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/sfbinaryformat.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/sfdatetime.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/snow_logging.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/sqlstate.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/ssd_internal_keys.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/test_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/time_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/tool/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/tool/dump_certs.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/tool/dump_ocsp_response.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/tool/dump_ocsp_response_cache.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/tool/probe_connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/url_util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/LICENSE +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/__version__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/_internal_utils.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/adapters.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/api.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/auth.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/certs.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/compat.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/cookies.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/exceptions.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/help.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/hooks.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/models.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/packages.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/sessions.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/status_codes.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/structures.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/requests/utils.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/LICENSE.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/_base_connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/_collections.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/_request_methods.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/_version.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/connectionpool.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/emscripten_fetch_worker.js +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/fetch.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/request.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/emscripten/response.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/contrib/socks.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/exceptions.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/fields.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/filepost.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/http2/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/http2/connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/http2/probe.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/poolmanager.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/py.typed +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/response.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/__init__.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/connection.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/proxy.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/request.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/response.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/retry.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/ssl_.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/ssltransport.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/timeout.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/url.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/util.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake/connector/vendored/urllib3/util/wait.py +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/SOURCES.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/dependency_links.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/entry_points.txt +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/not-zip-safe +0 -0
- {snowflake_connector_python-4.0.0 → snowflake_connector_python-4.1.0}/src/snowflake_connector_python.egg-info/top_level.txt +0 -0
|
@@ -7,7 +7,16 @@ https://docs.snowflake.com/
|
|
|
7
7
|
Source code is also available at: https://github.com/snowflakedb/snowflake-connector-python
|
|
8
8
|
|
|
9
9
|
# Release Notes
|
|
10
|
-
- v4.1.0(
|
|
10
|
+
- v4.1.0(November 18,2025)
|
|
11
|
+
- Added the `SNOWFLAKE_AUTH_FORCE_SERVER` environment variable to force the use of the local-listening server when using the `externalbrowser` auth method.
|
|
12
|
+
- This allows headless environments (like Docker or Airflow) running locally to auth via a browser URL.
|
|
13
|
+
- Fix compilation error when building from sources with libc++.
|
|
14
|
+
- Pin lower versions of dependencies to oldest version without vulnerabilities.
|
|
15
|
+
- Added no_proxy parameter for proxy configuration without using environmental variables.
|
|
16
|
+
- Added OAUTH_AUTHORIZATION_CODE and OAUTH_CLIENT_CREDENTIALS to list of authenticators that don't require user to be set
|
|
17
|
+
- Added `oauth_socket_uri` connection parameter allowing to separate server and redirect URIs for local OAuth server.
|
|
18
|
+
- Made platform_detection logs silent and improved its timeout handling. Added support for ENV_VAR_DISABLE_PLATFORM_DETECTION environment variable.
|
|
19
|
+
- Fixed FIPS environments md5 hash issues with multipart upload on Azure.
|
|
11
20
|
|
|
12
21
|
- v4.0.0(October 09,2025)
|
|
13
22
|
- Added support for checking certificates revocation using revocation lists (CRLs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snowflake-connector-python
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: Snowflake Connector for Python
|
|
5
5
|
Home-page: https://www.snowflake.com/
|
|
6
6
|
Author: Snowflake, Inc
|
|
@@ -39,16 +39,16 @@ Description-Content-Type: text/markdown
|
|
|
39
39
|
License-File: LICENSE.txt
|
|
40
40
|
License-File: NOTICE
|
|
41
41
|
Requires-Dist: asn1crypto<2.0.0,>0.24.0
|
|
42
|
-
Requires-Dist: cryptography>=
|
|
43
|
-
Requires-Dist: pyOpenSSL<26.0.0,>=
|
|
44
|
-
Requires-Dist: pyjwt<3.0.0
|
|
42
|
+
Requires-Dist: cryptography>=44.0.1
|
|
43
|
+
Requires-Dist: pyOpenSSL<26.0.0,>=24.0.0
|
|
44
|
+
Requires-Dist: pyjwt<3.0.0,>=2.10.1
|
|
45
45
|
Requires-Dist: pytz
|
|
46
|
-
Requires-Dist: requests<3.0.0
|
|
46
|
+
Requires-Dist: requests<3.0.0,>=2.32.4
|
|
47
47
|
Requires-Dist: packaging
|
|
48
48
|
Requires-Dist: charset_normalizer<4,>=2
|
|
49
|
-
Requires-Dist: idna<4,>=
|
|
50
|
-
Requires-Dist: urllib3<2.0.0,>=1.
|
|
51
|
-
Requires-Dist: certifi>=
|
|
49
|
+
Requires-Dist: idna<4,>=3.7
|
|
50
|
+
Requires-Dist: urllib3<2.0.0,>=1.26.5; python_version < "3.10"
|
|
51
|
+
Requires-Dist: certifi>=2024.7.4
|
|
52
52
|
Requires-Dist: typing_extensions<5,>=4.3
|
|
53
53
|
Requires-Dist: filelock<4,>=3.5
|
|
54
54
|
Requires-Dist: sortedcontainers>=2.4.0
|
|
@@ -75,7 +75,7 @@ Requires-Dist: pytzdata; extra == "development"
|
|
|
75
75
|
Requires-Dist: responses; extra == "development"
|
|
76
76
|
Provides-Extra: pandas
|
|
77
77
|
Requires-Dist: pandas<3.0.0,>=2.1.2; extra == "pandas"
|
|
78
|
-
Requires-Dist: pyarrow; extra == "pandas"
|
|
78
|
+
Requires-Dist: pyarrow>=14.0.1; extra == "pandas"
|
|
79
79
|
Provides-Extra: secure-local-storage
|
|
80
80
|
Requires-Dist: keyring<26.0.0,>=23.1.0; extra == "secure-local-storage"
|
|
81
81
|
Dynamic: license-file
|
|
@@ -90,7 +90,16 @@ https://docs.snowflake.com/
|
|
|
90
90
|
Source code is also available at: https://github.com/snowflakedb/snowflake-connector-python
|
|
91
91
|
|
|
92
92
|
# Release Notes
|
|
93
|
-
- v4.1.0(
|
|
93
|
+
- v4.1.0(November 18,2025)
|
|
94
|
+
- Added the `SNOWFLAKE_AUTH_FORCE_SERVER` environment variable to force the use of the local-listening server when using the `externalbrowser` auth method.
|
|
95
|
+
- This allows headless environments (like Docker or Airflow) running locally to auth via a browser URL.
|
|
96
|
+
- Fix compilation error when building from sources with libc++.
|
|
97
|
+
- Pin lower versions of dependencies to oldest version without vulnerabilities.
|
|
98
|
+
- Added no_proxy parameter for proxy configuration without using environmental variables.
|
|
99
|
+
- Added OAUTH_AUTHORIZATION_CODE and OAUTH_CLIENT_CREDENTIALS to list of authenticators that don't require user to be set
|
|
100
|
+
- Added `oauth_socket_uri` connection parameter allowing to separate server and redirect URIs for local OAuth server.
|
|
101
|
+
- Made platform_detection logs silent and improved its timeout handling. Added support for ENV_VAR_DISABLE_PLATFORM_DETECTION environment variable.
|
|
102
|
+
- Fixed FIPS environments md5 hash issues with multipart upload on Azure.
|
|
94
103
|
|
|
95
104
|
- v4.0.0(October 09,2025)
|
|
96
105
|
- Added support for checking certificates revocation using revocation lists (CRLs)
|
|
@@ -44,16 +44,16 @@ python_requires = >=3.9
|
|
|
44
44
|
packages = find_namespace:
|
|
45
45
|
install_requires =
|
|
46
46
|
asn1crypto>0.24.0,<2.0.0
|
|
47
|
-
cryptography>=
|
|
48
|
-
pyOpenSSL>=
|
|
49
|
-
pyjwt
|
|
47
|
+
cryptography>=44.0.1
|
|
48
|
+
pyOpenSSL>=24.0.0,<26.0.0
|
|
49
|
+
pyjwt>=2.10.1,<3.0.0
|
|
50
50
|
pytz
|
|
51
|
-
requests
|
|
51
|
+
requests>=2.32.4,<3.0.0
|
|
52
52
|
packaging
|
|
53
53
|
charset_normalizer>=2,<4
|
|
54
|
-
idna>=
|
|
55
|
-
urllib3>=1.
|
|
56
|
-
certifi>=
|
|
54
|
+
idna>=3.7,<4
|
|
55
|
+
urllib3>=1.26.5,<2.0.0; python_version < '3.10'
|
|
56
|
+
certifi>=2024.7.4
|
|
57
57
|
typing_extensions>=4.3,<5
|
|
58
58
|
filelock>=3.5,<4
|
|
59
59
|
sortedcontainers>=2.4.0
|
|
@@ -95,7 +95,7 @@ development =
|
|
|
95
95
|
responses
|
|
96
96
|
pandas =
|
|
97
97
|
pandas>=2.1.2,<3.0.0
|
|
98
|
-
pyarrow
|
|
98
|
+
pyarrow>=14.0.1
|
|
99
99
|
secure-local-storage =
|
|
100
100
|
keyring>=23.1.0,<26.0.0
|
|
101
101
|
|
|
@@ -53,7 +53,9 @@ from ..network import (
|
|
|
53
53
|
ReauthenticationRequest,
|
|
54
54
|
)
|
|
55
55
|
from ..platform_detection import detect_platforms
|
|
56
|
-
from ..session_manager import
|
|
56
|
+
from ..session_manager import BaseHttpConfig, HttpConfig
|
|
57
|
+
from ..session_manager import SessionManager as SyncSessionManager
|
|
58
|
+
from ..session_manager import SessionManagerFactory
|
|
57
59
|
from ..sqlstate import SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED
|
|
58
60
|
from ..token_cache import TokenCache, TokenKey, TokenType
|
|
59
61
|
from ..version import VERSION
|
|
@@ -106,8 +108,17 @@ class Auth:
|
|
|
106
108
|
network_timeout: int | None = None,
|
|
107
109
|
socket_timeout: int | None = None,
|
|
108
110
|
platform_detection_timeout_seconds: float | None = None,
|
|
109
|
-
session_manager:
|
|
111
|
+
session_manager: SyncSessionManager | None = None,
|
|
112
|
+
http_config: BaseHttpConfig | None = None,
|
|
110
113
|
):
|
|
114
|
+
# Create sync SessionManager for platform detection if config is provided
|
|
115
|
+
# Platform detection runs in threads and uses sync SessionManager
|
|
116
|
+
if http_config is not None and session_manager is None:
|
|
117
|
+
# Extract base fields (automatically excludes subclass-specific fields)
|
|
118
|
+
# Note: It won't be possible to pass adapter_factory from outer async-code to this part of code
|
|
119
|
+
sync_config = HttpConfig(**http_config.to_base_dict())
|
|
120
|
+
session_manager = SessionManagerFactory.get_manager(config=sync_config)
|
|
121
|
+
|
|
111
122
|
return {
|
|
112
123
|
"data": {
|
|
113
124
|
"CLIENT_APP_ID": internal_application_name,
|
|
@@ -503,6 +514,16 @@ class Auth:
|
|
|
503
514
|
user: str,
|
|
504
515
|
session_parameters: dict[str, Any],
|
|
505
516
|
) -> None:
|
|
517
|
+
"""Attempt to load cached credentials to skip interactive authentication.
|
|
518
|
+
|
|
519
|
+
SSO (ID_TOKEN): If present, avoids opening browser for external authentication.
|
|
520
|
+
Controlled by client_store_temporary_credential parameter.
|
|
521
|
+
|
|
522
|
+
MFA (MFA_TOKEN): If present, skips MFA prompt on next connection.
|
|
523
|
+
Controlled by client_request_mfa_token parameter.
|
|
524
|
+
|
|
525
|
+
If cached tokens are expired/invalid, they're deleted and normal auth proceeds.
|
|
526
|
+
"""
|
|
506
527
|
if session_parameters.get(PARAMETER_CLIENT_STORE_TEMPORARY_CREDENTIAL, False):
|
|
507
528
|
self._rest.id_token = self._read_temporary_credential(
|
|
508
529
|
host,
|
|
@@ -538,6 +559,13 @@ class Auth:
|
|
|
538
559
|
session_parameters: dict[str, Any],
|
|
539
560
|
response: dict[str, Any],
|
|
540
561
|
) -> None:
|
|
562
|
+
"""Cache credentials received from successful authentication for future use.
|
|
563
|
+
|
|
564
|
+
Tokens are only cached if:
|
|
565
|
+
1. Server returned the token in response (server-side caching must be enabled)
|
|
566
|
+
2. Client has caching enabled via session parameters
|
|
567
|
+
3. User consented to caching (consent_cache_id_token for ID tokens)
|
|
568
|
+
"""
|
|
541
569
|
if (
|
|
542
570
|
self._rest._connection.auth_class.consent_cache_id_token
|
|
543
571
|
and session_parameters.get(
|
|
@@ -70,8 +70,10 @@ class AuthHttpServer:
|
|
|
70
70
|
self,
|
|
71
71
|
uri: str,
|
|
72
72
|
buf_size: int = 16384,
|
|
73
|
+
redirect_uri: str | None = None,
|
|
73
74
|
) -> None:
|
|
74
75
|
parsed_uri = urllib.parse.urlparse(uri)
|
|
76
|
+
parsed_redirect = urllib.parse.urlparse(redirect_uri) if redirect_uri else None
|
|
75
77
|
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
76
78
|
self.buf_size = buf_size
|
|
77
79
|
if os.getenv("SNOWFLAKE_AUTH_SOCKET_REUSE_PORT", "False").lower() == "true":
|
|
@@ -82,30 +84,34 @@ class AuthHttpServer:
|
|
|
82
84
|
else:
|
|
83
85
|
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
if parsed_redirect and self._is_local_uri(parsed_redirect):
|
|
88
|
+
server_port = parsed_redirect.port or 0
|
|
89
|
+
else:
|
|
90
|
+
server_port = parsed_uri.port or 0
|
|
91
|
+
|
|
86
92
|
for attempt in range(1, self.DEFAULT_MAX_ATTEMPTS + 1):
|
|
87
93
|
try:
|
|
88
94
|
self._socket.bind(
|
|
89
95
|
(
|
|
90
96
|
parsed_uri.hostname,
|
|
91
|
-
|
|
97
|
+
server_port,
|
|
92
98
|
)
|
|
93
99
|
)
|
|
94
100
|
break
|
|
95
101
|
except socket.gaierror as ex:
|
|
96
102
|
logger.error(
|
|
97
|
-
f"Failed to bind authorization callback server to port {
|
|
103
|
+
f"Failed to bind authorization callback server to port {server_port}: {ex}"
|
|
98
104
|
)
|
|
99
105
|
raise
|
|
100
106
|
except OSError as ex:
|
|
101
107
|
if attempt == self.DEFAULT_MAX_ATTEMPTS:
|
|
102
108
|
logger.error(
|
|
103
|
-
f"Failed to bind authorization callback server to port {
|
|
109
|
+
f"Failed to bind authorization callback server to port {server_port}: {ex}"
|
|
104
110
|
)
|
|
105
111
|
raise
|
|
106
112
|
logger.warning(
|
|
107
113
|
f"Attempt {attempt}/{self.DEFAULT_MAX_ATTEMPTS}. "
|
|
108
|
-
f"Failed to bind authorization callback server to port {
|
|
114
|
+
f"Failed to bind authorization callback server to port {server_port}: {ex}"
|
|
109
115
|
)
|
|
110
116
|
time.sleep(self.PORT_BIND_TIMEOUT / self.PORT_BIND_MAX_ATTEMPTS)
|
|
111
117
|
try:
|
|
@@ -114,16 +120,47 @@ class AuthHttpServer:
|
|
|
114
120
|
logger.error(f"Failed to start listening for auth callback: {ex}")
|
|
115
121
|
self.close()
|
|
116
122
|
raise
|
|
117
|
-
|
|
123
|
+
|
|
124
|
+
server_port = self._socket.getsockname()[1]
|
|
118
125
|
self._uri = urllib.parse.ParseResult(
|
|
119
126
|
scheme=parsed_uri.scheme,
|
|
120
|
-
netloc=parsed_uri.hostname + ":" + str(
|
|
127
|
+
netloc=parsed_uri.hostname + ":" + str(server_port),
|
|
121
128
|
path=parsed_uri.path,
|
|
122
129
|
params=parsed_uri.params,
|
|
123
130
|
query=parsed_uri.query,
|
|
124
131
|
fragment=parsed_uri.fragment,
|
|
125
132
|
)
|
|
126
133
|
|
|
134
|
+
if parsed_redirect:
|
|
135
|
+
if (
|
|
136
|
+
self._is_local_uri(parsed_redirect)
|
|
137
|
+
and server_port != parsed_redirect.port
|
|
138
|
+
):
|
|
139
|
+
logger.debug(
|
|
140
|
+
f"Updating redirect port {parsed_redirect.port} to match the server port {server_port}."
|
|
141
|
+
)
|
|
142
|
+
self._redirect_uri = urllib.parse.ParseResult(
|
|
143
|
+
scheme=parsed_redirect.scheme,
|
|
144
|
+
netloc=parsed_redirect.hostname + ":" + str(server_port),
|
|
145
|
+
path=parsed_redirect.path,
|
|
146
|
+
params=parsed_redirect.params,
|
|
147
|
+
query=parsed_redirect.query,
|
|
148
|
+
fragment=parsed_redirect.fragment,
|
|
149
|
+
)
|
|
150
|
+
else:
|
|
151
|
+
self._redirect_uri = parsed_redirect
|
|
152
|
+
else:
|
|
153
|
+
# For backwards compatibility
|
|
154
|
+
self._redirect_uri = self._uri
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def _is_local_uri(uri):
|
|
158
|
+
return uri.hostname in ("localhost", "127.0.0.1")
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def redirect_uri(self) -> str | None:
|
|
162
|
+
return self._redirect_uri.geturl()
|
|
163
|
+
|
|
127
164
|
@property
|
|
128
165
|
def url(self) -> str:
|
|
129
166
|
return self._uri.geturl()
|
|
@@ -35,6 +35,14 @@ logger = logging.getLogger(__name__)
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class _OAuthTokensMixin:
|
|
38
|
+
"""Manages OAuth token caching to avoid repeated browser authentication flows.
|
|
39
|
+
|
|
40
|
+
Access tokens: Short-lived (typically 10 minutes), cached to avoid immediate re-auth.
|
|
41
|
+
Refresh tokens: Long-lived (hours/days), used to obtain new access tokens silently.
|
|
42
|
+
|
|
43
|
+
Tokens are cached per (user, IDP host) to support multiple OAuth providers/accounts.
|
|
44
|
+
"""
|
|
45
|
+
|
|
38
46
|
def __init__(
|
|
39
47
|
self,
|
|
40
48
|
token_cache: TokenCache | None,
|
|
@@ -77,12 +85,18 @@ class _OAuthTokensMixin:
|
|
|
77
85
|
return self._token_cache.retrieve(key)
|
|
78
86
|
|
|
79
87
|
def _pop_cached_access_token(self) -> bool:
|
|
80
|
-
"""Retrieves OAuth access token from the token cache if enabled
|
|
88
|
+
"""Retrieves OAuth access token from the token cache if enabled, available and still valid.
|
|
89
|
+
|
|
90
|
+
Returns True if cached token found, allowing authentication to skip OAuth flow.
|
|
91
|
+
"""
|
|
81
92
|
self._access_token = self._pop_cached_token(self._get_access_token_cache_key())
|
|
82
93
|
return self._access_token is not None
|
|
83
94
|
|
|
84
95
|
def _pop_cached_refresh_token(self) -> bool:
|
|
85
|
-
"""Retrieves OAuth refresh token from the token cache if enabled
|
|
96
|
+
"""Retrieves OAuth refresh token from the token cache (if enabled) to silently obtain new access token.
|
|
97
|
+
|
|
98
|
+
Returns True if refresh token found, enabling automatic token renewal without user interaction.
|
|
99
|
+
"""
|
|
86
100
|
if self._refresh_token_enabled:
|
|
87
101
|
self._refresh_token = self._pop_cached_token(
|
|
88
102
|
self._get_refresh_token_cache_key()
|
|
@@ -65,6 +65,7 @@ class AuthByOauthCode(AuthByOAuthBase):
|
|
|
65
65
|
external_browser_timeout: int | None = None,
|
|
66
66
|
enable_single_use_refresh_tokens: bool = False,
|
|
67
67
|
connection: SnowflakeConnection | None = None,
|
|
68
|
+
uri: str | None = None,
|
|
68
69
|
**kwargs,
|
|
69
70
|
) -> None:
|
|
70
71
|
authentication_url, redirect_uri = self._validate_oauth_code_uris(
|
|
@@ -92,6 +93,7 @@ class AuthByOauthCode(AuthByOAuthBase):
|
|
|
92
93
|
self._origin: str | None = None
|
|
93
94
|
self._authentication_url = authentication_url
|
|
94
95
|
self._redirect_uri = redirect_uri
|
|
96
|
+
self._uri = uri
|
|
95
97
|
self._state = secrets.token_urlsafe(43)
|
|
96
98
|
logger.debug("chose oauth state: %s", "".join("*" for _ in self._state))
|
|
97
99
|
self._protocol = "http"
|
|
@@ -117,7 +119,10 @@ class AuthByOauthCode(AuthByOAuthBase):
|
|
|
117
119
|
) -> (str | None, str | None):
|
|
118
120
|
"""Web Browser based Authentication."""
|
|
119
121
|
logger.debug("authenticating with OAuth authorization code flow")
|
|
120
|
-
with AuthHttpServer(
|
|
122
|
+
with AuthHttpServer(
|
|
123
|
+
redirect_uri=self._redirect_uri,
|
|
124
|
+
uri=self._uri or self._redirect_uri, # for backward compatibility
|
|
125
|
+
) as callback_server:
|
|
121
126
|
code = self._do_authorization_request(callback_server, conn)
|
|
122
127
|
return self._do_token_request(code, callback_server, conn)
|
|
123
128
|
|
|
@@ -260,7 +265,7 @@ You can close this window now and go back where you started from.
|
|
|
260
265
|
connection: SnowflakeConnection,
|
|
261
266
|
) -> str | None:
|
|
262
267
|
authorization_request = self._construct_authorization_request(
|
|
263
|
-
callback_server.
|
|
268
|
+
callback_server.redirect_uri
|
|
264
269
|
)
|
|
265
270
|
logger.debug("step 1: going to open authorization URL")
|
|
266
271
|
print(
|
|
@@ -315,7 +320,7 @@ You can close this window now and go back where you started from.
|
|
|
315
320
|
fields = {
|
|
316
321
|
"grant_type": "authorization_code",
|
|
317
322
|
"code": code,
|
|
318
|
-
"redirect_uri": callback_server.
|
|
323
|
+
"redirect_uri": callback_server.redirect_uri,
|
|
319
324
|
}
|
|
320
325
|
if self._enable_single_use_refresh_tokens:
|
|
321
326
|
fields["enable_single_use_refresh_tokens"] = "true"
|
|
@@ -165,15 +165,26 @@ class AuthByWebBrowser(AuthByPlugin):
|
|
|
165
165
|
return
|
|
166
166
|
|
|
167
167
|
print(
|
|
168
|
-
"Initiating login request with your identity provider.
|
|
169
|
-
"browser window should have opened for you to complete the "
|
|
170
|
-
"login. If you can't see it, check existing browser windows, "
|
|
171
|
-
"or your OS settings. Press CTRL+C to abort and try again..."
|
|
168
|
+
"Initiating login request with your identity provider. Press CTRL+C to abort and try again..."
|
|
172
169
|
)
|
|
173
170
|
|
|
174
171
|
logger.debug("step 2: open a browser")
|
|
175
172
|
print(f"Going to open: {sso_url} to authenticate...")
|
|
176
|
-
|
|
173
|
+
browser_opened = self._webbrowser.open_new(sso_url)
|
|
174
|
+
if browser_opened:
|
|
175
|
+
print(
|
|
176
|
+
"A browser window should have opened for you to complete the "
|
|
177
|
+
"login. If you can't see it, check existing browser windows, "
|
|
178
|
+
"or your OS settings."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if (
|
|
182
|
+
browser_opened
|
|
183
|
+
or os.getenv("SNOWFLAKE_AUTH_FORCE_SERVER", "False").lower() == "true"
|
|
184
|
+
):
|
|
185
|
+
logger.debug("step 3: accept SAML token")
|
|
186
|
+
self._receive_saml_token(conn, socket_connection)
|
|
187
|
+
else:
|
|
177
188
|
print(
|
|
178
189
|
"We were unable to open a browser window for you, "
|
|
179
190
|
"please open the url above manually then paste the "
|
|
@@ -195,9 +206,6 @@ class AuthByWebBrowser(AuthByPlugin):
|
|
|
195
206
|
},
|
|
196
207
|
)
|
|
197
208
|
return
|
|
198
|
-
else:
|
|
199
|
-
logger.debug("step 3: accept SAML token")
|
|
200
|
-
self._receive_saml_token(conn, socket_connection)
|
|
201
209
|
finally:
|
|
202
210
|
socket_connection.close()
|
|
203
211
|
|
|
@@ -14,7 +14,7 @@ from .compat import quote
|
|
|
14
14
|
from .constants import FileHeader, ResultStatus
|
|
15
15
|
from .encryption_util import EncryptionMetadata
|
|
16
16
|
from .storage_client import SnowflakeStorageClient
|
|
17
|
-
from .util_text import
|
|
17
|
+
from .util_text import get_md5_for_integrity
|
|
18
18
|
from .vendored import requests
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -241,9 +241,9 @@ class SnowflakeAzureRestClient(SnowflakeStorageClient):
|
|
|
241
241
|
fd.close()
|
|
242
242
|
headers = {
|
|
243
243
|
"x-ms-blob-content-encoding": "utf-8",
|
|
244
|
-
"x-ms-blob-content-md5": base64.b64encode(
|
|
245
|
-
|
|
246
|
-
),
|
|
244
|
+
"x-ms-blob-content-md5": base64.b64encode(
|
|
245
|
+
get_md5_for_integrity(file_content)
|
|
246
|
+
).decode("utf-8"),
|
|
247
247
|
}
|
|
248
248
|
azure_metadata = self._prepare_file_metadata()
|
|
249
249
|
headers.update(azure_metadata)
|
|
@@ -88,6 +88,7 @@ from .constants import (
|
|
|
88
88
|
)
|
|
89
89
|
from .converter import SnowflakeConverter
|
|
90
90
|
from .crl import CRLConfig
|
|
91
|
+
from .crl_cache import CRLCacheFactory
|
|
91
92
|
from .cursor import LOG_MAX_QUERY_LENGTH, SnowflakeCursor, SnowflakeCursorBase
|
|
92
93
|
from .description import (
|
|
93
94
|
CLIENT_NAME,
|
|
@@ -129,7 +130,12 @@ from .network import (
|
|
|
129
130
|
ReauthenticationRequest,
|
|
130
131
|
SnowflakeRestful,
|
|
131
132
|
)
|
|
132
|
-
from .session_manager import
|
|
133
|
+
from .session_manager import (
|
|
134
|
+
HttpConfig,
|
|
135
|
+
ProxySupportAdapterFactory,
|
|
136
|
+
SessionManager,
|
|
137
|
+
SessionManagerFactory,
|
|
138
|
+
)
|
|
133
139
|
from .sqlstate import SQLSTATE_CONNECTION_NOT_EXISTS, SQLSTATE_FEATURE_NOT_SUPPORTED
|
|
134
140
|
from .telemetry import TelemetryClient, TelemetryData, TelemetryField
|
|
135
141
|
from .time_util import HeartBeatTimer, get_time_millis
|
|
@@ -199,6 +205,10 @@ DEFAULT_CONFIGURATION: dict[str, tuple[Any, type | tuple[type, ...]]] = {
|
|
|
199
205
|
"proxy_port": (None, (type(None), str)), # snowflake
|
|
200
206
|
"proxy_user": (None, (type(None), str)), # snowflake
|
|
201
207
|
"proxy_password": (None, (type(None), str)), # snowflake
|
|
208
|
+
"no_proxy": (
|
|
209
|
+
None,
|
|
210
|
+
(type(None), str, Iterable),
|
|
211
|
+
), # hosts/ips to bypass proxy (str or iterable)
|
|
202
212
|
"protocol": ("https", str), # snowflake
|
|
203
213
|
"warehouse": (None, (type(None), str)), # snowflake
|
|
204
214
|
"region": (None, (type(None), str)), # snowflake
|
|
@@ -271,8 +281,13 @@ DEFAULT_CONFIGURATION: dict[str, tuple[Any, type | tuple[type, ...]]] = {
|
|
|
271
281
|
"support_negative_year": (True, bool), # snowflake
|
|
272
282
|
"log_max_query_length": (LOG_MAX_QUERY_LENGTH, int), # snowflake
|
|
273
283
|
"disable_request_pooling": (False, bool), # snowflake
|
|
274
|
-
#
|
|
284
|
+
# Cache SSO ID tokens to avoid repeated browser popups. Must be enabled on the server-side.
|
|
285
|
+
# Storage: keyring (macOS/Windows), file (Linux). Auto-enabled on macOS/Windows.
|
|
286
|
+
# Sets session PARAMETER_CLIENT_STORE_TEMPORARY_CREDENTIAL as well
|
|
275
287
|
"client_store_temporary_credential": (False, bool),
|
|
288
|
+
# Cache MFA tokens to skip MFA prompts on reconnect. Must be enabled on the server-side.
|
|
289
|
+
# Storage: keyring (macOS/Windows), file (Linux). Auto-enabled on macOS/Windows.
|
|
290
|
+
# In driver, we extract this from session using PARAMETER_CLIENT_REQUEST_MFA_TOKEN.
|
|
276
291
|
"client_request_mfa_token": (False, bool),
|
|
277
292
|
"use_openssl_only": (
|
|
278
293
|
True,
|
|
@@ -375,6 +390,11 @@ DEFAULT_CONFIGURATION: dict[str, tuple[Any, type | tuple[type, ...]]] = {
|
|
|
375
390
|
# SNOW-1825621: OAUTH implementation
|
|
376
391
|
),
|
|
377
392
|
"oauth_redirect_uri": ("http://127.0.0.1", str),
|
|
393
|
+
"oauth_socket_uri": (
|
|
394
|
+
"http://127.0.0.1",
|
|
395
|
+
str,
|
|
396
|
+
# SNOW-2194055: Separate server and redirect URIs in AuthHttpServer
|
|
397
|
+
),
|
|
378
398
|
"oauth_scope": (
|
|
379
399
|
"",
|
|
380
400
|
str,
|
|
@@ -808,6 +828,10 @@ class SnowflakeConnection:
|
|
|
808
828
|
def proxy_password(self) -> str | None:
|
|
809
829
|
return self._proxy_password
|
|
810
830
|
|
|
831
|
+
@property
|
|
832
|
+
def no_proxy(self) -> str | Iterable | None:
|
|
833
|
+
return self._no_proxy
|
|
834
|
+
|
|
811
835
|
@property
|
|
812
836
|
def account(self) -> str:
|
|
813
837
|
return self._account
|
|
@@ -1069,6 +1093,15 @@ class SnowflakeConnection:
|
|
|
1069
1093
|
|
|
1070
1094
|
self._crl_config: CRLConfig = CRLConfig.from_connection(self)
|
|
1071
1095
|
|
|
1096
|
+
no_proxy_csv_str = (
|
|
1097
|
+
",".join(str(x) for x in self.no_proxy)
|
|
1098
|
+
if (
|
|
1099
|
+
self.no_proxy is not None
|
|
1100
|
+
and isinstance(self.no_proxy, Iterable)
|
|
1101
|
+
and not isinstance(self.no_proxy, (str, bytes))
|
|
1102
|
+
)
|
|
1103
|
+
else self.no_proxy
|
|
1104
|
+
)
|
|
1072
1105
|
self._http_config = HttpConfig(
|
|
1073
1106
|
adapter_factory=ProxySupportAdapterFactory(),
|
|
1074
1107
|
use_pooling=(not self.disable_request_pooling),
|
|
@@ -1076,8 +1109,9 @@ class SnowflakeConnection:
|
|
|
1076
1109
|
proxy_port=self.proxy_port,
|
|
1077
1110
|
proxy_user=self.proxy_user,
|
|
1078
1111
|
proxy_password=self.proxy_password,
|
|
1112
|
+
no_proxy=no_proxy_csv_str,
|
|
1079
1113
|
)
|
|
1080
|
-
self._session_manager =
|
|
1114
|
+
self._session_manager = SessionManagerFactory.get_manager(self._http_config)
|
|
1081
1115
|
|
|
1082
1116
|
if self.enable_connection_diag:
|
|
1083
1117
|
exceptions_dict = {}
|
|
@@ -1119,11 +1153,17 @@ class SnowflakeConnection:
|
|
|
1119
1153
|
else:
|
|
1120
1154
|
self.__open_connection()
|
|
1121
1155
|
|
|
1156
|
+
# Register the connection in the pool after successful connection
|
|
1157
|
+
_connections_registry.add_connection(self)
|
|
1158
|
+
|
|
1122
1159
|
def close(self, retry: bool = True) -> None:
|
|
1123
1160
|
"""Closes the connection."""
|
|
1124
1161
|
# unregister to dereference connection object as it's already closed after the execution
|
|
1125
1162
|
atexit.unregister(self._close_at_exit)
|
|
1126
1163
|
try:
|
|
1164
|
+
# Remove connection from the pool
|
|
1165
|
+
_connections_registry.remove_connection(self)
|
|
1166
|
+
|
|
1127
1167
|
if not self.rest:
|
|
1128
1168
|
logger.debug("Rest object has been destroyed, cannot close session")
|
|
1129
1169
|
return
|
|
@@ -1135,7 +1175,8 @@ class SnowflakeConnection:
|
|
|
1135
1175
|
|
|
1136
1176
|
# close telemetry first, since it needs rest to send remaining data
|
|
1137
1177
|
logger.debug("closed")
|
|
1138
|
-
|
|
1178
|
+
if self.telemetry_enabled:
|
|
1179
|
+
self._telemetry.close(retry=retry)
|
|
1139
1180
|
if (
|
|
1140
1181
|
self._all_async_queries_finished()
|
|
1141
1182
|
and not self._server_session_keep_alive
|
|
@@ -1368,9 +1409,11 @@ class SnowflakeConnection:
|
|
|
1368
1409
|
backoff_generator=self._backoff_generator,
|
|
1369
1410
|
)
|
|
1370
1411
|
elif self._authenticator == EXTERNAL_BROWSER_AUTHENTICATOR:
|
|
1412
|
+
# Enable SSO credential caching
|
|
1371
1413
|
self._session_parameters[
|
|
1372
1414
|
PARAMETER_CLIENT_STORE_TEMPORARY_CREDENTIAL
|
|
1373
1415
|
] = (self._client_store_temporary_credential if IS_LINUX else True)
|
|
1416
|
+
# Try to load cached ID token to avoid browser popup
|
|
1374
1417
|
auth.read_temporary_credentials(
|
|
1375
1418
|
self.host,
|
|
1376
1419
|
self.user,
|
|
@@ -1434,6 +1477,7 @@ class SnowflakeConnection:
|
|
|
1434
1477
|
host=self.host, port=self.port
|
|
1435
1478
|
),
|
|
1436
1479
|
redirect_uri=self._oauth_redirect_uri,
|
|
1480
|
+
uri=self._oauth_socket_uri,
|
|
1437
1481
|
scope=self._oauth_scope,
|
|
1438
1482
|
pkce_enabled=not self._oauth_disable_pkce,
|
|
1439
1483
|
token_cache=(
|
|
@@ -1461,9 +1505,11 @@ class SnowflakeConnection:
|
|
|
1461
1505
|
connection=self,
|
|
1462
1506
|
)
|
|
1463
1507
|
elif self._authenticator == USR_PWD_MFA_AUTHENTICATOR:
|
|
1508
|
+
# Enable MFA token caching
|
|
1464
1509
|
self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN] = (
|
|
1465
1510
|
self._client_request_mfa_token if IS_LINUX else True
|
|
1466
1511
|
)
|
|
1512
|
+
# Try to load cached MFA token to skip MFA prompt
|
|
1467
1513
|
if self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN]:
|
|
1468
1514
|
auth.read_temporary_credentials(
|
|
1469
1515
|
self.host,
|
|
@@ -1672,6 +1718,8 @@ class SnowflakeConnection:
|
|
|
1672
1718
|
WORKLOAD_IDENTITY_AUTHENTICATOR,
|
|
1673
1719
|
PROGRAMMATIC_ACCESS_TOKEN,
|
|
1674
1720
|
PAT_WITH_EXTERNAL_SESSION,
|
|
1721
|
+
OAUTH_AUTHORIZATION_CODE,
|
|
1722
|
+
OAUTH_CLIENT_CREDENTIALS,
|
|
1675
1723
|
}
|
|
1676
1724
|
|
|
1677
1725
|
if not (self._master_token and self._session_token):
|
|
@@ -2492,3 +2540,56 @@ class SnowflakeConnection:
|
|
|
2492
2540
|
return "jupyter_notebook"
|
|
2493
2541
|
if "snowbooks" in sys.modules:
|
|
2494
2542
|
return "snowflake_notebook"
|
|
2543
|
+
|
|
2544
|
+
|
|
2545
|
+
class _ConnectionsRegistry:
|
|
2546
|
+
"""Thread-safe registry for tracking opened SnowflakeConnection instances.
|
|
2547
|
+
|
|
2548
|
+
This class maintains a registry of active connections using weak references
|
|
2549
|
+
to avoid preventing garbage collection.
|
|
2550
|
+
"""
|
|
2551
|
+
|
|
2552
|
+
def __init__(self):
|
|
2553
|
+
"""Initialize the connections registry with an empty registry and a lock."""
|
|
2554
|
+
self._connections: weakref.WeakSet = weakref.WeakSet()
|
|
2555
|
+
self._lock = Lock()
|
|
2556
|
+
|
|
2557
|
+
def add_connection(self, connection: SnowflakeConnection) -> None:
|
|
2558
|
+
"""Add a connection to the registry.
|
|
2559
|
+
|
|
2560
|
+
Args:
|
|
2561
|
+
connection: The SnowflakeConnection instance to register.
|
|
2562
|
+
"""
|
|
2563
|
+
with self._lock:
|
|
2564
|
+
self._connections.add(connection)
|
|
2565
|
+
logger.debug(
|
|
2566
|
+
f"Connection {id(connection)} added to pool. Total connections: {len(self._connections)}"
|
|
2567
|
+
)
|
|
2568
|
+
|
|
2569
|
+
def remove_connection(self, connection: SnowflakeConnection) -> None:
|
|
2570
|
+
"""Remove a connection from the registry.
|
|
2571
|
+
|
|
2572
|
+
Args:
|
|
2573
|
+
connection: The SnowflakeConnection instance to unregister.
|
|
2574
|
+
"""
|
|
2575
|
+
with self._lock:
|
|
2576
|
+
self._connections.discard(connection)
|
|
2577
|
+
logger.debug(
|
|
2578
|
+
f"Connection {id(connection)} removed from registry. Total connections: {len(self._connections)}"
|
|
2579
|
+
)
|
|
2580
|
+
|
|
2581
|
+
if len(self._connections) == 0:
|
|
2582
|
+
self._last_connection_handler()
|
|
2583
|
+
|
|
2584
|
+
def _last_connection_handler(self):
|
|
2585
|
+
# If no connections left then stop CRL background task
|
|
2586
|
+
# to avoid script dangling
|
|
2587
|
+
CRLCacheFactory.stop_periodic_cleanup()
|
|
2588
|
+
|
|
2589
|
+
def get_connection_count(self) -> int:
|
|
2590
|
+
with self._lock:
|
|
2591
|
+
return len(self._connections)
|
|
2592
|
+
|
|
2593
|
+
|
|
2594
|
+
# Global instance of the connections pool
|
|
2595
|
+
_connections_registry = _ConnectionsRegistry()
|
|
@@ -19,7 +19,7 @@ import OpenSSL
|
|
|
19
19
|
|
|
20
20
|
from .compat import IS_WINDOWS, urlparse
|
|
21
21
|
from .cursor import SnowflakeCursor
|
|
22
|
-
from .session_manager import SessionManager
|
|
22
|
+
from .session_manager import SessionManager, SessionManagerFactory
|
|
23
23
|
from .url_util import extract_top_level_domain_from_hostname
|
|
24
24
|
from .vendored import urllib3
|
|
25
25
|
|
|
@@ -197,7 +197,7 @@ class ConnectionDiagnostic:
|
|
|
197
197
|
self._session_manager = (
|
|
198
198
|
session_manager.clone(use_pooling=False)
|
|
199
199
|
if session_manager
|
|
200
|
-
else
|
|
200
|
+
else SessionManagerFactory.get_manager(use_pooling=False)
|
|
201
201
|
)
|
|
202
202
|
|
|
203
203
|
def __parse_proxy(self, proxy_url: str) -> tuple[str, str, str, str]:
|
|
@@ -441,7 +441,10 @@ DAY_IN_SECONDS = 60 * 60 * 24
|
|
|
441
441
|
# TODO: all env variables definitions should be here
|
|
442
442
|
ENV_VAR_PARTNER = "SF_PARTNER"
|
|
443
443
|
ENV_VAR_TEST_MODE = "SNOWFLAKE_TEST_MODE"
|
|
444
|
+
ENV_VAR_DISABLE_PLATFORM_DETECTION = "SNOWFLAKE_DISABLE_PLATFORM_DETECTION"
|
|
444
445
|
|
|
446
|
+
# Boolean positive values (lowercased) for environment variable checks
|
|
447
|
+
ENV_VAR_BOOL_POSITIVE_VALUES_LOWERCASED = ["true"]
|
|
445
448
|
|
|
446
449
|
_DOMAIN_NAME_MAP = {_DEFAULT_HOSTNAME_TLD: "GLOBAL", _CHINA_HOSTNAME_TLD: "CHINA"}
|
|
447
450
|
|