Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nipy/nibabel
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5.3.1
Choose a base ref
...
head repository: nipy/nibabel
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Loading
Showing with 489 additions and 351 deletions.
  1. +4 −0 .git-blame-ignore-revs
  2. +53 −21 .github/workflows/test.yml
  3. +4 −7 .pre-commit-config.yaml
  4. +21 −0 .readthedocs.yaml
  5. +14 −3 Changelog
  6. +1 −2 bin/parrec2nii
  7. +1 −1 doc-requirements.txt
  8. +16 −4 min-requirements.txt
  9. +25 −0 nibabel/_typing.py
  10. +3 −2 nibabel/arrayproxy.py
  11. +8 −7 nibabel/benchmarks/bench_array_to_file.py
  12. +2 −2 nibabel/benchmarks/bench_arrayproxy_slicing.py
  13. +5 −4 nibabel/benchmarks/bench_finite_range.py
  14. +8 −7 nibabel/benchmarks/bench_load_save.py
  15. +1 −1 nibabel/benchmarks/butils.py
  16. +1 −1 nibabel/brikhead.py
  17. +1 −2 nibabel/cifti2/cifti2.py
  18. +4 −2 nibabel/cifti2/cifti2_axes.py
  19. +1 −2 nibabel/cifti2/parse_cifti2.py
  20. +1 −1 nibabel/cmdline/dicomfs.py
  21. +3 −3 nibabel/cmdline/diff.py
  22. +2 −2 nibabel/cmdline/ls.py
  23. +2 −2 nibabel/cmdline/tests/test_conform.py
  24. +28 −8 nibabel/cmdline/tests/test_utils.py
  25. +16 −36 nibabel/cmdline/utils.py
  26. +1 −1 nibabel/data.py
  27. +5 −6 nibabel/dataobj_images.py
  28. +3 −3 nibabel/deprecated.py
  29. +1 −1 nibabel/deprecator.py
  30. +10 −16 nibabel/filebasedimages.py
  31. +1 −2 nibabel/filename_parser.py
  32. +6 −1 nibabel/freesurfer/mghformat.py
  33. +2 −2 nibabel/freesurfer/tests/test_mghformat.py
  34. +1 −1 nibabel/gifti/gifti.py
  35. +3 −3 nibabel/gifti/tests/test_parse_gifti_fast.py
  36. +7 −4 nibabel/loadsave.py
  37. +22 −9 nibabel/nicom/dicomwrappers.py
  38. +33 −18 nibabel/nicom/tests/test_dicomwrappers.py
  39. +2 −2 nibabel/nicom/tests/test_utils.py
  40. +4 −9 nibabel/nifti1.py
  41. +3 −2 nibabel/openers.py
  42. +4 −4 nibabel/parrec.py
  43. +3 −3 nibabel/pointset.py
  44. +6 −1 nibabel/processing.py
  45. +1 −1 nibabel/rstutils.py
  46. +9 −8 nibabel/spatialimages.py
  47. +1 −2 nibabel/streamlines/__init__.py
  48. +1 −1 nibabel/streamlines/array_sequence.py
  49. +1 −1 nibabel/streamlines/tests/test_array_sequence.py
  50. +1 −1 nibabel/streamlines/trk.py
  51. +2 −2 nibabel/tests/data/check_parrec_reslice.py
  52. +1 −1 nibabel/tests/test_analyze.py
  53. +1 −1 nibabel/tests/test_deprecator.py
  54. +5 −5 nibabel/tests/test_fileslice.py
  55. +6 −6 nibabel/tests/test_funcs.py
  56. +1 −1 nibabel/tests/test_image_types.py
  57. +2 −2 nibabel/tests/test_loadsave.py
  58. +9 −9 nibabel/tests/test_nifti1.py
  59. +5 −2 nibabel/tests/test_processing.py
  60. +4 −0 nibabel/tests/test_proxy_api.py
  61. +3 −3 nibabel/tests/test_scripts.py
  62. +3 −3 nibabel/tests/test_spatialimages.py
  63. +3 −3 nibabel/viewers.py
  64. +10 −13 nibabel/volumeutils.py
  65. +18 −17 pyproject.toml
  66. +4 −3 requirements.txt
  67. +9 −5 tools/update_requirements.py
  68. +47 −53 tox.ini
4 changes: 4 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Sun Jan 12 12:22:13 2025 -0500 - markiewicz@stanford.edu - sty: ruff format [git-blame-ignore-rev]
40e41208a0f04063b3c4e373a65da1a2a6a275b5
# Sun Jan 12 11:51:49 2025 -0500 - markiewicz@stanford.edu - STY: ruff format [git-blame-ignore-rev]
7e5d584910c67851dcfcd074ff307122689b61f5
# Sun Jan 1 12:38:02 2023 -0500 - effigies@gmail.com - STY: Run pre-commit config on all files
d14c1cf282a9c3b19189f490f10c35f5739e24d1
# Thu Dec 29 22:53:17 2022 -0500 - effigies@gmail.com - STY: Reduce array().astype() and similar constructs
74 changes: 53 additions & 21 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -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
@@ -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
@@ -167,30 +187,42 @@ jobs:
with:
submodules: recursive
fetch-depth: 0
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v6
- 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/action@v3.2.0
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
run: tox -vv --exit-and-dump-after 1200
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@v5
if: ${{ always() }}
with:
files: cov.xml
11 changes: 4 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
exclude: ".*/data/.*"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -13,18 +13,15 @@ repos:
- id: check-merge-conflict
- id: check-vcs-permalinks
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.4
rev: v0.9.6
hooks:
- id: ruff
args: [ --fix ]
exclude: = ["doc", "tools"]
- id: ruff-format
exclude: = ["doc", "tools"]
- id: ruff
args: [ --select, ISC001, --fix ]
exclude: = ["doc", "tools"]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
rev: v1.15.0
hooks:
- id: mypy
# Sync with project.optional-dependencies.typing
@@ -39,7 +36,7 @@ repos:
args: ["nibabel"]
pass_filenames: false
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
rev: v2.4.1
hooks:
- id: codespell
additional_dependencies:
21 changes: 21 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2

build:
os: ubuntu-lts-latest
tools:
python: latest
jobs:
pre_create_environment:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
create_environment:
- uv venv $READTHEDOCS_VIRTUALENV_PATH
install:
# Use a cache dir in the same mount to halve the install time
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH uv pip install --cache-dir $READTHEDOCS_VIRTUALENV_PATH/../../uv_cache .[doc]
pre_build:
- ( cd doc; python tools/build_modref_templates.py nibabel source/reference False )

sphinx:
configuration: doc/source/conf.py
17 changes: 14 additions & 3 deletions Changelog
Original file line number Diff line number Diff line change
@@ -25,6 +25,17 @@ Eric Larson (EL), Demian Wassermann, Stephan Gerhard and Ross Markello (RM).

References like "pr/298" refer to github pull request numbers.

5.3.2 (Wednesday 23 October 2024)
=================================

Bug-fix release in the 5.3.x series.

Bug fixes
---------
* Restore MRS extension type to Nifti1Extension to maintain backwards compatibility.
(pr/1380) (CM)


5.3.1 (Tuesday 15 October 2024)
===============================

@@ -46,9 +57,9 @@ NiBabel 6.0 will drop support for Numpy 1.x.

New features
------------
* Update NIfTI extension protocol to include ``.content : bytes``, ``.text : str`` and ``.json : dict``
properties for accessing extension contents. Exceptions will be raised on ``.text`` and ``.json`` if
conversion fails. (pr/1336) (CM)
* Update NIfTI extension protocol to include ``.content : bytes``, ``.text : str`` and
``.json() : dict`` properties/methods for accessing extension contents.
Exceptions will be raised on ``.text`` and ``.json()`` if conversion fails. (pr/1336) (CM)

Enhancements
------------
3 changes: 1 addition & 2 deletions bin/parrec2nii
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!python
"""PAR/REC to NIfTI converter
"""
"""PAR/REC to NIfTI converter"""

from nibabel.cmdline.parrec2nii import main

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
25 changes: 25 additions & 0 deletions nibabel/_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Helpers for typing compatibility across Python versions"""

import sys

if sys.version_info < (3, 10):
from typing_extensions import ParamSpec
else:
from typing import ParamSpec

if sys.version_info < (3, 11):
from typing_extensions import Self
else:
from typing import Self

if sys.version_info < (3, 13):
from typing_extensions import TypeVar
else:
from typing import TypeVar


__all__ = [
'ParamSpec',
'Self',
'TypeVar',
]
5 changes: 3 additions & 2 deletions nibabel/arrayproxy.py
Original file line number Diff line number Diff line change
@@ -59,10 +59,11 @@

if ty.TYPE_CHECKING:
import numpy.typing as npt
from typing_extensions import Self # PY310

from ._typing import Self, TypeVar

# Taken from numpy/__init__.pyi
_DType = ty.TypeVar('_DType', bound=np.dtype[ty.Any])
_DType = TypeVar('_DType', bound=np.dtype[ty.Any])


class ArrayLike(ty.Protocol):
15 changes: 8 additions & 7 deletions nibabel/benchmarks/bench_array_to_file.py
Original file line number Diff line number Diff line change
@@ -29,24 +29,25 @@ def bench_array_to_file():
sys.stdout.flush()
print_git_title('\nArray to file')
mtime = measure('array_to_file(arr, BytesIO(), np.float32)', repeat)
print('%30s %6.2f' % ('Save float64 to float32', mtime))
fmt = '{:30s} {:6.2f}'.format
print(fmt('Save float64 to float32', mtime))
mtime = measure('array_to_file(arr, BytesIO(), np.int16)', repeat)
print('%30s %6.2f' % ('Save float64 to int16', mtime))
print(fmt('Save float64 to int16', mtime))
# Set a lot of NaNs to check timing
arr[:, :, :, 1] = np.nan
mtime = measure('array_to_file(arr, BytesIO(), np.float32)', repeat)
print('%30s %6.2f' % ('Save float64 to float32, NaNs', mtime))
print(fmt('Save float64 to float32, NaNs', mtime))
mtime = measure('array_to_file(arr, BytesIO(), np.int16)', repeat)
print('%30s %6.2f' % ('Save float64 to int16, NaNs', mtime))
print(fmt('Save float64 to int16, NaNs', mtime))
# Set a lot of infs to check timing
arr[:, :, :, 1] = np.inf
mtime = measure('array_to_file(arr, BytesIO(), np.float32)', repeat)
print('%30s %6.2f' % ('Save float64 to float32, infs', mtime))
print(fmt('Save float64 to float32, infs', mtime))
mtime = measure('array_to_file(arr, BytesIO(), np.int16)', repeat)
print('%30s %6.2f' % ('Save float64 to int16, infs', mtime))
print(fmt('Save float64 to int16, infs', mtime))
# Int16 input, float output
arr = np.random.random_integers(low=-1000, high=1000, size=img_shape)
arr = arr.astype(np.int16)
mtime = measure('array_to_file(arr, BytesIO(), np.float32)', repeat)
print('%30s %6.2f' % ('Save Int16 to float32', mtime))
print(fmt('Save Int16 to float32', mtime))
sys.stdout.flush()
4 changes: 2 additions & 2 deletions nibabel/benchmarks/bench_arrayproxy_slicing.py
Original file line number Diff line number Diff line change
@@ -96,10 +96,10 @@ def fmt_sliceobj(sliceobj):
slcstr.append(s)
else:
slcstr.append(str(int(s * SHAPE[i])))
return f"[{', '.join(slcstr)}]"
return f'[{", ".join(slcstr)}]'

with InTemporaryDirectory():
print(f'Generating test data... ({int(round(np.prod(SHAPE) * 4 / 1048576.0))} MB)')
print(f'Generating test data... ({round(np.prod(SHAPE) * 4 / 1048576.0)} MB)')

data = np.array(np.random.random(SHAPE), dtype=np.float32)

9 changes: 5 additions & 4 deletions nibabel/benchmarks/bench_finite_range.py
Original file line number Diff line number Diff line change
@@ -28,16 +28,17 @@ def bench_finite_range():
sys.stdout.flush()
print_git_title('\nFinite range')
mtime = measure('finite_range(arr)', repeat)
print('%30s %6.2f' % ('float64 all finite', mtime))
fmt = '{:30s} {:6.2f}'.format
print(fmt('float64 all finite', mtime))
arr[:, :, :, 1] = np.nan
mtime = measure('finite_range(arr)', repeat)
print('%30s %6.2f' % ('float64 many NaNs', mtime))
print(fmt('float64 many NaNs', mtime))
arr[:, :, :, 1] = np.inf
mtime = measure('finite_range(arr)', repeat)
print('%30s %6.2f' % ('float64 many infs', mtime))
print(fmt('float64 many infs', mtime))
# Int16 input, float output
arr = np.random.random_integers(low=-1000, high=1000, size=img_shape)
arr = arr.astype(np.int16)
mtime = measure('finite_range(arr)', repeat)
print('%30s %6.2f' % ('int16', mtime))
print(fmt('int16', mtime))
sys.stdout.flush()
Loading