Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
13 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from snowflake.connector import ProgrammingError
from snowflake.connector.cursor import SnowflakeCursor
from snowflake.connector.options import pyarrow
from snowflake.snowpark._internal.options import pyarrow
from snowflake.snowpark._internal.analyzer.binary_plan_node import (
AsOf,
Except,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from snowflake.snowpark._internal.data_source.drivers.base_driver import BaseDriver
from snowflake.snowpark.exceptions import SnowparkDataframeReaderException
from snowflake.snowpark.types import StructType
from snowflake.connector.options import pandas as pd
from snowflake.snowpark._internal.options import pandas as pd
import logging

logger = logging.getLogger(__name__)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from enum import Enum
import datetime
from typing import Dict, List, Callable, Any, Optional, TYPE_CHECKING
from snowflake.connector.options import pandas as pd
from snowflake.snowpark._internal.options import pandas as pd

from snowflake.snowpark._internal.analyzer.analyzer_utils import unquote_if_quoted
from snowflake.snowpark._internal.data_source.datasource_typing import (
Expand Down
5 changes: 4 additions & 1 deletion src/snowflake/snowpark/_internal/event_table_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
from abc import ABC
from logging import getLogger
from typing import Dict, Optional, Tuple
from snowflake.connector.options import MissingOptionalDependency, ModuleLikeObject
import snowflake.snowpark
import requests

from snowflake.snowpark._internal.options import (
MissingOptionalDependency,
ModuleLikeObject,
)
from snowflake.snowpark._internal.utils import parse_table_name

_logger = getLogger(__name__)
Expand Down
38 changes: 38 additions & 0 deletions src/snowflake/snowpark/_internal/options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
#
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
#

from snowflake.connector.version import VERSION as connector_version

IS_V5_DRIVER: bool = connector_version[0] >= 5

if IS_V5_DRIVER:
from snowflake.connector._common.extras import pandas # noqa: F401
from snowflake.connector._common.extras import ModuleLikeObject # noqa: F401
from snowflake.connector._common.extras import installed_pandas # noqa: F401
from snowflake.connector._common.extras import (
MissingOptionalDependency,
pyarrow,
installed_pyarrow,
)
else:
from snowflake.connector.options import pandas # noqa: F401
from snowflake.connector.options import ModuleLikeObject # noqa: F401
from snowflake.connector.options import installed_pandas # noqa: F401
from snowflake.connector.options import (
MissingOptionalDependency,
MissingPandas,
pyarrow,
)

# connector.options (v4) never exported installed_pyarrow as its own name.
installed_pyarrow: bool = not isinstance(pyarrow, MissingOptionalDependency)


def _missing_pandas() -> MissingOptionalDependency:
# v4 has no __init__ override (no-arg-subclass only); v5 deleted
# MissingPandas in favor of the positional-arg form.
if IS_V5_DRIVER:
return MissingOptionalDependency("pandas")
return MissingPandas()
9 changes: 7 additions & 2 deletions src/snowflake/snowpark/_internal/server_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
from snowflake.connector.constants import FIELD_ID_TO_NAME
from snowflake.connector.cursor import ResultMetadata, SnowflakeCursor
from snowflake.connector.errors import Error, NotSupportedError, ProgrammingError
from snowflake.connector.network import ReauthenticationRequest
from snowflake.connector.options import pandas
from snowflake.snowpark._internal.options import pandas
from snowflake.snowpark._internal.analyzer.analyzer_utils import (
quote_name_without_upper_casing,
)
Expand All @@ -54,6 +53,7 @@
get_plan_telemetry_metrics,
)
from snowflake.snowpark._internal.utils import (
IS_V5_DRIVER,
create_rlock,
create_thread_local,
escape_quotes,
Expand All @@ -69,6 +69,11 @@
result_set_to_rows,
unwrap_stage_location_single_quote,
)

if IS_V5_DRIVER:
from snowflake.connector.errors import ReauthenticationRequest
else:
from snowflake.connector.network import ReauthenticationRequest
from snowflake.snowpark import context
from snowflake.snowpark.async_job import AsyncJob, _AsyncResultType
from snowflake.snowpark.query_history import QueryListener, QueryRecord
Expand Down
19 changes: 14 additions & 5 deletions src/snowflake/snowpark/_internal/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@
from typing import Any, Dict, List, Optional

from snowflake.connector import SnowflakeConnection
from snowflake.connector.telemetry import (
TelemetryClient as PCTelemetryClient,
TelemetryData as PCTelemetryData,
TelemetryField as PCTelemetryField,
)
from snowflake.connector.time_util import get_time_millis
from snowflake.snowpark._internal.analyzer.query_plan_analysis_utils import (
PlanState,
Expand All @@ -30,6 +25,7 @@
DescribeQueryTelemetryField,
)
from snowflake.snowpark._internal.utils import (
IS_V5_DRIVER,
get_application_name,
get_os_name,
get_python_version,
Expand All @@ -39,6 +35,19 @@
generate_random_alphanumeric,
)

if IS_V5_DRIVER:
from snowflake.connector._common.telemetry import (
TelemetryClient as PCTelemetryClient,
TelemetryData as PCTelemetryData,
TelemetryField as PCTelemetryField,
)
else:
from snowflake.connector.telemetry import (
TelemetryClient as PCTelemetryClient,
TelemetryData as PCTelemetryData,
TelemetryField as PCTelemetryField,
)

try:
import psutil

Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/_internal/type_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import snowflake.snowpark.types # type: ignore
from snowflake.connector.constants import FIELD_ID_TO_NAME
from snowflake.connector.cursor import ResultMetadata
from snowflake.connector.options import installed_pandas, pandas
from snowflake.snowpark._internal.options import installed_pandas, pandas
from snowflake.snowpark._internal.utils import quote_name
from snowflake.snowpark.row import Row
from snowflake.snowpark.types import (
Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/_internal/udf_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from packaging.requirements import Requirement

import snowflake.snowpark
from snowflake.connector.options import installed_pandas, pandas
from snowflake.snowpark._internal.options import installed_pandas, pandas
from snowflake.snowpark._internal import code_generation, type_utils
from snowflake.snowpark._internal.analyzer.datatype_mapper import to_sql, to_sql_no_cast
from snowflake.snowpark._internal.telemetry import TelemetryField
Expand Down
28 changes: 9 additions & 19 deletions src/snowflake/snowpark/_internal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,20 @@
from snowflake.connector.constants import FIELD_ID_TO_NAME
from snowflake.connector.cursor import ResultMetadata, SnowflakeCursor
from snowflake.connector.description import OPERATING_SYSTEM, PLATFORM
from snowflake.connector.options import MissingOptionalDependency, ModuleLikeObject
from snowflake.connector.version import VERSION as connector_version
from snowflake.snowpark._internal.error_message import SnowparkClientExceptionMessages
from snowflake.snowpark.row import Row
from snowflake.snowpark.version import VERSION as snowpark_version

IS_V5_DRIVER: bool = connector_version[0] >= 5

from snowflake.snowpark._internal.options import ( # noqa: E402
MissingOptionalDependency,
ModuleLikeObject,
installed_pandas,
)


if TYPE_CHECKING:
from snowflake.snowpark._internal.analyzer.snowflake_plan import (
SnowflakePlan,
Expand Down Expand Up @@ -240,24 +248,6 @@

SUPPORTED_TABLE_TYPES = ["temp", "temporary", "transient"]

# TODO: merge fixed pandas importer changes to connector.
def _pandas_importer(): # noqa: E302
"""Helper function to lazily import pandas and return MissingPandas if not installed."""
from snowflake.connector.options import MissingPandas

pandas = MissingPandas()
try:
pandas = 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 pandas


pandas = _pandas_importer()
installed_pandas = not isinstance(pandas, MissingOptionalDependency)


class TempObjectType(Enum):
TABLE = "TABLE"
Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/async_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import snowflake.snowpark
from snowflake.connector.errors import DatabaseError
from snowflake.connector.options import pandas
from snowflake.snowpark._internal.options import pandas
from snowflake.snowpark._internal.analyzer.analyzer_utils import result_scan_statement
from snowflake.snowpark._internal.analyzer.snowflake_plan import Query
from snowflake.snowpark._internal.utils import (
Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import snowflake.snowpark
import snowflake.snowpark.context as context
import snowflake.snowpark._internal.proto.generated.ast_pb2 as proto
from snowflake.connector.options import installed_pandas, pandas, pyarrow
from snowflake.snowpark._internal.options import installed_pandas, pandas, pyarrow

from snowflake.snowpark._internal.analyzer.binary_plan_node import (
AsOf,
Expand Down
31 changes: 20 additions & 11 deletions src/snowflake/snowpark/mock/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,35 @@

import importlib

from snowflake.connector.options import MissingOptionalDependency, MissingPandas
from snowflake.snowpark._internal.options import (
MissingOptionalDependency,
_missing_pandas,
)
from snowflake.snowpark._internal.utils import IS_V5_DRIVER

try:
import pandas

installed_pandas = True
except ImportError:
pandas = MissingPandas()
pandas = _missing_pandas()
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
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/relational_grouped_dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from snowflake.snowpark._internal.error_message import SnowparkClientExceptionMessages
import snowflake.snowpark._internal.proto.generated.ast_pb2 as proto
import snowflake.snowpark.context as context
from snowflake.connector.options import pandas
from snowflake.snowpark._internal.options import pandas
from snowflake.snowpark._internal.analyzer.analyzer_utils import unquote_if_quoted
from snowflake.snowpark import functions
from snowflake.snowpark._internal.analyzer.expression import (
Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import snowflake.snowpark._internal.proto.generated.ast_pb2 as proto
import snowflake.snowpark.context as context
from snowflake.connector import ProgrammingError, SnowflakeConnection
from snowflake.connector.options import installed_pandas, pandas, pyarrow
from snowflake.snowpark._internal.options import installed_pandas, pandas, pyarrow
from snowflake.connector.pandas_tools import write_pandas

from snowflake.snowpark import UDFProfiler
Expand Down
7 changes: 2 additions & 5 deletions src/snowflake/snowpark/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
import snowflake.snowpark._internal.proto.generated.ast_pb2 as proto

# Use correct version from here:
from snowflake.snowpark._internal.utils import (
installed_pandas,
pandas,
quote_name,
)
from snowflake.snowpark._internal.options import installed_pandas, pandas
from snowflake.snowpark._internal.utils import quote_name

# TODO: connector installed_pandas is broken. If pyarrow is not installed, but pandas is this function returns the wrong answer.
# The core issue is that in the connector detection of both pandas/arrow are mixed, which is wrong.
Expand Down
2 changes: 1 addition & 1 deletion tests/integ/scala/test_datatype_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from unittest import mock

import snowflake.snowpark.context as context
from snowflake.connector.options import installed_pandas
from snowflake.snowpark._internal.options import installed_pandas
from snowflake.snowpark import Row
from snowflake.snowpark.dataframe import DataFrame
from snowflake.snowpark.exceptions import SnowparkSQLException
Expand Down
2 changes: 1 addition & 1 deletion tests/integ/scala/test_update_delete_merge_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import pytest

from snowflake.connector.options import installed_pandas
from snowflake.snowpark._internal.options import installed_pandas
from snowflake.snowpark import (
DeleteResult,
MergeResult,
Expand Down
2 changes: 1 addition & 1 deletion tests/integ/test_cte.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import pytest

from snowflake.connector.errors import ProgrammingError
from snowflake.connector.options import installed_pandas
from snowflake.snowpark._internal.options import installed_pandas
from snowflake.snowpark import Window
from snowflake.snowpark._internal.analyzer import analyzer
from snowflake.snowpark._internal.analyzer.snowflake_plan import PlanQueryType, Query
Expand Down
2 changes: 1 addition & 1 deletion tests/integ/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
year,
)
import functools
from snowflake.connector.options import installed_pandas
from snowflake.snowpark._internal.options import installed_pandas
from snowflake.snowpark.functions import udf, vectorized
from snowflake.snowpark.udf import UserDefinedFunction
from snowflake.snowpark.types import (
Expand Down
20 changes: 7 additions & 13 deletions tests/unit/test_internal_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 import options, utils
from snowflake.snowpark._internal.utils import (
_pandas_importer,
generate_random_alphanumeric,
split_snowflake_identifier_with_dot,
)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -210,3 +198,9 @@ def test_generate_random_alphanumeric():
)
def test_split_snowflake_identifier_with_dot(string, expected_result):
assert split_snowflake_identifier_with_dot(string) == expected_result


def test_missing_pandas():
result = options._missing_pandas()
assert isinstance(result, options.MissingOptionalDependency)
assert result._dep_name == "pandas"
Loading
Loading