From cae519f2af2044e7bef54014f452df42dbad3daf Mon Sep 17 00:00:00 2001 From: Filip Pawlowski Date: Sat, 15 Aug 2026 11:39:02 +0000 Subject: [PATCH 1/2] SNOW-2912540: remove _pandas_importer(), source pandas/installed_pandas from connector _pandas_importer() predates this whole effort and duplicated resolution the connector already does correctly on both driver generations -- including the "relative imports without dots" DataFrame workaround, now folded into UD's own _common.extras.pandas (confirmed on the not-yet-merged UD PR #1151/#1152; v4's options.py already had it). Add pandas/installed_pandas to the existing IS_V5_DRIVER-gated import block and delete the local resolution entirely. Verified the workaround isn't needed on Snowpark's side by running the exact invocation style its comment called out (pytest with tests/unit/ as cwd) -- no failure, consistent with both driver generations now handling it internally. --- src/snowflake/snowpark/_internal/utils.py | 20 ++++---------------- tests/unit/test_internal_utils.py | 12 ------------ 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/snowflake/snowpark/_internal/utils.py b/src/snowflake/snowpark/_internal/utils.py index b61330783e..5578477ab6 100644 --- a/src/snowflake/snowpark/_internal/utils.py +++ b/src/snowflake/snowpark/_internal/utils.py @@ -63,7 +63,9 @@ from snowflake.connector._common.extras import ( MissingOptionalDependency, ModuleLikeObject, + pandas, pyarrow, + installed_pandas, installed_pyarrow, ) else: @@ -71,7 +73,9 @@ MissingOptionalDependency, MissingPandas, ModuleLikeObject, + pandas, pyarrow, + installed_pandas, ) # connector.options (v4) never exported installed_pyarrow as its own name. @@ -269,22 +273,6 @@ def _missing_pandas() -> MissingOptionalDependency: SUPPORTED_TABLE_TYPES = ["temp", "temporary", "transient"] -def _pandas_importer(): # noqa: E302 - """Helper function to lazily import pandas and return MissingPandas if not installed.""" - result = _missing_pandas() - try: - result = importlib.import_module("pandas") - # since we enable relative imports without dots this import gives us an issues when ran from test directory - from pandas import DataFrame # NOQA - except ImportError: # pragma: no cover - pass # pragma: no cover - return result - - -pandas = _pandas_importer() -installed_pandas = not isinstance(pandas, MissingOptionalDependency) - - class TempObjectType(Enum): TABLE = "TABLE" VIEW = "VIEW" diff --git a/tests/unit/test_internal_utils.py b/tests/unit/test_internal_utils.py index f09cfc63d3..e3e6882dc5 100644 --- a/tests/unit/test_internal_utils.py +++ b/tests/unit/test_internal_utils.py @@ -4,11 +4,9 @@ import concurrent.futures import random import pytest -from snowflake.connector.options import MissingPandas from snowflake.snowpark._internal import utils from snowflake.snowpark._internal.utils import ( - _pandas_importer, generate_random_alphanumeric, split_snowflake_identifier_with_dot, ) @@ -148,16 +146,6 @@ def test_normalize_path_escapes_backslash_and_quote(raw_path, is_local): ), f"decoded={decoded!r} does not end with {expected_tail!r}" -def test__pandas_importer(): - imported_pandas = _pandas_importer() - try: - import pandas - - assert imported_pandas == pandas - except ImportError: - assert isinstance(imported_pandas, MissingPandas) - - def test_generate_random_alphanumeric(): random.seed(42) random_string1 = generate_random_alphanumeric() From 35c5e06138dd75efe2e6f114eec1acac58067d77 Mon Sep 17 00:00:00 2001 From: Filip Pawlowski Date: Sat, 15 Aug 2026 11:41:08 +0000 Subject: [PATCH 2/2] SNOW-2912540: dedup mock/_options.py's numpy handling against _common.extras mock/_options.py's MissingNumpy/numpy try-except was functionally identical to _common/extras.py's own numpy resolution (confirmed: pure duplicate, no fix to merge, per UD PR #1152's investigation). Import numpy from _common.extras on v5; v4 keeps its own MissingNumpy class since v4's options.py has no numpy handling to delegate to. Does not touch the pandas try/except in this file -- Local Testing deliberately never resolves pyarrow, unlike every other pandas-resolution path in this codebase (commit #1628). --- src/snowflake/snowpark/mock/_options.py | 29 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/snowflake/snowpark/mock/_options.py b/src/snowflake/snowpark/mock/_options.py index 7d1f088433..37d71e3d4f 100644 --- a/src/snowflake/snowpark/mock/_options.py +++ b/src/snowflake/snowpark/mock/_options.py @@ -4,7 +4,11 @@ import importlib -from snowflake.snowpark._internal.utils import MissingOptionalDependency, _missing_pandas +from snowflake.snowpark._internal.utils import ( + IS_V5_DRIVER, + MissingOptionalDependency, + _missing_pandas, +) try: import pandas @@ -15,15 +19,20 @@ installed_pandas = False -class MissingNumpy(MissingOptionalDependency): - """The class is specifically for numpy optional dependency.""" +if IS_V5_DRIVER: + from snowflake.connector._common.extras import numpy - _dep_name = "numpy" + installed_numpy = not isinstance(numpy, MissingOptionalDependency) +else: + class MissingNumpy(MissingOptionalDependency): + """The class is specifically for numpy optional dependency.""" -try: - numpy = importlib.import_module("numpy") - installed_numpy = True -except ImportError: - numpy = MissingNumpy() - installed_numpy = False + _dep_name = "numpy" + + try: + numpy = importlib.import_module("numpy") + installed_numpy = True + except ImportError: + numpy = MissingNumpy() + installed_numpy = False