|
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