Skip to content

Commit e2b45cf

Browse files
authored
SNOW-2387344: add py3.13 in pipeline, update doc (#3834)
1 parent 1c0d060 commit e2b45cf

10 files changed

Lines changed: 44 additions & 70 deletions

File tree

.github/workflows/daily_precommit.yml

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ jobs:
162162
run: uv pip install -U setuptools pip wheel --system
163163
- name: Install tox
164164
run: uv pip install tox --system
165-
# SNOW-2213578: Re-enable the test for 3.13
166-
- if: ${{ contains('macos', matrix.os.download_name) && matrix.python-version != '3.13' }}
165+
- if: ${{ contains('macos', matrix.os.download_name) }}
167166
name: Run doctests
168167
run: python -m tox -e "py${PYTHON_VERSION}-doctest-notudf-ci"
169168
env:
@@ -174,8 +173,7 @@ jobs:
174173
# Specify SNOWFLAKE_IS_PYTHON_RUNTIME_TEST: 1 when adding >= python3.12 with no server-side support
175174
# For example, see https://github.com/snowflakedb/snowpark-python/pull/681
176175
shell: bash
177-
- if: ${{ matrix.python-version != '3.13' }}
178-
name: Run tests (excluding doctests)
176+
- name: Run tests (excluding doctests)
179177
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctest-ci"
180178
env:
181179
PYTHON_VERSION: ${{ matrix.python-version }}
@@ -185,18 +183,6 @@ jobs:
185183
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
186184
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
187185
shell: bash
188-
# SNOW-2213578 : Remove the test below and run udf tests for 3.13
189-
- if: ${{ matrix.python-version == '3.13' }}
190-
name: Run tests (excluding udf, doctests)
191-
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctestnotudf-ci"
192-
env:
193-
PYTHON_VERSION: ${{ matrix.python-version }}
194-
cloud_provider: ${{ matrix.cloud-provider }}
195-
PYTEST_ADDOPTS: --color=yes --tb=short
196-
TOX_PARALLEL_NO_SPINNER: 1
197-
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
198-
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
199-
shell: bash
200186
- name: Install MS ODBC Driver (Ubuntu only)
201187
if: ${{ matrix.os.download_name == 'linux' }}
202188
run: |
@@ -608,8 +594,7 @@ jobs:
608594
run: uv pip install -U setuptools pip wheel --system
609595
- name: Install tox
610596
run: uv pip install tox --system
611-
# SNOW-2213578: Re-enable the test for 3.13
612-
- if: ${{ contains('macos', matrix.os.download_name) && matrix.python-version != '3.13' }}
597+
- if: ${{ contains('macos', matrix.os.download_name) }}
613598
name: Run doctests
614599
run: python -m tox -e "py${PYTHON_VERSION}-doctest-notudf-ci"
615600
env:
@@ -618,8 +603,7 @@ jobs:
618603
PYTEST_ADDOPTS: --color=yes --tb=short --disable_cte_optimization
619604
TOX_PARALLEL_NO_SPINNER: 1
620605
shell: bash
621-
- if: ${{ matrix.python-version != '3.13' }}
622-
name: Run tests (excluding doctests)
606+
- name: Run tests (excluding doctests)
623607
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctest-ci"
624608
env:
625609
PYTHON_VERSION: ${{ matrix.python-version }}
@@ -629,18 +613,6 @@ jobs:
629613
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
630614
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
631615
shell: bash
632-
# SNOW-2213578 : Remove the test below and run udf tests for 3.13
633-
- if: ${{ matrix.python-version == '3.13' }}
634-
name: Run tests (excluding udf, doctests)
635-
run: python -m tox -e "py${PYTHON_VERSION/\./}-dailynotdoctestnotudf-ci"
636-
env:
637-
PYTHON_VERSION: ${{ matrix.python-version }}
638-
cloud_provider: ${{ matrix.cloud-provider }}
639-
PYTEST_ADDOPTS: --color=yes --tb=short --disable_cte_optimization
640-
TOX_PARALLEL_NO_SPINNER: 1
641-
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
642-
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
643-
shell: bash
644616
- name: Combine coverages
645617
run: python -m tox -e coverage --skip-missing-interpreters false
646618
shell: bash

.github/workflows/precommit.yml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ jobs:
183183
# For example, see https://github.com/snowflakedb/snowpark-python/pull/681
184184
shell: bash
185185
# do not run other tests for macos
186-
- if: ${{ matrix.os != 'macos-latest' && matrix.python-version != '3.13' }}
186+
- if: ${{ matrix.os != 'macos-latest' }}
187187
name: Run tests (excluding doctests)
188188
run: python -m tox -e "py${PYTHON_VERSION/\./}-notdoctest-ci"
189189
env:
@@ -194,19 +194,6 @@ jobs:
194194
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
195195
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
196196
shell: bash
197-
# SNOW-2213578 : Remove the test below and run udf tests for 3.13
198-
# for 3.13, skip udf, doctest
199-
- if: ${{ matrix.os != 'macos-latest' && matrix.python-version == '3.13' }}
200-
name: Run tests (excluding udf, doctests)
201-
run: python -m tox -e "py${PYTHON_VERSION/\./}-notudfdoctest-ci"
202-
env:
203-
PYTHON_VERSION: ${{ matrix.python-version }}
204-
cloud_provider: ${{ matrix.cloud-provider }}
205-
PYTEST_ADDOPTS: --color=yes --tb=short
206-
SNOWPARK_PYTHON_API_TEST_BUCKET_PATH: ${{ secrets.SNOWPARK_PYTHON_API_TEST_BUCKET_PATH }}
207-
SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION: ${{ vars.SNOWPARK_PYTHON_API_S3_STORAGE_INTEGRATION }}
208-
TOX_PARALLEL_NO_SPINNER: 1
209-
shell: bash
210197
- name: Install MS ODBC Driver (Ubuntu only)
211198
if: ${{ contains(matrix.os, 'ubuntu') }}
212199
run: |
@@ -217,8 +204,7 @@ jobs:
217204
shell: bash
218205
- name: Run data source tests
219206
# psycopg2 is not supported on macos 3.9
220-
# SNOW-2213578: Re-enable the test for 3.13
221-
if: ${{ !(matrix.os == 'macos-latest' && matrix.python-version == '3.9') && !(matrix.python-version == '3.13') }}
207+
if: ${{ !(matrix.os == 'macos-latest' && matrix.python-version == '3.9') }}
222208
run: python -m tox -e datasource
223209
env:
224210
PYTHON_VERSION: ${{ matrix.python-version }}

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ cd snowpark-python
3434
#### Install the library in edit mode and install its dependencies
3535

3636
- Create a new Python virtual environment with any Python version that we support.
37-
- The Snowpark Python API supports **Python 3.9, Python 3.10, Python 3.11 and Python 3.12**.
37+
- The Snowpark Python API supports **Python 3.9, Python 3.10, Python 3.11, Python 3.12 and Python 3.13**.
3838
- The Snowpark pandas API supports **Python 3.9, Python 3.10, and Python 3.11**. Additionally, Snowpark pandas requires **Modin 0.36.x or 0.37.x**, and **pandas 2.2.x or 2.3.x**.
3939

4040
```bash

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ If you don't have a Snowflake account yet, you can [sign up for a 30-day free tr
1818

1919
### Create a Python virtual environment
2020
You can use [miniconda][miniconda], [anaconda][anaconda], or [virtualenv][virtualenv]
21-
to create a Python 3.9, 3.10, 3.11 or 3.12 virtual environment.
21+
to create a Python 3.9, 3.10, 3.11, 3.12 or 3.13 virtual environment.
2222

2323
For Snowpark pandas, only Python 3.9, 3.10, or 3.11 is supported.
2424

src/snowflake/snowpark/session.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1733,8 +1733,10 @@ def add_requirements(
17331733
>>> from snowflake.snowpark.functions import udf
17341734
>>> import numpy
17351735
>>> import pandas
1736+
>>> import sys
17361737
>>> # test_requirements.txt contains "numpy" and "pandas"
1737-
>>> session.add_requirements("tests/resources/test_requirements.txt")
1738+
>>> file = "test_requirements.txt" if sys.version_info < (3, 13) else "test_requirements_py313.txt"
1739+
>>> session.add_requirements(f"tests/resources/{file}")
17381740
>>> @udf
17391741
... def get_package_name_udf() -> list:
17401742
... return [numpy.__name__, pandas.__name__]

tests/integ/test_packaging.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,19 @@ def test_patch_on_get_available_versions_for_packages(session):
185185
reason="numpy and pandas are required",
186186
)
187187
def test_add_packages(session, local_testing_mode):
188+
# Use numpy 2.3.1 for Python 3.13+, numpy 1.26.3 doesn't support Python 3.13
189+
numpy_version = "numpy==2.3.1" if sys.version_info >= (3, 13) else "numpy==1.26.3"
190+
188191
session.add_packages(
189192
[
190-
"numpy==1.26.3",
193+
numpy_version,
191194
"pandas==2.2.3",
192195
"matplotlib",
193196
"pyyaml",
194197
]
195198
)
196199
assert session.get_packages() == {
197-
"numpy": "numpy==1.26.3",
200+
"numpy": numpy_version,
198201
"pandas": "pandas==2.2.3",
199202
"matplotlib": "matplotlib",
200203
"pyyaml": "pyyaml",
@@ -210,8 +213,9 @@ def get_numpy_pandas_dateutil_version() -> str:
210213
df = session.create_dataframe([None]).to_df("a")
211214
res = df.select(call_udf(udf_name)).collect()[0][0]
212215
# don't need to check the version of dateutil, as it can be changed on the server side
216+
expected_numpy_ver = "2.3.1" if sys.version_info >= (3, 13) else "1.26.3"
213217
assert (
214-
res.startswith("1.26.3/2.2.3")
218+
res.startswith(f"{expected_numpy_ver}/2.2.3")
215219
if not local_testing_mode
216220
else res == get_numpy_pandas_dateutil_version()
217221
)
@@ -284,7 +288,7 @@ def extract_major_minor_patch(version_string):
284288

285289
@pytest.mark.udf
286290
def test_add_packages_with_underscore(session):
287-
packages = ["spacy-model-en_core_web_sm", "typing_extensions"]
291+
packages = ["huggingface_hub", "typing_extensions"]
288292
count = (
289293
session.table("information_schema.packages")
290294
.where(col("package_name").in_(packages))
@@ -299,10 +303,9 @@ def test_add_packages_with_underscore(session):
299303
@udf(name=udf_name, packages=packages)
300304
def check_if_package_installed() -> bool:
301305
try:
302-
import spacy
306+
import huggingface_hub # noqa: F401
303307
import typing_extensions # noqa: F401
304308

305-
spacy.load("en_core_web_sm")
306309
return True
307310
except Exception:
308311
return False
@@ -417,7 +420,7 @@ def test_add_requirements(session, resources_path, local_testing_mode):
417420

418421
session.add_requirements(test_files.test_requirements_file)
419422
assert session.get_packages() == {
420-
"numpy": "numpy==1.26.3",
423+
"numpy": "numpy==2.3.1" if sys.version_info >= (3, 13) else "numpy==1.26.3",
421424
"pandas": "pandas==2.2.3",
422425
}
423426

@@ -429,9 +432,10 @@ def get_numpy_pandas_version() -> str:
429432

430433
df = session.create_dataframe([None]).to_df("a")
431434
res = df.select(call_udf(udf_name))
435+
expected_numpy_ver = "2.3.1" if sys.version_info >= (3, 13) else "1.26.3"
432436
Utils.check_answer(
433437
res,
434-
[Row("1.26.3/2.2.3")]
438+
[Row(f"{expected_numpy_ver}/2.2.3")]
435439
if not local_testing_mode
436440
else [Row(f"{numpy.__version__}/{pandas.__version__}")],
437441
)
@@ -441,10 +445,10 @@ def test_add_requirements_twice_should_fail_if_packages_are_different(
441445
session, resources_path
442446
):
443447
test_files = TestFiles(resources_path)
444-
448+
expected_numpy_ver = "2.3.1" if sys.version_info >= (3, 13) else "1.26.3"
445449
session.add_requirements(test_files.test_requirements_file)
446450
assert session.get_packages() == {
447-
"numpy": "numpy==1.26.3",
451+
"numpy": f"numpy=={expected_numpy_ver}",
448452
"pandas": "pandas==2.2.3",
449453
}
450454

@@ -690,7 +694,7 @@ def test_add_packages_with_native_dependency_without_force_push(session):
690694
with pytest.raises(
691695
RuntimeError, match="Your code depends on packages that contain native code"
692696
):
693-
session.add_packages(["catboost==1.2.3"])
697+
session.add_packages(["catboost==1.2.8"])
694698

695699

696700
@pytest.fixture(scope="function")
@@ -911,29 +915,30 @@ def test_add_requirements_with_empty_stage_as_cache_path(
911915
}
912916

913917
session.add_requirements(test_files.test_requirements_file)
918+
expected_numpy_ver = "2.3.1" if sys.version_info >= (3, 13) else "1.26.3"
914919
assert session.get_packages() == {
915-
"numpy": "numpy==1.26.3",
920+
"numpy": f"numpy=={expected_numpy_ver}",
916921
"pandas": "pandas==2.2.3",
917922
}
918923

919924
udf_name = Utils.random_name_for_temp_object(TempObjectType.FUNCTION)
920925

921926
# use a newer snowpark to create an old snowpark udf could lead to conflict cloudpickle.
922-
# e.g. using snowpark 1.27 with cloudpickle 3.0 to create udf using snowpark 1.8, this will leads to
927+
# e.g. using snowpark 1.39 with cloudpickle 3.0 to create udf using snowpark 1.8, this will leads to
923928
# error as cloudpickle 3.0 is specified in udf creation but unsupported in snowpark 1.8
924929
# the solution is to downgrade to cloudpickle 2.2.1 in the env
925930
# TODO: SNOW-1951792, improve error experience
926-
# pin cloudpickle as 1.27.0 snowpark upper bounds it to <=3.0.0
931+
# pin cloudpickle as 1.39.0 snowpark upper bounds it to <=3.0.0
927932
@udf(
928933
name=udf_name,
929-
packages=["snowflake-snowpark-python==1.27.0", "cloudpickle==3.0.0"],
934+
packages=["snowflake-snowpark-python==1.39.0", "cloudpickle==3.0.0"],
930935
)
931936
def get_numpy_pandas_version() -> str:
932937
import snowflake.snowpark as snowpark
933938

934939
return f"{snowpark.__version__}"
935940

936-
Utils.check_answer(session.sql(f"select {udf_name}()"), [Row("1.27.0")])
941+
Utils.check_answer(session.sql(f"select {udf_name}()"), [Row("1.39.0")])
937942

938943

939944
@pytest.mark.udf

tests/integ/test_stored_procedure.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,7 +2327,7 @@ def artifact_repo_test(session: snowflake.snowpark.Session) -> str:
23272327
@pytest.mark.parametrize(
23282328
"version_override, expect_warning",
23292329
[
2330-
("1.27.1", False), # Bugfix version - no warning
2330+
("1.39.1", False), # Bugfix version - no warning
23312331
("999.999.999", True), # Major version change - expect warning
23322332
],
23332333
)
@@ -2350,8 +2350,8 @@ def plus1(session_, x):
23502350
plus1,
23512351
return_type=IntegerType(),
23522352
input_types=[IntegerType()],
2353-
# pin cloudpickle as 1.27.0 snowpark upper bounds it to <=3.0.0
2354-
packages=["snowflake-snowpark-python==1.27.0", "cloudpickle==3.0.0"],
2353+
# pin cloudpickle as 1.39.0 snowpark upper bounds it to <=3.0.0
2354+
packages=["snowflake-snowpark-python==1.39.0", "cloudpickle==3.0.0"],
23552355
)
23562356
assert plus1_sp(lit(6)) == 7
23572357

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
numpy==2.3.1
2+
pandas==2.2.3

tests/unit/scala/test_utils_suite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ def check_zip_files_and_close_stream(input_stream, expected_files):
350350
"resources/test_all_data_types.parquet",
351351
"resources/test_file_with_special_characters.parquet",
352352
"resources/test_requirements.txt",
353+
"resources/test_requirements_py313.txt",
353354
"resources/test_requirements_unsupported.txt",
354355
"resources/test_concat_file1.csv",
355356
"resources/test_concat_file2.csv",

tests/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,12 @@ def test_pandas_udf_py_file(self):
16331633

16341634
@property
16351635
def test_requirements_file(self):
1636+
# TODO: SNOW-2389419, snowpark does not support multiple line requirements for a single package
1637+
# ideally the req file could be like:
1638+
# numpy==1.26.3; python_version<"3.13"
1639+
# numpy==2.3.1; python_version>="3.13"
1640+
if sys.version_info >= (3, 13):
1641+
return os.path.join(self.resources_path, "test_requirements_py313.txt")
16361642
return os.path.join(self.resources_path, "test_requirements.txt")
16371643

16381644
@property

0 commit comments

Comments
 (0)