Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add broad testing for Python 3.13 #1381

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4cf3eeb
CI: Test on Python 3.13t across OSs
effigies Oct 23, 2024
7b4165e
Add 3.13 without free-threading, reduce non-Linux build matrix
effigies Oct 23, 2024
2c22359
Do not update VIRTUAL_ENV
effigies Oct 23, 2024
afe4117
Install pip into tox environment
effigies Oct 23, 2024
3fbc2ef
Use tomllib over tomli when available
effigies Oct 23, 2024
2e4a124
Sync requirements.txt files
effigies Oct 23, 2024
30f324b
Compile min-requirements.txt
effigies Oct 23, 2024
2894a3e
TOX: Control pip via environment variables
effigies Oct 31, 2024
62012ef
Handle 3.13 better
effigies Oct 31, 2024
cf4ef06
Configure uv installation
effigies Oct 31, 2024
04c4d30
fix virtual environment
effigies Oct 31, 2024
1ad263e
chore(ci): Try another way to find the right Python
effigies Dec 7, 2024
b99ad93
chore(deps): Add missing and set min versions for optional deps
effigies Dec 7, 2024
ee09135
chore(tox): Use uv_resolution to run minimum tests
effigies Dec 7, 2024
1acb1fb
Define environment for py313t-full/pre
effigies Dec 7, 2024
6023c35
Use tox-gh-actions branch
effigies Dec 8, 2024
bcb9f2d
chore(ci): Test win32 with no extras for 3.9 and 3.13
effigies Dec 8, 2024
78a8878
chore(tox): Remove unused env vars
effigies Dec 8, 2024
91d2e42
chore(tox): Set PYTHONGIL from environment if found
effigies Dec 8, 2024
265257e
chore(ci): Update setup-uv version
effigies Dec 8, 2024
6cb49a3
chore(ci): Re-add arm64 exclusions
effigies Dec 8, 2024
81e2e9f
chore: Disable writing min-requirements from update_requirements.py
effigies Dec 8, 2024
6f77556
chore(ci): Restore x86 for Windows, will just drop mpl in tox
effigies Dec 8, 2024
85a6cfe
chore(tox): Drop mpl from x86, old numpy constraint
effigies Dec 8, 2024
5e4c4ae
chore(tox): Drop dev, pre is good enough
effigies Dec 8, 2024
76b809c
chore(tox): Rework default environments, extras
effigies Dec 8, 2024
821f34b
chore(ci): Improve version specification for uv
effigies Dec 8, 2024
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
72 changes: 52 additions & 20 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,31 +113,49 @@ jobs:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'windows-latest', 'macos-13', 'macos-latest']
python-version: ["3.9", "3.10", "3.11", "3.12"]
architecture: ['x64', 'x86', 'arm64']
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.13t"]
architecture: ['x86', 'x64', 'arm64']
dependencies: ['full', 'pre']
include:
# Basic dependencies only
- os: ubuntu-latest
python-version: 3.9
python-version: "3.9"
architecture: 'x64'
dependencies: 'none'
# Absolute minimum dependencies
- os: ubuntu-latest
python-version: 3.9
python-version: "3.9"
architecture: 'x64'
dependencies: 'min'
# NoGIL
- os: ubuntu-latest
python-version: '3.13-dev'
dependencies: 'dev'
exclude:
# x86 for Windows + Python<3.12
- os: ubuntu-latest
architecture: x86
# Use ubuntu-latest to cover the whole range of Python. For Windows
# and OSX, checking oldest and newest should be sufficient.
- os: windows-latest
python-version: "3.10"
- os: windows-latest
python-version: "3.11"
- os: windows-latest
python-version: "3.12"
- os: macos-13
python-version: "3.10"
- os: macos-13
python-version: "3.11"
- os: macos-13
python-version: "3.12"
- os: macos-latest
python-version: "3.10"
- os: macos-latest
python-version: "3.11"
- os: macos-latest
python-version: "3.12"

## Unavailable architectures
# x86 is available for Windows
- os: ubuntu-latest
architecture: x86
- os: macos-latest
architecture: x86
- python-version: '3.12'
- os: macos-13
architecture: x86
# arm64 is available for macos-14+
- os: ubuntu-latest
Expand All @@ -149,6 +167,8 @@ jobs:
# x64 is not available for macos-14+
- os: macos-latest
architecture: x64

## Reduced support
# Drop pre tests for macos-13
- os: macos-13
dependencies: pre
Expand All @@ -167,25 +187,37 @@ jobs:
with:
submodules: recursive
fetch-depth: 0
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v4
- name: Set up Python ${{ matrix.python-version }}
if: "!endsWith(matrix.python-version, '-dev')"
if: "!endsWith(matrix.python-version, 't')"
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }}
allow-prereleases: true
- name: Set up Python ${{ matrix.python-version }}
if: endsWith(matrix.python-version, '-dev')
uses: deadsnakes/[email protected]
with:
python-version: ${{ matrix.python-version }}
nogil: true
if: endsWith(matrix.python-version, 't')
run: |
uv python install ${IMPL}-${VERSION}-${OS%-*}-${ARCH}-${LIBC}
env:
IMPL: cpython
VERSION: ${{ matrix.python-version }}
# uv expects linux|macos|windows, we can drop the -* but need to rename ubuntu
OS: ${{ matrix.os == 'ubuntu-latest' && 'linux' || matrix.os }}
# uv expects x86, x86_64, aarch64 (among others)
ARCH: ${{ matrix.architecture == 'x64' && 'x86_64' ||
matrix.architecture == 'arm64' && 'aarch64' ||
matrix.architecture }}
# windows and macos have no options, gnu is the only option for the archs
LIBC: ${{ matrix.os == 'ubuntu-latest' && 'gnu' || 'none' }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: Install tox
run: |
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
uv tool install tox --with=git+https://github.com/effigies/tox-gh-actions@abiflags --with=tox-uv
env:
UV_PYTHON: ${{ matrix.python-version }}
- name: Show tox config
run: tox c
- name: Run tox
Expand Down
2 changes: 1 addition & 1 deletion doc-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Auto-generated by tools/update_requirements.py
-r requirements.txt
sphinx
matplotlib>=1.5.3
matplotlib>=3.5
numpydoc
texext
tomli; python_version < '3.11'
20 changes: 16 additions & 4 deletions min-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
# Auto-generated by tools/update_requirements.py
numpy ==1.20
packaging ==17
importlib_resources ==1.3; python_version < '3.9'
# This file was autogenerated by uv via the following command:
# uv pip compile --resolution lowest-direct --python 3.9 -o min-requirements.txt pyproject.toml
importlib-resources==5.12.0
# via nibabel (pyproject.toml)
numpy==1.22.0
# via nibabel (pyproject.toml)
packaging==20.0
# via nibabel (pyproject.toml)
pyparsing==3.2.0
# via packaging
six==1.16.0
# via packaging
typing-extensions==4.6.0
# via nibabel (pyproject.toml)
zipp==3.20.2
# via importlib-resources
27 changes: 16 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ nib-roi = "nibabel.cmdline.roi:main"
parrec2nii = "nibabel.cmdline.parrec2nii:main"

[project.optional-dependencies]
all = ["nibabel[dicomfs,minc2,spm,zstd]"]
all = ["nibabel[dicomfs,indexed_gzip,minc2,spm,zstd]"]
# Features
indexed_gzip = ["indexed_gzip >=1.6"]
dicom = ["pydicom >=2.3"]
dicomfs = ["nibabel[dicom]", "pillow"]
minc2 = ["h5py"]
spm = ["scipy"]
zstd = ["pyzstd >= 0.14.3"]
dicomfs = ["nibabel[dicom]", "pillow >=8.4"]
minc2 = ["h5py >=3.5"]
spm = ["scipy >=1.8"]
viewers = ["matplotlib >=3.5"]
zstd = ["pyzstd >=0.15.2"]
# For doc and test, make easy to use outside of tox
# tox should use these with extras instead of duplicating
doc = [
Expand All @@ -68,12 +70,12 @@ doc = [
"tomli; python_version < '3.11'",
]
test = [
"pytest",
"pytest-doctestplus",
"pytest-cov",
"pytest-httpserver",
"pytest-xdist",
"coverage>=7.2",
"pytest >=6",
"pytest-doctestplus >=1",
"pytest-cov >=2.11",
"pytest-httpserver >=1.0.7",
"pytest-xdist >=3.5",
"coverage[toml]>=7.2",
]
# Remaining: Simpler to centralize in tox
dev = ["tox"]
Expand Down Expand Up @@ -200,3 +202,6 @@ enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
[tool.codespell]
skip = "*/data/*,./nibabel-data"
ignore-words-list = "ans,te,ue,ist,nin,nd,ccompiler,ser"

[tool.uv.pip]
only-binary = ["numpy", "scipy", "h5py"]
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Auto-generated by tools/update_requirements.py
numpy >=1.20
packaging >=17
importlib_resources >=1.3; python_version < '3.9'
numpy >=1.22
packaging >=20
importlib_resources >=5.12; python_version < '3.12'
typing_extensions >=4.6; python_version < '3.13'
14 changes: 9 additions & 5 deletions tools/update_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import sys
from pathlib import Path

import tomli
try:
import tomllib
except ImportError:
import tomli as tomllib

if sys.version_info < (3, 6):
print('This script requires Python 3.6 to work correctly')
Expand All @@ -15,7 +18,7 @@
doc_reqs = repo_root / 'doc-requirements.txt'

with open(pyproject_toml, 'rb') as fobj:
config = tomli.load(fobj)
config = tomllib.load(fobj)
requirements = config['project']['dependencies']
doc_requirements = config['project']['optional-dependencies']['doc']

Expand All @@ -27,9 +30,10 @@
lines[1:-1] = requirements
reqs.write_text('\n'.join(lines))

# Write minimum requirements
lines[1:-1] = [req.replace('>=', '==').replace('~=', '==') for req in requirements]
min_reqs.write_text('\n'.join(lines))
# # Write minimum requirements
# lines[1:-1] = [req.replace('>=', '==').replace('~=', '==') for req in requirements]
# min_reqs.write_text('\n'.join(lines))
print(f"To update {min_reqs.name}, use `uv pip compile` (see comment at top of file).")

# Write documentation requirements
lines[1:-1] = ['-r requirements.txt'] + doc_requirements
Expand Down
97 changes: 44 additions & 53 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@
[tox]
requires =
tox>=4
tox-uv
envlist =
# No preinstallations
py3{9,10,11,12,13}-none
# Minimum Python
py39-{min,full}
# x86 support range
py3{9,10,11}-{full,pre}-{x86,x64}
py3{9,10,11}-pre-{x86,x64}
# x64-only range
py3{12,13}-{full,pre}-x64
# Special environment for numpy 2.0-dev testing
py313-dev-x64
py3{9,10,11,12,13,13t}-none
# Minimum Python with minimum deps
py39-min
# Run full and pre dependencies against all archs
py3{9,10,11,12,13,13t}-{full,pre}-{x86,x64,arm64}
install
doctest
style
Expand All @@ -31,12 +27,12 @@ python =
3.11: py311
3.12: py312
3.13: py313
3.13t: py313t

[gh-actions:env]
DEPENDS =
none: none, install
none: none
pre: pre
dev: dev
full: full, install
min: min

Expand All @@ -48,14 +44,8 @@ ARCH =
[testenv]
description = Pytest with coverage
labels = test
install_command =
python -I -m pip install -v \
dev: --only-binary numpy,scipy,h5py \
!dev: --only-binary numpy,scipy,h5py,pillow,matplotlib \
pre,dev: --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple \
{opts} {packages}
pip_pre =
pre,dev: true
pre: true
pass_env =
# getpass.getuser() sources for Windows:
LOGNAME
Expand All @@ -71,40 +61,42 @@ pass_env =
CLICOLOR
CLICOLOR_FORCE
set_env =
py313: PYTHON_GIL=0
extras = test
pre: PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
pre: UV_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
py313t: PYTHONGIL={env:PYTHONGIL:0}
extras =
test

# Simple, thanks Hugo and Paul
!none: dicomfs
!none: indexed_gzip

# Minimum dependencies
min: minc2
min: spm
min: viewers
min: zstd

# Matplotlib has wheels for everything except win32 (x86)
{full,pre}-{x,arm}64: viewers

# Nightly, but not released cp313t wheels for: scipy
# When released, remove the py3* line and add full to the pre line
py3{9,10,11,12,13}-full-{x,arm}64: spm
pre-{x,arm}64: spm

# No cp313t wheels for: h5py, pyzstd
py3{9,10,11,12,13}-{full,pre}-{x,arm}64: minc2
py3{9,10,11,12,13}-{full,pre}-{x,arm}64: zstd

# win32 (x86) wheels still exist for scipy+py39
py39-full-x86: spm

deps =
# General minimum dependencies: pin based on API usage
# matplotlib 3.5 requires packaging 20
min: packaging ==20
min: importlib_resources ==5.12; python_version < '3.12'
min: typing_extensions ==4.6; python_version < '3.13'
# NEP29/SPEC0 + 1yr: Test on minor release series within the last 3 years
# We're extending this to all optional dependencies
# This only affects the range that we test on; numpy is the only non-optional
# dependency, and will be the only one to affect pip environment resolution.
min: numpy ==1.22
min: h5py ==3.5
min: indexed_gzip ==1.6
min: matplotlib ==3.5
min: pillow ==8.4
min: pydicom ==2.3
min: pyzstd ==0.15.2
min: scipy ==1.8
# Numpy 2.0 is a major breaking release; we cannot put much effort into
# supporting until it's at least RC stable
dev: numpy >=2.1.dev0
# Scipy stopped producing win32 wheels at py310
py39-full-x86,x64,arm64: scipy >=1.8
# Matplotlib depends on scipy, so cannot be built for py310 on x86
py39-full-x86,x64,arm64: matplotlib >=3.5
# h5py stopped producing win32 wheels at py39
{full,pre}-{x64,arm64}: h5py >=3.5
full,pre,dev: pillow >=8.4
full,pre: indexed_gzip >=1.6
full,pre,dev: pyzstd >=0.15.2
full,pre: pydicom >=2.3
dev: pydicom @ git+https://github.com/pydicom/pydicom.git@main
pre: pydicom @ git+https://github.com/pydicom/pydicom.git@main

uv_resolution =
min: lowest-direct

commands =
pytest --doctest-modules --doctest-plus \
Expand All @@ -118,7 +110,6 @@ description = Install and verify import succeeds
labels = test
deps =
extras =
install_command = python -I -m pip install {opts} {packages}
commands =
python -c "import nibabel; print(nibabel.__version__)"

Expand Down
Loading