def test_get_shim_setting(tmpdir, fname, content, expected_return): """ Tests for get_shim_setting """ json_name = op.join(str(tmpdir), fname) json_dir = op.dirname(json_name) if not op.exists(json_dir): os.makedirs(json_dir) save_json(json_name, content) assert get_shim_setting(json_name) == expected_return
def embed_dicom_and_nifti_metadata(dcmfiles, niftifile, infofile, bids_info): """Embed metadata from nifti (affine etc) and dicoms into infofile (json) `niftifile` should exist. Its affine's orientation information is used while establishing new `NiftiImage` out of dicom stack and together with `bids_info` (if provided) is dumped into json `infofile` Parameters ---------- dcmfiles niftifile infofile bids_info: dict Additional metadata to be embedded. `infofile` is overwritten if exists, so here you could pass some metadata which would overload (at the first level of the dict structure, no recursive fancy updates) what is obtained from nifti and dicoms """ # imports for nipype import nibabel as nb import os.path as op import json import re from heudiconv.utils import save_json from heudiconv.external.dcmstack import ds stack = ds.parse_and_stack(dcmfiles, force=True).values() if len(stack) > 1: raise ValueError('Found multiple series') # may be odict now - iter to be safe stack = next(iter(stack)) if not op.exists(niftifile): raise NotImplementedError( "%s does not exist. " "We are not producing new nifti files here any longer. " "Use dcm2niix directly or .convert.nipype_convert helper ." % niftifile ) orig_nii = nb.load(niftifile) aff = orig_nii.affine ornt = nb.orientations.io_orientation(aff) axcodes = nb.orientations.ornt2axcodes(ornt) new_nii = stack.to_nifti(voxel_order=''.join(axcodes), embed_meta=True) meta_info = ds.NiftiWrapper(new_nii).meta_ext.to_json() meta_info = json.loads(meta_info) if bids_info: meta_info.update(bids_info) # write to outfile save_json(infofile, meta_info)
def test_get_shim_setting(tmpdir): """ Tests for get_shim_setting """ json_dir = op.join(str(tmpdir), 'foo') if not op.exists(json_dir): os.makedirs(json_dir) json_name = op.join(json_dir, 'sub-foo.json') # 1) file with no "ShimSetting", should return None save_json(json_name, {}) with pytest.raises(KeyError): assert get_shim_setting(json_name) # -file with "ShimSetting" field save_json(json_name, {SHIM_KEY: A_SHIM}) assert get_shim_setting(json_name) == A_SHIM
def test_get_key_info_for_fmap_assignment(tmpdir, monkeypatch): """ Test get_key_info_for_fmap_assignment """ # Stuff needed to mock reading of a NIfTI file header: # affines (qforms/sforms) are 4x4 matrices MY_AFFINE = [[random() for i in range(4)] for j in range(4)] # dims are arrays with 8 elements with the first one indicating the number # of dims in the image; remaining elements are 1: MY_DIM = [4] + [round(256 * random()) for i in range(4)] + [1] * 3 # We use namedtuples so that we can use the .dot notation, to mock # nibabel headers: MyHeader = namedtuple('MyHeader', 'affine dim') MY_HEADER = MyHeader(MY_AFFINE, MY_DIM) MyMockNifti = namedtuple('MyMockNifti', 'header') def mock_nibabel_load(file): """ Pretend we run nibabel.load, but return only a header with just a few fields """ return MyMockNifti(MY_HEADER) monkeypatch.setattr(nibabel, "load", mock_nibabel_load) json_name = op.join(str(tmpdir), 'foo.json') # 1) Call for a non-existing file should give an error: with pytest.raises(FileNotFoundError): assert get_key_info_for_fmap_assignment('foo.json') # 2) matching_parameters = 'Shims' save_json(json_name, {SHIM_KEY: A_SHIM}) # otherwise get_key_info_for_fmap_assignment will give an error key_info = get_key_info_for_fmap_assignment( json_name, matching_parameter='Shims' ) assert key_info == [A_SHIM] # 3) matching_parameters = 'ImagingVolume' key_info = get_key_info_for_fmap_assignment( json_name, matching_parameter='ImagingVolume' ) assert key_info == [MY_AFFINE, MY_DIM[1:3]] # 4) invalid matching_parameters: with pytest.raises(ValueError): assert get_key_info_for_fmap_assignment( json_name, matching_parameter='Invalid' )
def test_load_json(tmpdir, caplog): # test invalid json ifname = 'invalid.json' invalid_json_file = str(tmpdir / ifname) create_tree(str(tmpdir), {ifname: u"I'm Jason Bourne"}) with pytest.raises(JSONDecodeError): load_json(str(invalid_json_file)) assert ifname in caplog.text # test valid json vcontent = {"secret": "spy"} vfname = "valid.json" valid_json_file = str(tmpdir / vfname) save_json(valid_json_file, vcontent) assert load_json(valid_json_file) == vcontent
def test_load_json(tmpdir, caplog): # test invalid json ifname = 'invalid.json' invalid_json_file = str(tmpdir / ifname) create_tree(str(tmpdir), {ifname: u"I'm Jason Bourne"}) with pytest.raises(JSONDecodeError): load_json(str(invalid_json_file)) # and even if we ask to retry a few times -- should be the same with pytest.raises(JSONDecodeError): load_json(str(invalid_json_file), retry=3) with pytest.raises(FileNotFoundError): load_json("absent123not.there", retry=3) assert ifname in caplog.text # test valid json vcontent = {"secret": "spy"} vfname = "valid.json" valid_json_file = str(tmpdir / vfname) save_json(valid_json_file, vcontent) assert load_json(valid_json_file) == vcontent calls = [0] json_load = json.load def json_load_patched(fp): calls[0] += 1 if calls[0] == 1: # just reuse bad file load_json(str(invalid_json_file)) elif calls[0] == 2: raise FileNotFoundError() else: return json_load(fp) with mock.patch.object(json, 'load', json_load_patched): assert load_json(valid_json_file, retry=3) == vcontent
def test_update_json(tmpdir): """ Test utils.update_json() """ dummy_json_file = str(tmpdir / 'dummy.json') some_content = {"name": "Jason", "age": 30, "city": "New York"} save_json(dummy_json_file, some_content, pretty=True) added_content = { "LastName": "Bourne", "Movies": [ "The Bourne Identity", "The Bourne Supremacy", "The Bourne Ultimatum", "The Bourne Legacy", "Jason Bourne" ] } update_json(dummy_json_file, added_content) # check that it was added: with open(dummy_json_file) as f: data = json.load(f) some_content.update(added_content) assert data == some_content
def test_get_key_info_for_fmap_assignment(tmpdir, label_size=4, label_seed=LABEL_SEED): """ Test get_key_info_for_fmap_assignment. label_size and label_seed are used for the "CustomAcquisitionLabel" matching parameter. label_size is the size of the random label while label_seed is the seed for the random label creation. """ nifti_file = op.join(TESTS_DATA_PATH, 'sample_nifti.nii.gz') # Get the expected parameters from the NIfTI header: MY_HEADER = nibabel.ni1.np.loadtxt( op.join(TESTS_DATA_PATH, remove_suffix(nifti_file, '.nii.gz') + '_params.txt')) json_name = op.join(TESTS_DATA_PATH, remove_suffix(nifti_file, '.nii.gz') + '.json') # 1) Call for a non-existing file should give an error: with pytest.raises(FileNotFoundError): assert get_key_info_for_fmap_assignment('foo.json', 'ImagingVolume') # 2) matching_parameters = 'Shims' json_name = op.join(TESTS_DATA_PATH, remove_suffix(nifti_file, '.nii.gz') + '.json') save_json( json_name, {SHIM_KEY: A_SHIM }) # otherwise get_key_info_for_fmap_assignment will give an error key_info = get_key_info_for_fmap_assignment(json_name, matching_parameter='Shims') assert key_info == [A_SHIM] # 3) matching_parameters = 'ImagingVolume' key_info = get_key_info_for_fmap_assignment( json_name, matching_parameter='ImagingVolume') np_testing.assert_almost_equal(key_info[0], MY_HEADER[:4], decimal=6) np_testing.assert_almost_equal(key_info[1], MY_HEADER[4][:3], decimal=6) # 4) matching_parameters = 'Force' key_info = get_key_info_for_fmap_assignment(json_name, matching_parameter='Force') assert key_info == [KeyInfoForForce] # 5) matching_parameter = 'ModalityAcquisitionLabel' for d in ['fmap', 'func', 'dwi', 'anat']: Path(op.join(str(tmpdir), d)).mkdir(parents=True, exist_ok=True) for (dirname, fname, expected_key_info) in [ ('fmap', 'sub-foo_acq-fmri_epi.json', 'func'), ('fmap', 'sub-foo_acq-bold_epi.json', 'func'), ('fmap', 'sub-foo_acq-func_epi.json', 'func'), ('fmap', 'sub-foo_acq-diff_epi.json', 'dwi'), ('fmap', 'sub-foo_acq-anat_epi.json', 'anat'), ('fmap', 'sub-foo_acq-struct_epi.json', 'anat'), ('func', 'sub-foo_bold.json', 'func'), ('dwi', 'sub-foo_dwi.json', 'dwi'), ('anat', 'sub-foo_T1w.json', 'anat'), ]: json_name = op.join(str(tmpdir), dirname, fname) save_json(json_name, {SHIM_KEY: A_SHIM}) assert [expected_key_info] == get_key_info_for_fmap_assignment( json_name, matching_parameter='ModalityAcquisitionLabel') # 6) matching_parameter = 'CustomAcquisitionLabel' A_LABEL = gen_rand_label(label_size, label_seed) for d in ['fmap', 'func', 'dwi', 'anat']: Path(op.join(str(tmpdir), d)).mkdir(parents=True, exist_ok=True) for (dirname, fname, expected_key_info) in [ ('fmap', f'sub-foo_acq-{A_LABEL}_epi.json', A_LABEL), ('func', f'sub-foo_task-{A_LABEL}_acq-foo_bold.json', A_LABEL), ('dwi', f'sub-foo_acq-{A_LABEL}_dwi.json', A_LABEL), ('anat', f'sub-foo_acq-{A_LABEL}_T1w.json', A_LABEL), ]: json_name = op.join(str(tmpdir), dirname, fname) save_json(json_name, {SHIM_KEY: A_SHIM}) assert [expected_key_info] == get_key_info_for_fmap_assignment( json_name, matching_parameter='CustomAcquisitionLabel') # Finally: invalid matching_parameters: assert get_key_info_for_fmap_assignment( json_name, matching_parameter='Invalid') == []