Skip to content

Commit 94fd0a1

Browse files
Merge branch 'main' into npeshkov/separate_redirect_and_socket
2 parents 46c7fec + d89ebee commit 94fd0a1

34 files changed

+790
-227
lines changed
Binary file not shown.

DESCRIPTION.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ https://docs.snowflake.com/
77
Source code is also available at: https://github.com/snowflakedb/snowflake-connector-python
88

99
# Release Notes
10+
- v3.16.1(TBD)
11+
- Added in-band OCSP exception telemetry.
12+
- Added `APPLICATION_PATH` within `CLIENT_ENVIRONMENT` to distinguish between multiple scripts using the PythonConnector in the same environment.
13+
- Disabled token caching for OAuth Client Credentials authentication
14+
- Added in-band HTTP exception telemetry.
15+
- Fixed a bug where timezoned timestamps fetched as pandas.DataFrame or pyarrow.Table would overflow for the sake of unnecessary precision. In the case where an overflow cannot be prevented a clear error will be raised now.
16+
- Fix OAuth authenticator values.
17+
1018
- v3.16.0(July 04,2025)
1119
- Bumped numpy dependency from <2.1.0 to <=2.2.4.
1220
- Added Windows support for Python 3.13.

ci/test_authentication.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ docker run \
2323
-v $(cd $THIS_DIR/.. && pwd):/mnt/host \
2424
-v $WORKSPACE:/mnt/workspace \
2525
--rm \
26-
nexus.int.snowflakecomputing.com:8086/docker/snowdrivers-test-external-browser-python:1 \
26+
nexus.int.snowflakecomputing.com:8086/docker/snowdrivers-test-external-browser-python:2 \
2727
"/mnt/host/ci/container/test_authentication.sh"

src/snowflake/connector/_utils.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import string
44
from enum import Enum
5+
from inspect import stack
56
from random import choice
67
from threading import Timer
78
from uuid import UUID
@@ -32,6 +33,15 @@ class TempObjectType(Enum):
3233

3334
REQUEST_ID_STATEMENT_PARAM_NAME = "requestId"
3435

36+
# Default server side cap on Degree of Parallelism for file transfer
37+
# This default value is set to 2^30 (~ 10^9), such that it will not
38+
# throttle regular sessions.
39+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER = 1 << 30
40+
# Variable name of server DoP cap for file transfer
41+
_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER = (
42+
"snowflake_server_dop_cap_for_file_transfer"
43+
)
44+
3545

3646
def generate_random_alphanumeric(length: int = 10) -> str:
3747
return "".join(choice(ALPHANUMERIC) for _ in range(length))
@@ -60,6 +70,15 @@ def is_uuid4(str_or_uuid: str | UUID) -> bool:
6070
return uuid_str == str_or_uuid
6171

6272

73+
def _snowflake_max_parallelism_for_file_transfer(connection):
74+
"""Returns the server side cap on max parallelism for file transfer for the given connection."""
75+
return getattr(
76+
connection,
77+
f"_{_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER}",
78+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER,
79+
)
80+
81+
6382
class _TrackedQueryCancellationTimer(Timer):
6483
def __init__(self, interval, function, args=None, kwargs=None):
6584
super().__init__(interval, function, args, kwargs)
@@ -68,3 +87,12 @@ def __init__(self, interval, function, args=None, kwargs=None):
6887
def run(self):
6988
super().run()
7089
self.executed = True
90+
91+
92+
def get_application_path() -> str:
93+
"""Get the path of the application script using the connector."""
94+
try:
95+
outermost_frame = stack()[-1]
96+
return outermost_frame.filename
97+
except Exception:
98+
return "unknown"

src/snowflake/connector/auth/_auth.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
load_pem_private_key,
1818
)
1919

20+
from .._utils import get_application_path
2021
from ..compat import urlencode
2122
from ..constants import (
2223
DAY_IN_SECONDS,
@@ -110,6 +111,7 @@ def base_auth_data(
110111
"LOGIN_NAME": user,
111112
"CLIENT_ENVIRONMENT": {
112113
"APPLICATION": application,
114+
"APPLICATION_PATH": get_application_path(),
113115
"OS": OPERATING_SYSTEM,
114116
"OS_VERSION": PLATFORM,
115117
"PYTHON_VERSION": PYTHON_VERSION,

src/snowflake/connector/auth/by_plugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class AuthType(Enum):
5050
ID_TOKEN = "ID_TOKEN"
5151
USR_PWD_MFA = "USERNAME_PASSWORD_MFA"
5252
OKTA = "OKTA"
53-
PAT = "PROGRAMMATIC_ACCESS_TOKEN'"
53+
PAT = "PROGRAMMATIC_ACCESS_TOKEN"
5454
NO_AUTH = "NO_AUTH"
5555
WORKLOAD_IDENTITY = "WORKLOAD_IDENTITY"
5656
PAT_WITH_EXTERNAL_SESSION = "PAT_WITH_EXTERNAL_SESSION"

src/snowflake/connector/auth/oauth_credentials.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from typing import TYPE_CHECKING, Any
99

1010
from ..constants import OAUTH_TYPE_CLIENT_CREDENTIALS
11-
from ..token_cache import TokenCache
1211
from ._oauth_base import AuthByOAuthBase
1312

1413
if TYPE_CHECKING:
@@ -27,8 +26,6 @@ def __init__(
2726
client_secret: str,
2827
token_request_url: str,
2928
scope: str,
30-
token_cache: TokenCache | None = None,
31-
refresh_token_enabled: bool = False,
3229
connection: SnowflakeConnection | None = None,
3330
**kwargs,
3431
) -> None:
@@ -38,8 +35,8 @@ def __init__(
3835
client_secret=client_secret,
3936
token_request_url=token_request_url,
4037
scope=scope,
41-
token_cache=token_cache,
42-
refresh_token_enabled=refresh_token_enabled,
38+
token_cache=None,
39+
refresh_token_enabled=False,
4340
**kwargs,
4441
)
4542
self._application = application

src/snowflake/connector/auth/pat.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def __init__(self, pat_token: str, **kwargs) -> None:
1313
super().__init__(**kwargs)
1414
self._pat_token: str | None = pat_token
1515

16+
@property
1617
def type_(self) -> AuthType:
1718
return AuthType.PAT
1819

src/snowflake/connector/connection.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929

3030
from . import errors, proxy
3131
from ._query_context_cache import QueryContextCache
32+
from ._utils import (
33+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER,
34+
_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER,
35+
)
3236
from .auth import (
3337
FIRST_PARTY_AUTHENTICATORS,
3438
Auth,
@@ -369,6 +373,14 @@ def _get_private_bytes_from_file(
369373
str,
370374
# SNOW-2096721: External (Spark) session ID
371375
),
376+
"unsafe_file_write": (
377+
False,
378+
bool,
379+
), # SNOW-1944208: add unsafe write flag
380+
_VARIABLE_NAME_SERVER_DOP_CAP_FOR_FILE_TRANSFER: (
381+
_DEFAULT_VALUE_SERVER_DOP_CAP_FOR_FILE_TRANSFER, # default value
382+
int, # type
383+
), # snowflake internal
372384
}
373385

374386
APPLICATION_RE = re.compile(r"[\w\d_]+")
@@ -1252,12 +1264,6 @@ def __open_connection(self):
12521264
host=self.host, port=self.port
12531265
),
12541266
scope=self._oauth_scope,
1255-
token_cache=(
1256-
auth.get_token_cache()
1257-
if self._client_store_temporary_credential
1258-
else None
1259-
),
1260-
refresh_token_enabled=self._oauth_enable_refresh_tokens,
12611267
connection=self,
12621268
)
12631269
elif self._authenticator == USR_PWD_MFA_AUTHENTICATOR:
@@ -1402,11 +1408,6 @@ def __config(self, **kwargs):
14021408
if "host" not in kwargs:
14031409
self._host = construct_hostname(kwargs.get("region"), self._account)
14041410

1405-
if "unsafe_file_write" in kwargs:
1406-
self._unsafe_file_write = kwargs["unsafe_file_write"]
1407-
else:
1408-
self._unsafe_file_write = False
1409-
14101411
logger.info(
14111412
f"Connecting to {_DOMAIN_NAME_MAP.get(extract_top_level_domain_from_hostname(self._host), 'GLOBAL')} Snowflake domain"
14121413
)

src/snowflake/connector/constants.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
_TOP_LEVEL_DOMAIN_REGEX = r"\.[a-zA-Z]{1,63}$"
3838
_SNOWFLAKE_HOST_SUFFIX_REGEX = r"snowflakecomputing(\.[a-zA-Z]{1,63}){1,2}$"
3939

40+
_PARAM_USE_SCOPED_TEMP_FOR_PANDAS_TOOLS = "ENABLE_FIX_1375538"
41+
4042

4143
class FieldType(NamedTuple):
4244
name: str
@@ -438,5 +440,5 @@ class IterUnit(Enum):
438440
)
439441

440442
_OAUTH_DEFAULT_SCOPE = "session:role:{role}"
441-
OAUTH_TYPE_AUTHORIZATION_CODE = "authorization_code"
442-
OAUTH_TYPE_CLIENT_CREDENTIALS = "client_credentials"
443+
OAUTH_TYPE_AUTHORIZATION_CODE = "oauth_authorization_code"
444+
OAUTH_TYPE_CLIENT_CREDENTIALS = "oauth_client_credentials"

0 commit comments

Comments
 (0)