Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
dependencies: [latest, pre]
include:
- python-version: "3.9"
- python-version: "3.10"
dependencies: min
exclude:
# Do not test pre-releases for versions out of SPEC0
- python-version: "3.9"
dependencies: pre
- python-version: "3.10"
dependencies: pre
- python-version: "3.11"
dependencies: pre

env:
DEPENDS: ${{ matrix.dependencies }}
Expand Down
2 changes: 1 addition & 1 deletion niworkflows/func/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

bold_datasets = [[str((datapath / p).absolute()) for p in ds] for ds in bold_datasets]

parameters = zip(bold_datasets, exp_masks)
parameters = zip(bold_datasets, exp_masks, strict=False)

if not bold_datasets:
raise RuntimeError(
Expand Down
14 changes: 2 additions & 12 deletions niworkflows/interfaces/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import os
import re
import shutil
import sys
from collections import defaultdict
from contextlib import suppress
from json import dumps, loads
Expand Down Expand Up @@ -66,15 +65,6 @@
LOGGER = logging.getLogger('nipype.interface')


if sys.version_info < (3, 10): # PY39
builtin_zip = zip

def zip(*args, strict=False): # noqa: A001
if strict and any(len(args[0]) != len(arg) for arg in args):
raise ValueError('strict_zip() requires all arguments to have the same length')
return builtin_zip(*args)


def _none():
return None

Expand Down Expand Up @@ -629,7 +619,7 @@ def _run_interface(self, runtime):
self._results['out_path'] = dest_files
self._results['out_meta'] = metadata

for i, (orig_file, dest_file) in enumerate(zip(in_file, dest_files)):
for i, (orig_file, dest_file) in enumerate(zip(in_file, dest_files, strict=False)):
# Set data and header iff changes need to be made. If these are
# still None when it's time to write, just copy.
new_data, new_header = None, None
Expand Down Expand Up @@ -1132,7 +1122,7 @@ def _run_interface(self, runtime):
f'by interpolated patterns ({len(dest_files)}).'
)

for i, (orig_file, dest_file) in enumerate(zip(in_file, dest_files)):
for i, (orig_file, dest_file) in enumerate(zip(in_file, dest_files, strict=False)):
out_file = out_path / dest_file
out_file.parent.mkdir(exist_ok=True, parents=True)
self._results['out_file'].append(str(out_file))
Expand Down
2 changes: 1 addition & 1 deletion niworkflows/interfaces/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def spike_regressors(
post_final = data.shape[0] + 1
epoch_length = np.diff(sorted(mask | {-1, post_final})) - 1
epoch_end = sorted(mask | {post_final})
for end, length in zip(epoch_end, epoch_length):
for end, length in zip(epoch_end, epoch_length, strict=False):
if length < minimum_contiguous:
mask = mask | set(range(end - length, end))
mask = mask.intersection(indices)
Expand Down
4 changes: 3 additions & 1 deletion niworkflows/interfaces/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,9 @@ def _run_interface(self, runtime):
self._results['out_file'] = fname(suffix='_average')
self._results['out_volumes'] = fname(suffix='_sliced')

sliced = nb.concat_images(i for i, t in zip(nb.four_to_three(img), t_mask) if t)
sliced = nb.concat_images(
i for i, t in zip(nb.four_to_three(img), t_mask, strict=False) if t
)

data = sliced.get_fdata(dtype='float32')
# Data can come with outliers showing very high numbers - preemptively prune
Expand Down
8 changes: 5 additions & 3 deletions niworkflows/interfaces/itk.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def _run_interface(self, runtime):
if num_threads == 1:
out_files = [
_applytfms((in_file, in_xfm, ifargs, i, runtime.cwd))
for i, (in_file, in_xfm) in enumerate(zip(in_files, xfms_list))
for i, (in_file, in_xfm) in enumerate(zip(in_files, xfms_list, strict=False))
]
else:
from concurrent.futures import ThreadPoolExecutor
Expand All @@ -152,7 +152,9 @@ def _run_interface(self, runtime):
_applytfms,
[
(in_file, in_xfm, ifargs, i, runtime.cwd)
for i, (in_file, in_xfm) in enumerate(zip(in_files, xfms_list))
for i, (in_file, in_xfm) in enumerate(
zip(in_files, xfms_list, strict=False)
)
],
)
)
Expand Down Expand Up @@ -264,4 +266,4 @@ def _arrange_xfms(transforms, num_files, tmp_folder):
xfms_T.append(split_xfms)

# Transpose back (only Python 3)
return list(map(list, zip(*xfms_T)))
return list(map(list, zip(*xfms_T, strict=False)))
1 change: 1 addition & 0 deletions niworkflows/interfaces/surf.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ def ply2gii(in_file, metadata, out_file=None):
zip(
('SurfaceCenterX', 'SurfaceCenterY', 'SurfaceCenterZ'),
[f'{c:.4f}' for c in surf.centroid],
strict=False,
)
)

Expand Down
6 changes: 3 additions & 3 deletions niworkflows/interfaces/tests/test_bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,10 @@ def test_DerivativesDataSink_build_path(
]

base = (out_path_base or 'niworkflows') if interface == bintfs.DerivativesDataSink else ''
for out, exp in zip(output, expectation):
for out, exp in zip(output, expectation, strict=False):
assert Path(out).relative_to(base_directory) == Path(base) / exp

for out, exp in zip(output, expectation):
for out, exp in zip(output, expectation, strict=False):
assert Path(out).relative_to(base_directory) == Path(base) / exp
# Regression - some images were given nan scale factors
if out.endswith(('.nii', '.nii.gz')):
Expand All @@ -374,7 +374,7 @@ def test_DerivativesDataSink_build_path(
hdr = img.header.from_fileobj(fobj)
assert not np.isnan(hdr['scl_slope'])
assert not np.isnan(hdr['scl_inter'])
for out, chksum in zip(output, checksum):
for out, chksum in zip(output, checksum, strict=False):
if chksum == '335f1394ce90b58bbf27026b6eeec4d2124c11da':
if Version(nb.__version__) < Version('5.3'):
# Nibabel 5.3 avoids unnecessary roundtrips for Cifti2Headers
Expand Down
2 changes: 1 addition & 1 deletion niworkflows/interfaces/tests/test_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def test_TemplateDimensions(tmp_path):
(0.9, 0.9, 0.9),
]

for i, (shape, zoom) in enumerate(zip(shapes, zooms)):
for i, (shape, zoom) in enumerate(zip(shapes, zooms, strict=False)):
img = nb.Nifti1Image(np.ones(shape, dtype='float32'), np.eye(4))
img.header.set_zooms(zoom)
img.to_filename(tmp_path / f'test{i}.nii')
Expand Down
2 changes: 1 addition & 1 deletion niworkflows/interfaces/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def _run_interface(self, runtime):
raise ValueError('Number of columns in datasets do not match')

merged = []
for d, j in zip(data, join):
for d, j in zip(data, join, strict=False):
line = '%s\t%s' % ((j, d) if self.inputs.side == 'left' else (d, j))
merged.append(line)

Expand Down
4 changes: 3 additions & 1 deletion niworkflows/reports/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,9 @@ def generate_reports(

logger = logging.getLogger('cli')
error_list = ', '.join(
f'{subid} ({err})' for subid, err in zip(subject_list, report_errors) if err
f'{subid} ({err})'
for subid, err in zip(subject_list, report_errors, strict=False)
if err
)
logger.error(
'Preprocessing did not finish successfully. Errors occurred while processing '
Expand Down
4 changes: 2 additions & 2 deletions niworkflows/tests/test_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_carpetplot(tr, sorting):
rng.shuffle(indexes)
segments = {}
start = 0
for group, size in zip(labels, sizes):
for group, size in zip(labels, sizes, strict=False):
segments[group] = indexes[start : start + size]
data[indexes[start : start + size]] = rng.normal(
rng.standard_normal(1) * 100, rng.normal(20, 5, size=1), size=(size, 300)
Expand Down Expand Up @@ -100,7 +100,7 @@ def test_carpetplot(tr, sorting):
rng.shuffle(indexes)
segments = {}
start = 0
for i, (group, size) in enumerate(zip(labels, sizes)):
for i, (group, size) in enumerate(zip(labels, sizes, strict=False)):
segments[group] = indexes[start : start + size]
data[indexes[start : start + size]] = i
start += size
Expand Down
2 changes: 1 addition & 1 deletion niworkflows/utils/spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,4 +805,4 @@ def _expand_entities(entities):
"""
keys = list(entities.keys())
values = list(product(*[entities[k] for k in keys]))
return [dict(zip(keys, combs)) for combs in values]
return [dict(zip(keys, combs, strict=False)) for combs in values]
2 changes: 1 addition & 1 deletion niworkflows/utils/tests/test_spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def test_space_action(parser, spaces, expected):
'Every element must be a `Reference`'
)
assert len(parsed_spaces.references) == len(expected)
for ref, expected_ref in zip(parsed_spaces.references, expected):
for ref, expected_ref in zip(parsed_spaces.references, expected, strict=False):
assert str(ref) == expected_ref


Expand Down
2 changes: 1 addition & 1 deletion niworkflows/viz/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ def compcor_variance_plot(
metadata_sources = ['CompCor']
else:
metadata_sources = [f'Decomposition {i:d}' for i in range(len(metadata_files))]
for file, source in zip(metadata_files, metadata_sources):
for file, source in zip(metadata_files, metadata_sources, strict=False):
metadata[source] = pd.read_csv(str(file), sep=r'\s+')
metadata[source]['source'] = source
metadata = pd.concat(list(metadata.values()))
Expand Down
4 changes: 2 additions & 2 deletions niworkflows/viz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def cuts_from_bbox(mask_nii, cuts=3):

vox_coords = np.zeros((4, cuts), dtype=np.float32)
vox_coords[-1, :] = 1.0
for ax, (c, th) in enumerate(zip(ijk_counts, ijk_th)):
for ax, (c, th) in enumerate(zip(ijk_counts, ijk_th, strict=False)):
# Start with full plane if mask is seemingly empty
smin, smax = (0, mask_data.shape[ax] - 1)

Expand All @@ -198,7 +198,7 @@ def cuts_from_bbox(mask_nii, cuts=3):
vox_coords[ax, :] = np.linspace(smin, smax, num=cuts + 2)[1:-1]

ras_coords = mask_nii.affine.dot(vox_coords)[:3, ...]
return {k: list(v) for k, v in zip(['x', 'y', 'z'], np.around(ras_coords, 3))}
return {k: list(v) for k, v in zip(['x', 'y', 'z'], np.around(ras_coords, 3), strict=False)}


def _3d_in_file(in_file):
Expand Down
83 changes: 62 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,37 @@ description = "NeuroImaging Workflows provides processing tools for magnetic res
readme = "README.rst"
license = "Apache-2.0"
license-files = ["LICENSE"]
requires-python = ">= 3.9"
requires-python = ">= 3.10"
authors = [
{ name = "The NiPreps Developers", email = "[email protected]" },
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering :: Image Recognition",
]
dependencies = [
"acres",
"attrs >=20.1",
"acres >=0.5",
"attrs >=23.1",
"jinja2 >=3",
"looseversion",
"matplotlib >= 3.5",
"nibabel >= 3.0",
"nilearn >= 0.8",
"nipype >= 1.8.5",
"nitransforms >= 22.0.0",
"numpy >= 1.20",
"looseversion >=1.3",
"matplotlib >= 3.7",
"nibabel >= 5.0",
"nilearn >= 0.10",
"nipype >= 1.9.1",
"nitransforms >= 23.0.0",
"numpy >= 1.24",
"packaging",
"pandas >= 1.2",
"pybids >= 0.15.1",
"PyYAML >= 5.4",
"scikit-image >= 0.18",
"scipy >= 1.8",
"seaborn >= 0.11",
"pandas >= 2.0",
"pybids >= 0.16",
"pyyaml >= 6.0",
"scikit-image >= 0.20",
"scipy >= 1.10",
"seaborn >= 0.13",
"svgutils >= 0.3.4",
"templateflow >= 23.1",
"transforms3d >= 0.4",
Expand All @@ -62,11 +61,11 @@ style = [
"flake8 >= 3.7.0",
]
tests = [
"coverage[toml] >=5.2.1",
"pytest >= 6",
"pytest-cov >= 2.11",
"coverage[toml] >=7",
"pytest >= 8",
"pytest-cov >= 7",
"pytest-env",
"pytest-xdist >= 2.5",
"pytest-xdist >= 3.8",
"pytest-xvfb >= 2",
]
# Aliases
Expand Down Expand Up @@ -226,3 +225,45 @@ source = [
[tool.codespell]
skip = "*/data/*,*/docs/_build/*,./examples/viz-report.*"
ignore-words-list = "objekt,nd"

[tool.pixi.workspace]
channels = ["https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public", "conda-forge"]
platforms = ["linux-64"]

[tool.pixi.feature.niworkflows.activation.env]
FSLDIR = "$CONDA_PREFIX"

[tool.pixi.pypi-dependencies]
niworkflows = { path = ".", editable = true }

[tool.pixi.environments]
default = { features = ["editable"], solve-group = "default" }
test = { features = ["editable", "tests"], solve-group = "default" }
niworkflows = { features = ["production"], solve-group = "production" }

[tool.pixi.feature.editable.pypi-dependencies]
niworkflows = { path = ".", editable = true }
[tool.pixi.feature.production.pypi-dependencies]
niworkflows = { path = ".", editable = false }

[tool.pixi.tasks]

[tool.pixi.dependencies]
python = "3.12.*"
mkl = "2024.2.2.*"
mkl-service = "2.4.2.*"
numpy = "1.26.*"
scipy = "1.15.*"
matplotlib = "3.9.*"
pandas = "2.2.*"
h5py = "3.13.*"
scikit-image = "0.25.*"
scikit-learn = "1.6.*"
graphviz = "11.0.*"
ants = "2.5.*"
libitk = "5.4.0.*"
fsl-bet2 = "2111.8.*"
fsl-flirt = "2111.2.*"
fsl-fast4 = "2111.3.*"
fsl-mcflirt = "2111.0.*"
fsl-miscmaths = "2203.2.*"
9 changes: 3 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
requires =
tox>=4
envlist =
py3{9,10,11,12,13}-latest
py39-min
py3{10,11,12,13}-pre
py3{10,11,12,13,14}-{latest,pre}
py310-min
skip_missing_interpreters = true

# Configuration that allows us to split tests across GitHub runners effectively
[gh-actions]
python =
3.9: py39
3.10: py310
3.11: py311
3.12: py312
3.13: py313
3.14: py314

[gh-actions:env]
DEPENDS =
Expand Down Expand Up @@ -54,8 +53,6 @@ pass_env =
CLICOLOR
CLICOLOR_FORCE
PYTHON_GIL
deps =
py313: traits @ git+https://github.com/enthought/traits.git@10954eb
extras = tests
setenv =
pre: PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
Expand Down
Loading