Skip to content

Commit

Permalink
Merge pull request #1381 from effigies/py313
Browse files Browse the repository at this point in the history
Add broad testing for Python 3.13
  • Loading branch information
effigies authored Jan 12, 2025
2 parents b6ca0d6 + 1e8043d commit f81f5a7
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 97 deletions.
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: |
echo "UV_PYTHON=${IMPL}-${VERSION}-${OS%-*}-${ARCH}-${LIBC}" >> $GITHUB_ENV
source $GITHUB_ENV
uv python install $UV_PYTHON
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 -v tox --with=git+https://github.com/effigies/tox-gh-actions@abiflags --with=tox-uv
- 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
99 changes: 46 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 @@ -70,41 +60,45 @@ pass_env =
NO_COLOR
CLICOLOR
CLICOLOR_FORCE
# uv needs help in this case
py313t-x86: UV_PYTHON
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 +112,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

0 comments on commit f81f5a7

Please sign in to comment.