Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 23 additions & 6 deletions .github/workflows/daily_precommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,23 @@ jobs:
- { os: {image_name: ubuntu-latest-64-cores, download_name: linux}, python-version: "3.11", cloud-provider: gcp }
- { os: {image_name: ubuntu-latest-64-cores, download_name: linux}, python-version: "3.12", cloud-provider: aws }
- { os: {image_name: ubuntu-latest-64-cores, download_name: linux}, python-version: "3.13", cloud-provider: azure }
- { os: {image_name: ubuntu-latest-64-cores, download_name: linux}, python-version: "3.14", cloud-provider: gcp }

# macOS + rotating cloud providers
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.9", cloud-provider: gcp }
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.10", cloud-provider: aws }
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.11", cloud-provider: azure }
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.12", cloud-provider: gcp }
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.13", cloud-provider: aws }
- { os: {image_name: macos-latest, download_name: macos}, python-version: "3.14", cloud-provider: azure }

# Windows + rotating cloud providers
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.9", cloud-provider: azure }
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.10", cloud-provider: gcp }
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.11", cloud-provider: aws }
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.12", cloud-provider: azure }
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.13", cloud-provider: gcp }
- { os: {image_name: windows-latest-64-cores, download_name: windows}, python-version: "3.14", cloud-provider: aws }
steps:
- name: Checkout Code
uses: actions/checkout@v4
Expand Down Expand Up @@ -162,7 +165,8 @@ jobs:
run: uv pip install -U setuptools pip wheel --system
- name: Install tox
run: uv pip install tox --system
- if: ${{ contains('macos', matrix.os.download_name) }}
# TODO: enable doctest for 3.14
- if: ${{ contains('macos', matrix.os.download_name) && matrix.python-version != '3.14' }}
name: Run doctests
run: python -m tox -e "py${PYTHON_VERSION}-doctest-notudf-ci"
env:
Expand All @@ -173,7 +177,9 @@ jobs:
# Specify SNOWFLAKE_IS_PYTHON_RUNTIME_TEST: 1 when adding >= python3.12 with no server-side support
# For example, see https://github.com/snowflakedb/snowpark-python/pull/681
shell: bash
- name: Run tests (excluding doctests)
# TODO: enable for 3.14
- if: ${{ matrix.python-version != '3.14' }}
name: Run tests (excluding doctests)
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctest-ci"
env:
PYTHON_VERSION: ${{ matrix.python-version }}
Expand All @@ -183,6 +189,16 @@ jobs:
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
shell: bash
# TODO: remove the test below and run udf tests for 3.14
- if: ${{ matrix.python-version == '3.14' }}
name: Run tests (excluding udf, doctests)
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctestnotudf-ci"
env:
PYTHON_VERSION: ${{ matrix.python-version }}
cloud_provider: ${{ matrix.cloud-provider }}
PYTEST_ADDOPTS: --color=yes --tb=short
TOX_PARALLEL_NO_SPINNER: 1
shell: bash
- name: Install MS ODBC Driver (Ubuntu only)
if: ${{ matrix.os.download_name == 'linux' }}
run: |
Expand All @@ -193,7 +209,8 @@ jobs:
shell: bash
- name: Run data source tests
# psycopg2 is not supported on macos 3.9
if: ${{ !(contains('macos', matrix.os.download_name) && matrix.python-version == '3.9') }}
# TODO: enable datasource tests for 3.14
if: ${{ !(contains('macos', matrix.os.download_name) && matrix.python-version == '3.9') && !(matrix.python-version == '3.14') }}
run: python -m tox -e datasource
env:
PYTHON_VERSION: ${{ matrix.python-version }}
Expand Down Expand Up @@ -418,7 +435,7 @@ jobs:
image_name: windows-latest
- download_name: ubuntu
image_name: ubuntu-latest
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
cloud-provider: [azure]
steps:
- name: Checkout Code
Expand Down Expand Up @@ -488,7 +505,7 @@ jobs:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
python-version: ["3.9", "3.10", "3.11", "3.12"] # SNOW-2230787 test failing on Python 3.13
python-version: ["3.9", "3.10", "3.11", "3.12", "3.14"] # SNOW-2230787 test failing on Python 3.13
cloud-provider: [gcp]
protobuf-version: ["3.20.1", "4.25.3", "5.28.3"]
steps:
Expand Down Expand Up @@ -558,7 +575,7 @@ jobs:
os:
- image_name: macos-latest
download_name: macos # it includes doctest
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
cloud-provider: [azure]
steps:
- name: Checkout Code
Expand Down
33 changes: 28 additions & 5 deletions .github/workflows/precommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ jobs:
- python-version: "3.13"
cloud-provider: gcp
os: windows-latest-64-cores
# run py 3.14 tests on aws/ubuntu
- python-version: "3.14"
cloud-provider: aws
os: ubuntu-latest-64-cores
# # run py 3.14 tests on gcp on windows
- python-version: "3.14"
cloud-provider: gcp
os: windows-latest-64-cores
steps:
- name: Checkout Code
uses: actions/checkout@v4
Expand Down Expand Up @@ -171,7 +179,8 @@ jobs:
- name: Install tox
run: uv pip install tox --system
# we only run doctest on macos
- if: ${{ matrix.os == 'macos-latest' }}
# TODO: enable doctest for 3.14
- if: ${{ matrix.os == 'macos-latest' && matrix.python-version != '3.14' }}
name: Run doctests
run: python -m tox -e "py${PYTHON_VERSION}-doctest-notudf-ci"
env:
Expand All @@ -183,7 +192,7 @@ jobs:
# For example, see https://github.com/snowflakedb/snowpark-python/pull/681
shell: bash
# do not run other tests for macos
- if: ${{ matrix.os != 'macos-latest' }}
- if: ${{ matrix.os != 'macos-latest' && matrix.python-version != '3.14' }}
name: Run tests (excluding doctests)
run: python -m tox -e "py${PYTHON_VERSION/\./}-notdoctest-ci"
env:
Expand All @@ -194,6 +203,19 @@ jobs:
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
shell: bash
# TODO: Remove the test below and run udf tests for 3.14
# for 3.14, skip udf, doctest
- if: ${{ matrix.os != 'macos-latest' && matrix.python-version == '3.14' }}
name: Run tests (excluding udf, doctests)
run: python -m tox -e "py${PYTHON_VERSION/\./}-notudfdoctest-ci"
env:
PYTHON_VERSION: ${{ matrix.python-version }}
cloud_provider: ${{ matrix.cloud-provider }}
PYTEST_ADDOPTS: --color=yes --tb=short
TOX_PARALLEL_NO_SPINNER: 1
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
shell: bash
- name: Install MS ODBC Driver (Ubuntu only)
if: ${{ contains(matrix.os, 'ubuntu') }}
run: |
Expand All @@ -204,7 +226,8 @@ jobs:
shell: bash
- name: Run data source tests
# psycopg2 is not supported on macos 3.9
if: ${{ !(matrix.os == 'macos-latest' && matrix.python-version == '3.9') }}
# TODO: enable datasource tests for 3.14
if: ${{ !(matrix.os == 'macos-latest' && matrix.python-version == '3.9') && !(matrix.python-version == '3.14') }}
run: python -m tox -e datasource
env:
PYTHON_VERSION: ${{ matrix.python-version }}
Expand Down Expand Up @@ -233,7 +256,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ["3.13"]
python-version: ["3.14"]
cloud-provider: [azure]
steps:
- name: Checkout Code
Expand Down Expand Up @@ -436,7 +459,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
python-version: [ "3.13" ] # Test latest python
python-version: [ "3.14" ] # Test latest python
cloud-provider: [ gcp ] # Test only one csp
steps:
- name: Checkout Code
Expand Down
11 changes: 8 additions & 3 deletions recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ build:
string: "py311_{{ build_number }}" # [py==311]
string: "py312_{{ build_number }}" # [py==312]
string: "py313_{{ build_number }}" # [py==313]
string: "py314_{{ build_number }}" # [py==314]
{% endif %}

{% if noarch_build and py not in [39, 310, 311, 312, 313] %}
error: "Noarch build for Python version {{ py }} is not supported. Supported versions: 3.9, 3.10, 3.11, 3.12, or 3.13."
{% if noarch_build and py not in [39, 310, 311, 312, 313, 314] %}
error: "Noarch build for Python version {{ py }} is not supported. Supported versions: 3.9, 3.10, 3.11, 3.12, 3.13, or 3.14."
{% else %}
requirements:
host:
Expand All @@ -37,7 +38,9 @@ requirements:
- wheel
# Snowpark IR
- protobuf==3.20.1 # [py<=310]
- protobuf==4.25.3 # [py>310]
- protobuf==4.25.3 # [py>310 and py<314]
- protobuf==5.29.3 # [py>=314]
- libprotobuf >=5.29.3 # [py>=314]
# mypy-protobuf 3.7.0 requires protobuf >= 5.26
- mypy-protobuf <=3.6.0
run:
Expand All @@ -51,6 +54,8 @@ requirements:
- python >=3.12,<3.13.0a0
{% elif noarch_build and py == 313 %}
- python >=3.13,<3.14.0a0
{% elif noarch_build and py == 314 %}
- python >=3.14,<3.15.0a0
{% else %}
- python
{% endif %}
Expand Down
1 change: 1 addition & 0 deletions scripts/conda_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ conda build recipe/ -c sfe1ed40 --python=3.10 --numpy=1.21
conda build recipe/ -c sfe1ed40 --python=3.11 --numpy=1.23
conda build recipe/ -c sfe1ed40 --python=3.12 --numpy=1.26
conda build recipe/ -c sfe1ed40 --python=3.13 --numpy=2.2.0
conda build recipe/ -c sfe1ed40 --python=3.14 --numpy=2.4.2
8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"python-dateutil", # Snowpark IR
"tzlocal", # Snowpark IR
]
REQUIRED_PYTHON_VERSION = ">=3.9, <3.14"
REQUIRED_PYTHON_VERSION = ">=3.9, <3.15"

if os.getenv("SNOWFLAKE_IS_PYTHON_RUNTIME_TEST", False):
REQUIRED_PYTHON_VERSION = ">=3.9"
Expand Down Expand Up @@ -71,7 +71,7 @@
# Snowpark pandas 3rd party library testing. Cap the scipy version because
# Snowflake cannot find newer versions of scipy for python 3.11+. See
# SNOW-2452791.
"scipy<=1.16.0",
"scipy<=1.16.3",
"statsmodels", # Snowpark pandas 3rd party library testing
"scikit-learn", # Snowpark pandas 3rd party library testing
# plotly version restricted due to foreseen change in query counts in version 6.0.0+
Expand All @@ -80,7 +80,8 @@
# snowflake-ml-python is available on python 3.12.
"snowflake-ml-python>=1.8.0; python_version<'3.12'",
"s3fs", # Used in tests that read CSV files from s3
"ray", # Used in data movement tests
# ray currently has no compatible wheels for Python 3.14.
"ray; python_version<'3.14'", # Used in data movement tests
]

# read the version
Expand Down Expand Up @@ -249,6 +250,7 @@ def run(self):
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Database",
"Topic :: Software Development",
"Topic :: Software Development :: Libraries",
Expand Down
5 changes: 3 additions & 2 deletions src/snowflake/snowpark/_internal/analyzer/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
#

import copy
import uuid
from typing import TYPE_CHECKING, AbstractSet, Any, Dict, List, Optional, Tuple

Expand Down Expand Up @@ -158,7 +157,9 @@ def expr_id(self) -> uuid.UUID:
return self._expr_id

def __copy__(self):
new = copy.copy(super())
cls = self.__class__
new = cls.__new__(cls)
new.__dict__.update(self.__dict__)
new._expr_id = None # type: ignore
return new

Expand Down
10 changes: 6 additions & 4 deletions src/snowflake/snowpark/_internal/analyzer/snowflake_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from logging import getLogger
import re
import sys
import uuid
import uuid as uuid_lib
from collections import defaultdict, deque
from enum import Enum
from dataclasses import dataclass
Expand Down Expand Up @@ -383,7 +383,7 @@ def add_single_quote(string: str) -> str:
# and it's a reading XML query.

def search_read_file_node(
node: Union[SnowflakePlan, Selectable]
node: Union[SnowflakePlan, Selectable],
) -> Optional[ReadFileNode]:
source_plan = (
node.source_plan
Expand Down Expand Up @@ -435,7 +435,7 @@ def __init__(
# during the compilation stage.
schema_query: Optional[str],
post_actions: Optional[List["Query"]] = None,
expr_to_alias: Optional[Dict[uuid.UUID, str]] = None,
expr_to_alias: Optional[Dict[uuid_lib.UUID, str]] = None,
source_plan: Optional[LogicalPlan] = None,
is_ddl_on_temp_object: bool = False,
api_calls: Optional[List[Dict]] = None,
Expand Down Expand Up @@ -479,7 +479,9 @@ def __init__(
if self.session._join_alias_fix
else defaultdict(dict)
)
self._uuid = from_selectable_uuid if from_selectable_uuid else str(uuid.uuid4())
self._uuid = (
from_selectable_uuid if from_selectable_uuid else str(uuid_lib.uuid4())
)
# We set the query line intervals for the last query in the queries list
self.set_last_query_line_intervals()
# In the placeholder query, subquery (child) is held by the ID of query plan
Expand Down
2 changes: 1 addition & 1 deletion src/snowflake/snowpark/mock/_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ def handle_function_expression(
if param_name in exp.named_arguments:
type_hint = str(type_hints.get(param_name, ""))
keep_literal = "Column" not in type_hint
if type_hint == "typing.Optional[dict]":
if type_hint in ["typing.Optional[dict]", "dict | None"]:
to_pass_kwargs[param_name] = json.loads(
exp.named_arguments[param_name].sql.replace("'", '"')
)
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 @@ -4981,7 +4981,7 @@ def _get_or_register_xpath_udf(
handler_name,
return_type=return_type_map[return_type],
input_types=[StringType(), StringType()],
packages=["snowflake-snowpark-python", "lxml<6"],
packages=["snowflake-snowpark-python", "lxml<=6.0.2"],
replace=True,
_emit_ast=False,
_suppress_local_package_warnings=True,
Expand Down
1 change: 1 addition & 0 deletions tests/integ/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ def session(
"alter session set ENABLE_EXTRACTION_PUSHDOWN_EXTERNAL_PARQUET_FOR_COPY_PHASE_I='Track';"
).collect()
session.sql("alter session set ENABLE_ROW_ACCESS_POLICY=true").collect()
session.sql("alter session set ENABLE_PYTHON_3_14=true").collect()

try:
yield session
Expand Down
2 changes: 2 additions & 0 deletions tests/integ/test_data_source_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ def assert_datasource_statement_params_run_query(*args, **kwargs):
RUNNING_ON_JENKINS,
reason="SNOW-2089683: oracledb real connection test failed on jenkins",
)
@pytest.mark.udf
def test_telemetry_tracking_for_udtf(caplog, session, ast_enabled):

if ast_enabled:
Expand Down Expand Up @@ -1013,6 +1014,7 @@ def test_empty_table(session, fetch_with_process):
assert df.collect() == []


@pytest.mark.udf
def test_sql_server_udtf_ingestion(session):
raw_schema = [
("Id", int, None, None, 10, 0, False),
Expand Down
7 changes: 6 additions & 1 deletion tests/integ/test_stored_procedure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,12 @@ def _(_: Session, x, y: int) -> int:
def _(_: Session, x: int, y: Union[int, float]) -> Union[int, float]:
return x + y

assert "invalid type typing.Union[int, float]" in str(ex_info)
msgs = [
"invalid type typing.Union[int, float]",
# python 3.14 changed the string representation of Union types
"invalid type int | float",
]
assert any(msg in str(ex_info) for msg in msgs)

with pytest.raises(TypeError) as ex_info:

Expand Down
7 changes: 6 additions & 1 deletion tests/integ/test_udf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1458,7 +1458,12 @@ def _(x, y: int) -> int:
def _(x: int, y: Union[int, float]) -> Union[int, float]:
return x + y

assert "invalid type typing.Union[int, float]" in str(ex_info)
msgs = [
"invalid type typing.Union[int, float]",
# python 3.14 changed the string representation of Union types
"invalid type int | float",
]
assert any(msg in str(ex_info) for msg in msgs)

with pytest.raises(ValueError) as ex_info:

Expand Down
2 changes: 2 additions & 0 deletions tests/integ/test_udf_profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def setup(profiler_session, resources_path, local_testing_mode):
"config.getoption('local_testing_mode', default=False)",
reason="session.sql is not supported in localtesting",
)
@pytest.mark.udf
def test_udf_profiler_basic(profiler_session):
@udf(
name="str_udf", replace=True, return_type=StringType(), session=profiler_session
Expand Down Expand Up @@ -65,6 +66,7 @@ def str_udf():
"config.getoption('local_testing_mode', default=False)",
reason="session.sql is not supported in localtesting",
)
@pytest.mark.udf
def test_anonymous_udf(profiler_session):
add_one = udf(
lambda x: x + 1,
Expand Down
Loading
Loading