Skip to content

Commit 79139f1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into enh/improve-jupyter-notebook
2 parents 9890cc3 + d05517d commit 79139f1

File tree

9 files changed

+83
-17
lines changed

9 files changed

+83
-17
lines changed

.zenodo.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
"name": "Eilidh MacNicol",
3838
"type": "Researcher"
3939
},
40+
{
41+
"orcid": "0000-0002-8888-1572",
42+
"affiliation": "Speech & Hearing Bioscience & Technology Program, Harvard University",
43+
"name": "Steven Meisler",
44+
"type": "Researcher"
45+
},
4046
{
4147
"orcid": "0000-0001-9049-0135",
4248
"affiliation": "Perelman School of Medicine, University of Pennsylvania, PA, USA",
@@ -49,12 +55,6 @@
4955
"name": "Kevin R. Sitek",
5056
"type": "Researcher"
5157
},
52-
{
53-
"orcid": "0000-0002-8888-1572",
54-
"affiliation": "Speech & Hearing Bioscience & Technology Program, Harvard University",
55-
"name": "Steven L. Meisler",
56-
"type": "Researcher"
57-
},
5858
{
5959
"orcid": "0000-0001-7644-7915",
6060
"affiliation": "Center for Lifespan Changes in Brain and Cognition, University of Oslo",

CHANGES.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
2.9.0 (June 13, 2024)
2+
=====================
3+
Feature release in the 2.9.x series.
4+
5+
The main change is that B0FieldIdentifiers with special characters
6+
are now sanitized and exposed through a ``FieldmapEstimator.sanitized_id``
7+
attribute.
8+
9+
Workflow names and input/output connections will use ``sanitized_id``,
10+
to ensure compatibility with filenames and workflow graph generation.
11+
Internal lookup tables will continue to use the the unsanitized ``bids_id``.
12+
13+
* FIX: Update suffix only when finding related fieldmap files (#436)
14+
* FIX: Remove unused ANTs parameter that was removed in 2.4.1 (#431)
15+
* RF: Add sanitized_id field to FieldmapEstimation (#444)
16+
* DOC: Un-mock the already-imported numpy (#440)
17+
* CI: Bump actions/cache from 3 to 4 (#429)
18+
119
2.8.1 (January 22, 2024)
220
========================
321
Bug-fix release in the 2.8.x series.

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ RUN python -m build /src
4040
#
4141

4242
# Utilities for downloading packages
43-
FROM ${BASE_IMAGE} as downloader
43+
FROM --platform=linux/amd64 ${BASE_IMAGE} as downloader
4444

4545
# Bump the date to current to refresh curl/certificates/etc
4646
RUN echo "2023.11.09"
@@ -100,7 +100,7 @@ RUN /opt/conda/envs/sdcflows/bin/pip install --no-cache-dir -r /tmp/requirements
100100
#
101101
# Main stage
102102
#
103-
FROM ${BASE_IMAGE} as sdcflows
103+
FROM --platform=linux/amd64 ${BASE_IMAGE} as sdcflows
104104

105105
# Configure apt
106106
ENV DEBIAN_FRONTEND="noninteractive" \

docs/notebooks/SDC - Theory and physics.ipynb

Lines changed: 12 additions & 1 deletion
Large diffs are not rendered by default.

sdcflows/fieldmaps.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ class FieldmapEstimation:
300300
bids_id = attr.ib(default=None, kw_only=True, type=str, on_setattr=_id_setter)
301301
"""The unique ``B0FieldIdentifier`` field of this fieldmap."""
302302

303+
sanitized_id = attr.ib(init=False, repr=False)
304+
"""Sanitized version of the bids_id with special characters replaced by underscores."""
305+
303306
_wf = attr.ib(init=False, default=None, repr=False)
304307
"""Internal pointer to a workflow."""
305308

@@ -436,6 +439,10 @@ def __attrs_post_init__(self):
436439
for intent_file in intents_meta:
437440
_intents[intent_file].add(self.bids_id)
438441

442+
# Provide a sanitized identifier that can be used in cases where
443+
# special characters are not allowed.
444+
self.sanitized_id = re.sub(r'[^a-zA-Z0-9]', '_', self.bids_id)
445+
439446
def paths(self):
440447
"""Return a tuple of paths that are sorted."""
441448
return tuple(sorted(str(f.path) for f in self.sources))
@@ -446,7 +453,7 @@ def get_workflow(self, set_inputs=True, **kwargs):
446453
return self._wf
447454

448455
# Override workflow name
449-
kwargs["name"] = f"wf_{self.bids_id}"
456+
kwargs["name"] = f"wf_{self.sanitized_id}"
450457

451458
if self.method in (EstimatorType.MAPPED, EstimatorType.PHASEDIFF):
452459
from .workflows.fit.fieldmap import init_fmap_wf

sdcflows/tests/test_fieldmaps.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def test_FieldmapEstimation(dsA_dir, inputfiles, method, nsources, raises):
111111
assert fe.method == method
112112
assert len(fe.sources) == nsources
113113
assert fe.bids_id is not None and fe.bids_id.startswith("auto_")
114+
assert fe.bids_id == fe.sanitized_id # Auto-generated IDs are sanitized
114115

115116
# Attempt to change bids_id
116117
with pytest.raises(ValueError):
@@ -243,6 +244,33 @@ def test_FieldmapEstimationIdentifier(monkeypatch, dsA_dir):
243244

244245
fm.clear_registry()
245246

247+
fe = fm.FieldmapEstimation(
248+
[
249+
fm.FieldmapFile(
250+
dsA_dir / "sub-01" / "fmap/sub-01_fieldmap.nii.gz",
251+
metadata={
252+
"Units": "Hz",
253+
"B0FieldIdentifier": "fmap-with^special#chars",
254+
"IntendedFor": ["file1.nii.gz", "file2.nii.gz"],
255+
},
256+
),
257+
fm.FieldmapFile(
258+
dsA_dir / "sub-01" / "fmap/sub-01_magnitude.nii.gz",
259+
metadata={"Units": "Hz", "B0FieldIdentifier": "fmap-with^special#chars"},
260+
),
261+
]
262+
)
263+
assert fe.bids_id == "fmap-with^special#chars"
264+
assert fe.sanitized_id == "fmap_with_special_chars"
265+
# The unsanitized ID is used for lookups
266+
assert fm.get_identifier("file1.nii.gz") == ("fmap-with^special#chars",)
267+
assert fm.get_identifier("file2.nii.gz") == ("fmap-with^special#chars",)
268+
269+
wf = fe.get_workflow()
270+
assert wf.name == "wf_fmap_with_special_chars"
271+
272+
fm.clear_registry()
273+
246274

247275
def test_type_setter():
248276
"""Cover the _type_setter routine."""

sdcflows/workflows/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def init_fmap_preproc_wf(
124124
output_dir=str(output_dir),
125125
write_coeff=True,
126126
bids_fmap_id=estimator.bids_id,
127-
name=f"fmap_derivatives_wf_{estimator.bids_id}",
127+
name=f"fmap_derivatives_wf_{estimator.sanitized_id}",
128128
)
129129
fmap_derivatives_wf.inputs.inputnode.source_files = source_files
130130
fmap_derivatives_wf.inputs.inputnode.fmap_meta = [
@@ -135,15 +135,15 @@ def init_fmap_preproc_wf(
135135
output_dir=str(output_dir),
136136
fmap_type=str(estimator.method).rpartition(".")[-1].lower(),
137137
bids_fmap_id=estimator.bids_id,
138-
name=f"fmap_reports_wf_{estimator.bids_id}",
138+
name=f"fmap_reports_wf_{estimator.sanitized_id}",
139139
)
140140
fmap_reports_wf.inputs.inputnode.source_files = source_files
141141

142142
if estimator.method not in (EstimatorType.MAPPED, EstimatorType.PHASEDIFF):
143143
fields = INPUT_FIELDS[estimator.method]
144144
inputnode = pe.Node(
145145
niu.IdentityInterface(fields=fields),
146-
name=f"in_{estimator.bids_id}",
146+
name=f"in_{estimator.sanitized_id}",
147147
)
148148
# fmt:off
149149
workflow.connect([

sdcflows/workflows/fit/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def init_sdcflows_wf():
6161
output_dir=config.execution.output_dir,
6262
bids_fmap_id=estim.bids_id,
6363
write_coeff=True,
64-
name=f"fmap_derivatives_{estim.bids_id}",
64+
name=f"fmap_derivatives_{estim.sanitized_id}",
6565
)
6666

6767
source_paths = [
@@ -76,7 +76,7 @@ def init_sdcflows_wf():
7676
fmap_type=estim.method,
7777
output_dir=config.execution.output_dir,
7878
bids_fmap_id=estim.bids_id,
79-
name=f"fmap_reports_{estim.bids_id}",
79+
name=f"fmap_reports_{estim.sanitized_id}",
8080
)
8181
reportlets_wf.inputs.inputnode.source_files = source_paths
8282

sdcflows/workflows/outputs.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
# https://www.nipreps.org/community/licensing/
2222
#
2323
"""Writing out outputs."""
24+
import re
25+
2426
from nipype.pipeline import engine as pe
2527
from nipype.interfaces import utility as niu
2628
from niworkflows.interfaces.bids import DerivativesDataSink as _DDS
@@ -77,7 +79,7 @@ def init_fmap_reports_wf(
7779

7880
custom_entities = custom_entities or {}
7981
if bids_fmap_id:
80-
custom_entities["fmapid"] = bids_fmap_id.replace("_", "")
82+
custom_entities["fmapid"] = re.sub(r'[^a-zA-Z0-9]', '', bids_fmap_id)
8183

8284
workflow = pe.Workflow(name=name)
8385
inputnode = pe.Node(
@@ -156,7 +158,7 @@ def init_fmap_derivatives_wf(
156158
"""
157159
custom_entities = custom_entities or {}
158160
if bids_fmap_id:
159-
custom_entities["fmapid"] = bids_fmap_id.replace("_", "")
161+
custom_entities["fmapid"] = re.sub(r'[^a-zA-Z0-9]', '', bids_fmap_id)
160162

161163
workflow = pe.Workflow(name=name)
162164
inputnode = pe.Node(

0 commit comments

Comments
 (0)