Skip to content

Support Python 3.15 and free-threaded 3.15t #11710

Open

Description

@headtr1ck

Python 3.15.0 is out, and conda-forge has both python-gil and python-freethreading builds. I tried running the test suite on both, as preparation for adding them to CI.

Python 3.15 (conda-forge)

  • All test dependencies have 3.15 builds except pyarrow.
  • The dask metapackage requires pyarrow, so without a lower bound the solver silently falls back to dask/distributed 2023.3.0. Using dask-core >=2026 + distributed instead gives dask 2026.8.0, and otherwise the same versions as test-py314.
  • Test results: 1 failed, 22016 passed. TestDataArray::test_to_dask_dataframe needs pyarrow (via dask.dataframe) but is only guarded by requires_dask.

Free-threaded Python 3.15t (PyPI wheels)

conda-forge has no free-threaded 3.15 builds of numpy, pandas, scipy etc. yet, but PyPI has cp315t wheels for numpy, pandas, scipy, pyarrow, matplotlib, cartopy, rasterio and lxml. There are no cp315t wheels for cftime, netCDF4, h5py, numcodecs, bottleneck, numexpr and numba.

With a conda python-freethreading interpreter and PyPI wheels: 150 failed, 2 errors, 14646 passed. With PYTHON_GIL=1, 148 of these still fail, so most aren't free-threading issues:

  • 137: h5netcdf is installed without h5py (no cp315t wheel), so requires_h5netcdf doesn't skip. Environment issue.
  • 5: test_ensure_warnings_not_elevated. ensure_warnings in xarray/testing/assertions.py reassigns warnings.filters, which has no effect with context-aware warnings (sys.flags.context_aware_warnings, on by default in free-threaded builds). So the public xr.testing.assert_* functions elevate warnings to errors there.
  • 3: test_rechunk_multi_dimensional_da_cftime is missing requires_cftime.
  • 3: datatree tests assume netCDF4 is installed (NameError: name 'nc4' is not defined in a fixture, and test_default_write_engine).

Only 4 failures depend on the GIL: test_open_mfdataset_manyfiles[scipy-20-*-*-5] (file_cache_maxsize=5, parallel dask reads). CachingFileManager evicts and closes a scipy file opened with mmap while another thread still uses its data. The resulting RuntimeWarning leaves the LRU cache inconsistent and ends in a KeyError. These pass with PYTHON_GIL=1.

Upstream status

Python 3.15 (checked when there are builds on conda-forge and wheels on PyPI):

Free-threaded Python 3.15t (checked when there are cp315t wheels on PyPI):

Other test dependencies without 3.15t wheels on PyPI (checked 2026-10-13): psutil and tornado (distributed), google-crc32c (zarr) and lz4 (dask extras). psutil, tornado and lz4 build from source on 3.15t; google-crc32c builds but falls back to a pure Python implementation with a RuntimeWarning on import. cf-units doesn't build without udunits2, so iris has to be left out of the 3.15t env.

Proposal for CI

  • Add test-py315 alongside the 3.14 envs, and only replace 3.14 once pyarrow has 3.15 builds on conda-forge. Until then, move pyarrow from the accel feature into its own feature and use dask-core in the 3.15 env.
  • Add test-py315t (ubuntu only) with a conda python-freethreading interpreter and PyPI wheels, without h5netcdf until h5py has cp315t wheels.
  • Fix the test guards and ensure_warnings above, and look into the file manager race.

[This is Claude Code on behalf of Michael Niklas]

Activity

  1. welcome commented on Oct 12, 2026

    @welcome

    Thanks for opening your first issue here at xarray! Be sure to follow the issue template!
    If you have an idea for a solution, we would really welcome a Pull Request with proposed changes.
    See the Contributing Guide for more.
    It may take us a while to respond here, but we really value your contribution. Contributors like you help make xarray better.
    Thank you!

  2. headtr1ck commented on Oct 12, 2026

    @headtr1ck
    CollaboratorAuthor

    I would propose to do it in two batches

    1. replace python 3.14 with 3.15 (wait for pyarrow conda-forge release)
    2. add a new env with python 3.15 free threaded
  3. headtr1ck commented on Oct 14, 2026

    @headtr1ck
    CollaboratorAuthor

    Seems like the main stopper right now is actually pyyaml, haha.

  4. keewis commented on Oct 24, 2026

    @keewis
    Collaborator

    see #11801. Most of this is done, except I used the default python which is probably python-freethreading.

  5. headtr1ck commented on Oct 24, 2026

    @headtr1ck
    CollaboratorAuthor

    see #11801. Most of this is done, except I used the default python which is probably python-freethreading.

    Is the pyyaml issue now resolved? I had the issue that without it dask resolved to an incredible old version. I'm on mobile only so I cannot check right now.

  6. keewis commented on Oct 24, 2026

    @keewis
    Collaborator

    it is using dask=2026.8.0, so I would assume that's fine? There are no pyyaml packages for python 3.15 yet, but the feedstock has a "rebuild for py3.15" PR. pyyaml has a noarch: python version, though, so I assume that is what is being used (which is probably slower than the compiled version).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions