|
4 | 4 | from glob import glob
|
5 | 5 |
|
6 | 6 | import pytest
|
7 |
| -from .utils import TESTS_DATA_PATH |
8 |
| - |
9 |
| -from heudiconv.convert import (update_complex_name, |
10 |
| - update_multiecho_name, |
11 |
| - update_uncombined_name, |
12 |
| - DW_IMAGE_IN_FMAP_FOLDER_WARNING, |
13 |
| - ) |
14 | 7 | import heudiconv.convert
|
15 | 8 | from heudiconv.bids import BIDSError
|
16 | 9 | from heudiconv.utils import load_heuristic
|
17 | 10 | from heudiconv.cli.run import main as runner
|
| 11 | +from heudiconv.convert import ( |
| 12 | + DW_IMAGE_IN_FMAP_FOLDER_WARNING, |
| 13 | + update_complex_name, |
| 14 | + update_multiecho_name, |
| 15 | + update_uncombined_name, |
| 16 | +) |
| 17 | + |
| 18 | +from .utils import TESTS_DATA_PATH |
18 | 19 |
|
19 | 20 |
|
20 | 21 | def test_update_complex_name():
|
21 | 22 | """Unit testing for heudiconv.convert.update_complex_name(), which updates
|
22 | 23 | filenames with the part field if appropriate.
|
23 | 24 | """
|
24 | 25 | # Standard name update
|
25 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_sbref' |
| 26 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_sbref' |
26 | 27 | metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'P', 'MB', 'TE3', 'ND', 'MOSAIC']}
|
27 |
| - suffix = 3 |
28 | 28 | out_fn_true = 'sub-X_ses-Y_task-Z_run-01_part-phase_sbref'
|
29 |
| - out_fn_test = update_complex_name(metadata, fn, suffix) |
| 29 | + out_fn_test = update_complex_name(metadata, base_fn) |
30 | 30 | assert out_fn_test == out_fn_true
|
| 31 | + |
31 | 32 | # Catch an unsupported type and *do not* update
|
32 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_phase' |
33 |
| - out_fn_test = update_complex_name(metadata, fn, suffix) |
34 |
| - assert out_fn_test == fn |
35 |
| - # Data type is missing from metadata so use suffix |
36 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_sbref' |
| 33 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_phase' |
| 34 | + out_fn_test = update_complex_name(metadata, base_fn) |
| 35 | + assert out_fn_test == base_fn |
| 36 | + |
| 37 | + # Data type is missing from metadata so raise a RuntimeError |
| 38 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_sbref' |
37 | 39 | metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'MB', 'TE3', 'ND', 'MOSAIC']}
|
38 |
| - out_fn_true = 'sub-X_ses-Y_task-Z_run-01_part-3_sbref' |
39 |
| - out_fn_test = update_complex_name(metadata, fn, suffix) |
40 |
| - assert out_fn_test == out_fn_true |
41 |
| - # Catch existing field with value that *does not match* metadata |
42 |
| - # and raise Exception |
43 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_part-mag_sbref' |
| 40 | + with pytest.raises(RuntimeError): |
| 41 | + update_complex_name(metadata, base_fn) |
| 42 | + |
| 43 | + # Catch existing field with value (part is already in the filename) |
| 44 | + # that *does not match* metadata and raise Exception |
| 45 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_part-mag_sbref' |
44 | 46 | metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'P', 'MB', 'TE3', 'ND', 'MOSAIC']}
|
45 |
| - suffix = 3 |
46 | 47 | with pytest.raises(BIDSError):
|
47 |
| - assert update_complex_name(metadata, fn, suffix) |
| 48 | + update_complex_name(metadata, base_fn) |
| 49 | + |
| 50 | + # Catch existing field with value (part is already in the filename) |
| 51 | + # that *does match* metadata and do not update |
| 52 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_part-phase_sbref' |
| 53 | + metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'P', 'MB', 'TE3', 'ND', 'MOSAIC']} |
| 54 | + out_fn_test = update_complex_name(metadata, base_fn) |
| 55 | + assert out_fn_test == base_fn |
48 | 56 |
|
49 | 57 |
|
50 | 58 | def test_update_multiecho_name():
|
51 | 59 | """Unit testing for heudiconv.convert.update_multiecho_name(), which updates
|
52 | 60 | filenames with the echo field if appropriate.
|
53 | 61 | """
|
54 | 62 | # Standard name update
|
55 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 63 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
56 | 64 | metadata = {'EchoTime': 0.01,
|
57 | 65 | 'EchoNumber': 1}
|
58 | 66 | echo_times = [0.01, 0.02, 0.03]
|
59 | 67 | out_fn_true = 'sub-X_ses-Y_task-Z_run-01_echo-1_bold'
|
60 |
| - out_fn_test = update_multiecho_name(metadata, fn, echo_times) |
| 68 | + out_fn_test = update_multiecho_name(metadata, base_fn, echo_times) |
61 | 69 | assert out_fn_test == out_fn_true
|
| 70 | + |
62 | 71 | # EchoNumber field is missing from metadata, so use echo_times
|
63 | 72 | metadata = {'EchoTime': 0.01}
|
64 |
| - out_fn_test = update_multiecho_name(metadata, fn, echo_times) |
| 73 | + out_fn_test = update_multiecho_name(metadata, base_fn, echo_times) |
65 | 74 | assert out_fn_test == out_fn_true
|
| 75 | + |
66 | 76 | # Catch an unsupported type and *do not* update
|
67 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_phasediff' |
68 |
| - out_fn_test = update_multiecho_name(metadata, fn, echo_times) |
69 |
| - assert out_fn_test == fn |
| 77 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_phasediff' |
| 78 | + out_fn_test = update_multiecho_name(metadata, base_fn, echo_times) |
| 79 | + assert out_fn_test == base_fn |
| 80 | + |
| 81 | + # EchoTime is missing, but use EchoNumber (which is the first thing it checks) |
| 82 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 83 | + out_fn_true = 'sub-X_ses-Y_task-Z_run-01_echo-1_bold' |
| 84 | + metadata = {'EchoNumber': 1} |
| 85 | + echo_times = [False, 0.02, 0.03] |
| 86 | + out_fn_test = update_multiecho_name(metadata, base_fn, echo_times) |
| 87 | + assert out_fn_test == out_fn_true |
| 88 | + |
| 89 | + # Both EchoTime and EchoNumber are missing, which raises a KeyError |
| 90 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 91 | + metadata = {} |
| 92 | + echo_times = [False, 0.02, 0.03] |
| 93 | + with pytest.raises(KeyError): |
| 94 | + update_multiecho_name(metadata, base_fn, echo_times) |
| 95 | + |
| 96 | + # Providing echo times as something other than a list should raise a TypeError |
| 97 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 98 | + with pytest.raises(TypeError): |
| 99 | + update_multiecho_name(metadata, base_fn, set(echo_times)) |
70 | 100 |
|
71 | 101 |
|
72 | 102 | def test_update_uncombined_name():
|
73 | 103 | """Unit testing for heudiconv.convert.update_uncombined_name(), which updates
|
74 | 104 | filenames with the ch field if appropriate.
|
75 | 105 | """
|
76 | 106 | # Standard name update
|
77 |
| - fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 107 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
78 | 108 | metadata = {'CoilString': 'H1'}
|
79 | 109 | channel_names = ['H1', 'H2', 'H3', 'HEA;HEP']
|
80 | 110 | out_fn_true = 'sub-X_ses-Y_task-Z_run-01_ch-01_bold'
|
81 |
| - out_fn_test = update_uncombined_name(metadata, fn, channel_names) |
| 111 | + out_fn_test = update_uncombined_name(metadata, base_fn, channel_names) |
82 | 112 | assert out_fn_test == out_fn_true
|
83 |
| - # CoilString field has no number in it |
| 113 | + |
| 114 | + # CoilString field has no number in it, so we index the channel_names list |
84 | 115 | metadata = {'CoilString': 'HEA;HEP'}
|
85 | 116 | out_fn_true = 'sub-X_ses-Y_task-Z_run-01_ch-04_bold'
|
86 |
| - out_fn_test = update_uncombined_name(metadata, fn, channel_names) |
| 117 | + out_fn_test = update_uncombined_name(metadata, base_fn, channel_names) |
87 | 118 | assert out_fn_test == out_fn_true
|
88 | 119 |
|
| 120 | + # Extract the number from the CoilString and use that |
| 121 | + channel_names = ['H1', 'B1', 'H3', 'HEA;HEP'] |
| 122 | + metadata = {'CoilString': 'H1'} |
| 123 | + out_fn_true = 'sub-X_ses-Y_task-Z_run-01_ch-01_bold' |
| 124 | + out_fn_test = update_uncombined_name(metadata, base_fn, channel_names) |
| 125 | + assert out_fn_test == out_fn_true |
| 126 | + |
| 127 | + # NOTE: Extracting the number does not protect against multiple coils with the same number |
| 128 | + # (but, say, different letters) |
| 129 | + # Note that this is still "ch-01" |
| 130 | + metadata = {'CoilString': 'B1'} |
| 131 | + out_fn_true = 'sub-X_ses-Y_task-Z_run-01_ch-01_bold' |
| 132 | + out_fn_test = update_uncombined_name(metadata, base_fn, channel_names) |
| 133 | + assert out_fn_test == out_fn_true |
| 134 | + |
| 135 | + # Providing echo times as something other than a list should raise a TypeError |
| 136 | + base_fn = 'sub-X_ses-Y_task-Z_run-01_bold' |
| 137 | + with pytest.raises(TypeError): |
| 138 | + update_uncombined_name(metadata, base_fn, set(channel_names)) |
| 139 | + |
89 | 140 |
|
90 | 141 | def test_b0dwi_for_fmap(tmpdir, caplog):
|
91 | 142 | """Make sure we raise a warning when .bvec and .bval files
|
|
0 commit comments