Skip to content

Commit 35fc1c5

Browse files
FilipPyrekmfranczel
andcommitted
feat: python 3.13 support
Co-authored-by: mfranczel <mfranczel@users.noreply.github.com>
1 parent 48b0a54 commit 35fc1c5

File tree

10 files changed

+66
-34
lines changed

10 files changed

+66
-34
lines changed

.cursorrules

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ Supported versions:
137137
- Python 3.10
138138
- Python 3.11
139139
- Python 3.12
140+
- Python 3.13
140141

141142
## Code Examples
142143

.github/workflows/cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
strategy:
3636
fail-fast: false
3737
matrix:
38-
python_version: ["3.9", "3.10", "3.11", "3.12"]
38+
python_version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
3939
permissions:
4040
id-token: write
4141
contents: read
@@ -413,7 +413,7 @@ jobs:
413413
needs: build-and-push-artifacts-status
414414
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
415415
env:
416-
PYTHON_VERSIONS: "3.9,3.10,3.11,3.12"
416+
PYTHON_VERSIONS: "3.9,3.10,3.11,3.12,3.13"
417417
steps:
418418
- name: Checkout code
419419
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ jobs:
162162
strategy:
163163
fail-fast: false
164164
matrix:
165-
python-version: ["3.9", "3.10", "3.11", "3.12"]
165+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
166166

167167
steps:
168168
- name: Checkout code
@@ -283,7 +283,7 @@ jobs:
283283
strategy:
284284
fail-fast: false
285285
matrix:
286-
python-version: ["3.9", "3.10", "3.11", "3.12"]
286+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
287287
steps:
288288
- name: Checkout code
289289
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
@@ -299,11 +299,11 @@ jobs:
299299
with:
300300
python-version: ${{ matrix.python-version }}
301301

302-
- name: Set up Java 11
302+
- name: Set up Java 17
303303
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
304304
with:
305305
distribution: 'temurin'
306-
java-version: '11'
306+
java-version: '17'
307307

308308
- name: Load cached Poetry installation
309309
id: cached-poetry

.mise.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[tools]
66
python = "3.12"
7-
java = "temurin-11"
7+
java = "temurin-17"
88
poetry = "2.2.0"
99

1010
[tasks.setup]

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252

5353
## Python Version Support
5454

55-
- Python 3.9, 3.10, 3.11, 3.12
55+
- Python 3.9, 3.10, 3.11, 3.12, 3.13
5656

5757
## Dependencies
5858

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ The toolkit consists of two main bundle types:
3737
2. Run setup:
3838

3939
```bash
40-
mise install # Installs Python 3.12 and Java 11
40+
mise install # Installs Python 3.12 and Java 17
4141
mise run setup # Installs dependencies and pre-commit hooks
4242
```
4343

4444
#### Option 2: Manual setup
4545

4646
1. Install poetry: [Installation](https://python-poetry.org/docs/#installation)
47-
2. Install Java 11 (required for PySpark tests):
47+
2. Install Java 17 (required for PySpark tests):
4848
- macOS: `brew install openjdk@11`
49-
- Ubuntu/Debian: `sudo apt-get install openjdk-11-jdk`
50-
- RHEL/Fedora: `sudo dnf install java-11-openjdk-devel`
49+
- Ubuntu/Debian: `sudo apt-get install openjdk-17-jdk`
50+
- RHEL/Fedora: `sudo dnf install java-17-openjdk-devel`
5151
3. Set up venv for development package:
5252

5353
```bash
@@ -277,7 +277,7 @@ $ ./bin/test-local
277277
278278
We use Docker to ensure reproducible environments due to Jupyter libraries' binary dependencies:
279279

280-
- `builder.Dockerfile`: Creates Python package bundles for different versions (3.9-3.12), generates kernel and server bundles, and packages the toolkit for distribution using Poetry.
280+
- `builder.Dockerfile`: Creates Python package bundles for different versions (3.9-3.13), generates kernel and server bundles, and packages the toolkit for distribution using Poetry.
281281

282282
- `test.Dockerfile`: Provides consistent test environment for running unit and integration tests across Python versions using nox. Used both locally and in CI/CD pipeline.
283283

deepnote_toolkit/ocelots/pandas/analyze.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,15 @@ def _get_histogram(pd_series):
8383
{"bin_start": bins[i], "bin_end": bins[i + 1], "count": count.item()}
8484
for i, count in enumerate(y)
8585
]
86-
except IndexError:
87-
# numpy bug https://github.com/numpy/numpy/issues/8627
88-
return None
86+
except ValueError as e:
87+
# NumPy 2.2+ raises "Too many bins for data range" when:
88+
# - Data range is zero (all values identical), or
89+
# - For integer data, bin width would be < 1.0, or
90+
# - Floating point precision prevents creating finite-sized bins at large scales
91+
# Numpy implementation: https://github.com/numpy/numpy/blob/e7a123b2d3eca9897843791dd698c1803d9a39c2/numpy/lib/_histograms_impl.py#L454
92+
if "Too many bins for data range" in str(e):
93+
return None
94+
raise
8995

9096

9197
def _calculate_min_max(column):

dockerfiles/test.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM quay.io/pypa/manylinux_2_28_x86_64:2025.05.28-1
22
RUN pipx install nox poetry==2.2.0
33

44
RUN dnf -y update && \
5-
dnf -y install java-11-openjdk-devel \
5+
dnf -y install java-17-openjdk-devel \
66
# Required for pymssql - provides sqlfront.h header file
77
freetds-devel \
88
# Required for database connectivity through ODBC

noxfile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from nox import session
44

55

6-
@session(python=["3.9", "3.10", "3.11", "3.12"], reuse_venv=True)
6+
@session(python=["3.9", "3.10", "3.11", "3.12", "3.13"], reuse_venv=True)
77
def unit(session):
88
"""Run unit tests. Coverage is disabled by default, use --coverage to enable."""
99

@@ -67,7 +67,7 @@ def unit(session):
6767
)
6868

6969

70-
@session(python=["3.9", "3.10", "3.11", "3.12"], reuse_venv=True)
70+
@session(python=["3.9", "3.10", "3.11", "3.12", "3.13"], reuse_venv=True)
7171
def integration(session):
7272
"""Run integration tests. Coverage is disabled by default, use --coverage to enable."""
7373
# Validate required environment variables

pyproject.toml

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ maintainers = [
1515
]
1616
readme = "README.md"
1717
license = {text = "Apache-2.0"}
18-
requires-python = ">=3.9.0,<3.13,!=3.9.7"
18+
requires-python = ">=3.9.0,<3.14,!=3.9.7"
1919
keywords = [
2020
"deepnote",
2121
"jupyter",
@@ -39,6 +39,7 @@ classifiers = [
3939
"Programming Language :: Python :: 3.10",
4040
"Programming Language :: Python :: 3.11",
4141
"Programming Language :: Python :: 3.12",
42+
"Programming Language :: Python :: 3.13",
4243
"Operating System :: OS Independent",
4344
"Environment :: Console",
4445
"Framework :: Jupyter"
@@ -47,55 +48,70 @@ dependencies = [
4748
# Core data libraries
4849
"pandas>=1.2.5,<2.2; python_version < '3.12'",
4950
"pandas>=2.1.0,<2.3; python_version >= '3.12'",
51+
"pandas>=2.2.3,<2.4; python_version >= '3.13'",
5052
"numpy>=1.21,<2; python_version >= '3.9' and python_version < '3.10'",
5153
"numpy>=1.23,<2; python_version >= '3.10' and python_version < '3.11'",
5254
"numpy>=1.24,<2; python_version >= '3.11' and python_version < '3.12'",
53-
"numpy>=1.26.0,<2; python_version >= '3.12'",
55+
"numpy>=1.26.0,<2; python_version == '3.12'",
56+
"numpy>=2.1.0,<3; python_version >= '3.13'",
5457

5558
# SQL and database dependencies
5659
"duckdb>=1.1.0,<2.0.0; python_version < '3.12'",
57-
"duckdb>=1.1.0; python_version >= '3.12'",
58-
"google-cloud-bigquery-storage==2.16.2",
60+
"duckdb>=1.1.0,<2.0.0; python_version >= '3.12'",
61+
"duckdb>=1.4.1,<2.0.0; python_version >= '3.13'",
62+
"google-cloud-bigquery-storage==2.16.2; python_version < '3.13'",
63+
"google-cloud-bigquery-storage>=2.33.1,<3; python_version>='3.13'",
5964

6065
"pyarrow>=10.0.0,<=17.0.0; python_version >= '3.9' and python_version < '3.11' and sys_platform != 'darwin'",
6166
"pyarrow>=16.0.0,<18.0.0; python_version >= '3.9' and python_version < '3.11' and sys_platform == 'darwin'",
6267
"pyarrow>=13.0.0,<=17.0.0; python_version >= '3.11' and python_version < '3.12' and sys_platform != 'darwin'",
6368
"pyarrow>=16.0.0,<=18.0.0; python_version >= '3.11' and python_version < '3.12' and sys_platform == 'darwin'",
6469
"pyarrow>=14.0.1; python_version >= '3.12'",
70+
"pyarrow>=18.0.0,<22.0; python_version >= '3.13'",
6571

6672
"db-dtypes>=1.2.0,<1.4",
6773

6874
# pymssql: macOS uses versions with ARM64 wheels (2.3.5+)
6975
"pymssql>=2.3.5,<2.4; python_version >= '3.9' and sys_platform == 'darwin'",
7076
"pymssql>=2.2.9,<2.4; python_version >= '3.9' and python_version < '3.12' and sys_platform != 'darwin'",
7177
"pymssql>=2.3.0,<2.4; python_version >= '3.12' and sys_platform != 'darwin'",
78+
"pymssql>=2.3.8,<2.4; python_version >= '3.13'",
7279

7380
"sshtunnel==0.4.0",
7481
"psycopg2-binary>=2.9.4,<2.9.10; sys_platform == 'darwin' and python_version == '3.9'",
7582
"psycopg2-binary>=2.9.4,<2.10; sys_platform != 'darwin' or python_version >= '3.10'",
83+
"psycopg2-binary>=2.9.10,<3; python_version>='3.13'",
7684

7785
# SQL templating
7886
"jinja2>=3.1.6,<4",
7987
"sqlparse>=0.4.4,<0.6",
80-
"ipykernel>6.22.0",
88+
"ipykernel>6.30.0",
8189
"pymysql>=1.1.1,<1.2",
82-
"pymongo>=4.6.3,<4.10",
83-
"dnspython>=2.6.1,<2.7",
90+
"pymongo>=4.6.3,<4.10; python_version < '3.13'",
91+
"pymongo>=4.9.0,<5; python_version>='3.13'",
92+
"dnspython>=2.6.1,<2.7; python_version < '3.13'",
93+
"dnspython>=2.7.0,<3.0; python_version>='3.13'",
8494
"paramiko>=3.4.0,<3.6",
8595
"sqlalchemy<2; python_version <= '3.11'",
96+
"sqlalchemy>=2.0.31,<3; python_version >= '3.13'",
8697
"snowflake-sqlalchemy>=1.6.0,<1.8",
8798
"snowflake-connector-python>=3.13.1",
99+
"snowflake-connector-python>=3.16.0,<5; python_version>='3.13'",
88100
"sqlalchemy-spanner>=1.6.2,<2",
89101
"clickhouse-sqlalchemy>0,<0.4",
90-
"sqlalchemy-bigquery>1.6.1,<1.13",
102+
"sqlalchemy-bigquery>1.6.1,<1.13; python_version < '3.13'",
103+
"sqlalchemy-bigquery>=1.15.0,<1.20; python_version>='3.13'",
91104
"zstd>1.5.5.1; python_version < '3.11'",
92105
"zstd>1.5.7.0; python_version >= '3.11' and python_version < '3.12'",
93106
"zstd>1.5.7.0; python_version >= '3.12'",
94107
"deepnote-sqlalchemy-redshift==0.8.17",
95108
"trino[sqlalchemy]>=0.327.0,<=0.330.0",
109+
"trino[sqlalchemy]>=0.329.0,<=0.336.0; python_version>='3.13'",
96110
"pyathena[sqlalchemy]==3.9.0",
111+
"pyathena[sqlalchemy]>=3.9.0,<4; python_version>='3.13'",
97112
"sqlalchemy-dremio>=3.0.3,<3.1",
98-
"dill==0.3.8",
113+
"dill>=0.3.8,<=0.4; python_version <= '3.12'",
114+
"dill>=0.3.9,<=0.4; python_version >= '3.13'",
99115

100116
# AlloyDB
101117
"pg8000==1.31.5",
@@ -122,9 +138,15 @@ dependencies = [
122138

123139
# Config dependencies - they need to be declared both in main and server extras, keep them in sync
124140
"pydantic>=1.10.0,<3",
141+
"pydantic>=2.8.0,<3; python_version>='3.13'",
125142
"pyyaml>=6,<7",
126143
"tomli>=2,<3; python_version < '3.11'",
127-
"toml>=0.10.0,<1.0.0"
144+
"toml>=0.10.0,<1.0.0",
145+
"toml>=0.10.0,<1.0.0",
146+
147+
# Compatibility constraints for transitive dependencies
148+
"grpcio>=1.66.2; python_version >= '3.13'",
149+
"greenlet>=3.1.0; python_version >= '3.13'"
128150
]
129151

130152
[project.urls]
@@ -143,6 +165,7 @@ server = [
143165

144166
# Config dependencies - they need to be declared both in main and server extras, keep them in sync
145167
"pydantic>=1.10.0,<3",
168+
"pydantic>=2.8.0,<3; python_version>='3.13'",
146169
"pyyaml>=6,<7",
147170
"tomli>=2,<3; python_version < '3.11'",
148171
"toml>=0.10.0,<1.0.0"
@@ -154,24 +177,25 @@ deepnote-toolkit = "deepnote_toolkit.cli.main:main"
154177

155178
[dependency-groups]
156179
dev = [
157-
"pylint>=3.2.5,<4.0.0",
180+
"pylint>=3.3.0,<4.0.0",
158181
"flake8>=7.1.0,<8.0.0",
159182
"black>=24.4.2,<25.0.0",
160183
"isort>=5.13.2,<6.0.0",
161184
"pytest>=8.3.1,<9.0.0",
162185
"pytest-cov>=6.0.0,<7.0.0",
163186
"coverage[toml]>=7.10.0,<8.0.0",
164-
"mypy>=1.11.0,<2.0.0",
187+
"mypy>=1.13.0,<2.0.0",
165188
"pre-commit>=3.6.0,<4.0.0; python_version >= '3.10'",
166189
"pre-commit<3.6.0; python_version >= '3.9' and python_version < '3.10'",
167-
"responses>=0.25.3,<0.26.0",
190+
"responses>=0.25.7,<0.26.0",
168191
"parameterized>=0.9.0,<0.10.0",
169192
"geopandas>=0.11.1,<1.1; python_version < '3.12'",
170193
"geopandas>=0.13.2; python_version >= '3.12'",
171194
# We do not distribute PySpark for all users because it's huge dependency (300mb) and not all
172195
# users need it. So in code we get pyspark from global module cache (since user already imported it at
173196
# that point). But we also have it as dev dependency to provide better autocompletion and for tests
174-
"pyspark>=3.5.5,<4.0.0",
197+
"pyspark>=3.5.5,<4.0.0; python_version < '3.13'",
198+
"pyspark>=4.0.0,<5.0.0; python_version >= '3.13'",
175199
"nox>=2025.5.1,<2026.0.0",
176200
"poetry-dynamic-versioning>=1.4.0,<2.0.0",
177201
"twine>=6.1.0,<7.0.0",
@@ -182,7 +206,8 @@ license-check = [
182206
# Dependencies needed for license checking that aren't in main production dependencies
183207
"geopandas>=0.11.1,<1.1; python_version < '3.12'",
184208
"geopandas>=0.13.2; python_version >= '3.12'",
185-
"pyspark>=3.5.5,<4.0.0"
209+
"pyspark>=3.5.5,<4.0.0",
210+
"pyspark>=3.5.5,<5.0.0"
186211
]
187212

188213
[tool.poetry]

0 commit comments

Comments
 (0)