def test_write_too_many_scalars_and_properties(self): # TRK supports up to 10 data_per_point. data_per_point = {} for i in range(10): data_per_point['#{0}'.format(i)] = DATA['fa'] tractogram = Tractogram(DATA['streamlines'], data_per_point=data_per_point, affine_to_rasmm=np.eye(4)) trk_file = BytesIO() trk = TrkFile(tractogram) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, tractogram) # More than 10 data_per_point should raise an error. data_per_point['#{0}'.format(i+1)] = DATA['fa'] tractogram = Tractogram(DATA['streamlines'], data_per_point=data_per_point, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) assert_raises(ValueError, trk.save, BytesIO()) # TRK supports up to 10 data_per_streamline. data_per_streamline = {} for i in range(10): data_per_streamline['#{0}'.format(i)] = DATA['mean_torsion'] tractogram = Tractogram(DATA['streamlines'], data_per_streamline=data_per_streamline, affine_to_rasmm=np.eye(4)) trk_file = BytesIO() trk = TrkFile(tractogram) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, tractogram) # More than 10 data_per_streamline should raise an error. data_per_streamline['#{0}'.format(i+1)] = DATA['mean_torsion'] tractogram = Tractogram(DATA['streamlines'], data_per_streamline=data_per_streamline) trk = TrkFile(tractogram) assert_raises(ValueError, trk.save, BytesIO())
def test_load_write_file(self): for fname in [DATA['empty_trk_fname'], DATA['simple_trk_fname'], DATA['complex_trk_fname']]: for lazy_load in [False, True]: trk = TrkFile.load(fname, lazy_load=lazy_load) trk_file = BytesIO() trk.save(trk_file) new_trk = TrkFile.load(fname, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, trk.tractogram) trk_file.seek(0, os.SEEK_SET)
def test_write_optional_header_fields(self): # The TRK file format doesn't support additional header fields. # If provided, they will be ignored. tractogram = Tractogram(affine_to_rasmm=np.eye(4)) trk_file = BytesIO() header = {'extra': 1234} trk = TrkFile(tractogram, header) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file) assert_true("extra" not in new_trk.header)
def test_header_read_restore(self): # Test that reading a header restores the file position trk_fname = DATA['simple_trk_fname'] bio = BytesIO() bio.write(b'Along my very merry way') hdr_pos = bio.tell() hdr_from_fname = TrkFile._read_header(trk_fname) with open(trk_fname, 'rb') as fobj: bio.write(fobj.read()) bio.seek(hdr_pos) # Check header is as expected hdr_from_fname['_offset_data'] += hdr_pos # Correct for start position assert_arr_dict_equal(TrkFile._read_header(bio), hdr_from_fname) # Check fileobject file position has not changed assert_equal(bio.tell(), hdr_pos)
def test_write_scalars_and_properties_name_too_long(self): # TRK supports data_per_point name up to 20 characters. # However, we reserve the last two characters to store # the number of values associated to each data_per_point. # So in reality we allow name of 18 characters, otherwise # the name is truncated and warning is issue. for nb_chars in range(22): data_per_point = {'A'*nb_chars: DATA['colors']} tractogram = Tractogram(DATA['streamlines'], data_per_point=data_per_point, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) if nb_chars > 18: assert_raises(ValueError, trk.save, BytesIO()) else: trk.save(BytesIO()) data_per_point = {'A'*nb_chars: DATA['fa']} tractogram = Tractogram(DATA['streamlines'], data_per_point=data_per_point, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) if nb_chars > 20: assert_raises(ValueError, trk.save, BytesIO()) else: trk.save(BytesIO()) # TRK supports data_per_streamline name up to 20 characters. # However, we reserve the last two characters to store # the number of values associated to each data_per_streamline. # So in reality we allow name of 18 characters, otherwise # the name is truncated and warning is issue. for nb_chars in range(22): data_per_streamline = {'A'*nb_chars: DATA['mean_colors']} tractogram = Tractogram(DATA['streamlines'], data_per_streamline=data_per_streamline, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) if nb_chars > 18: assert_raises(ValueError, trk.save, BytesIO()) else: trk.save(BytesIO()) data_per_streamline = {'A'*nb_chars: DATA['mean_torsion']} tractogram = Tractogram(DATA['streamlines'], data_per_streamline=data_per_streamline, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) if nb_chars > 20: assert_raises(ValueError, trk.save, BytesIO()) else: trk.save(BytesIO())
def test_load_file_with_wrong_information(self): trk_file = open(DATA['simple_trk_fname'], 'rb').read() # Simulate a TRK file where `count` was not provided. count = np.array(0, dtype="int32").tostring() new_trk_file = trk_file[:1000-12] + count + trk_file[1000-8:] trk = TrkFile.load(BytesIO(new_trk_file), lazy_load=False) assert_tractogram_equal(trk.tractogram, DATA['simple_tractogram']) # Simulate a TRK where `vox_to_ras` is not recorded (i.e. all zeros). vox_to_ras = np.zeros((4, 4), dtype=np.float32).tostring() new_trk_file = trk_file[:440] + vox_to_ras + trk_file[440+64:] with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: trk = TrkFile.load(BytesIO(new_trk_file)) assert_equal(len(w), 1) assert_true(issubclass(w[0].category, HeaderWarning)) assert_true("identity" in str(w[0].message)) assert_array_equal(trk.affine, np.eye(4)) # Simulate a TRK where `vox_to_ras` is invalid. vox_to_ras = np.zeros((4, 4), dtype=np.float32) vox_to_ras[3, 3] = 1 vox_to_ras = vox_to_ras.tostring() new_trk_file = trk_file[:440] + vox_to_ras + trk_file[440+64:] with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) # Simulate a TRK file where `voxel_order` was not provided. voxel_order = np.zeros(1, dtype="|S3").tostring() new_trk_file = trk_file[:948] + voxel_order + trk_file[948+3:] with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: TrkFile.load(BytesIO(new_trk_file)) assert_equal(len(w), 1) assert_true(issubclass(w[0].category, HeaderWarning)) assert_true("LPS" in str(w[0].message)) # Simulate a TRK file with an unsupported version. version = np.int32(123).tostring() new_trk_file = trk_file[:992] + version + trk_file[992+4:] assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) # Simulate a TRK file with a wrong hdr_size. hdr_size = np.int32(1234).tostring() new_trk_file = trk_file[:996] + hdr_size + trk_file[996+4:] assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) # Simulate a TRK file with a wrong scalar_name. trk_file = open(DATA['complex_trk_fname'], 'rb').read() noise = np.int32(42).tostring() new_trk_file = trk_file[:47] + noise + trk_file[47+4:] assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) # Simulate a TRK file with a wrong property_name. noise = np.int32(42).tostring() new_trk_file = trk_file[:254] + noise + trk_file[254+4:] assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file))
def test_write_empty_file(self): tractogram = Tractogram(affine_to_rasmm=np.eye(4)) trk_file = BytesIO() trk = TrkFile(tractogram) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file) assert_tractogram_equal(new_trk.tractogram, tractogram) new_trk_orig = TrkFile.load(DATA['empty_trk_fname']) assert_tractogram_equal(new_trk.tractogram, new_trk_orig.tractogram) trk_file.seek(0, os.SEEK_SET) assert_equal(trk_file.read(), open(DATA['empty_trk_fname'], 'rb').read())
def test_load_write_LPS_file(self): # Load the RAS and LPS version of the standard. trk_RAS = TrkFile.load(DATA['standard_trk_fname'], lazy_load=False) trk_LPS = TrkFile.load(DATA['standard_LPS_trk_fname'], lazy_load=False) assert_tractogram_equal(trk_LPS.tractogram, trk_RAS.tractogram) # Write back the standard. trk_file = BytesIO() trk = TrkFile(trk_LPS.tractogram, trk_LPS.header) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file) assert_arr_dict_equal(new_trk.header, trk.header) assert_tractogram_equal(new_trk.tractogram, trk.tractogram) new_trk_orig = TrkFile.load(DATA['standard_LPS_trk_fname']) assert_tractogram_equal(new_trk.tractogram, new_trk_orig.tractogram) trk_file.seek(0, os.SEEK_SET) assert_equal(trk_file.read(), open(DATA['standard_LPS_trk_fname'], 'rb').read()) # Test writing a file where the header is missing the # Field.VOXEL_ORDER. trk_file = BytesIO() # For TRK file format, the default voxel order is LPS. header = copy.deepcopy(trk_LPS.header) header[Field.VOXEL_ORDER] = b"" trk = TrkFile(trk_LPS.tractogram, header) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file) assert_arr_dict_equal(new_trk.header, trk_LPS.header) assert_tractogram_equal(new_trk.tractogram, trk.tractogram) new_trk_orig = TrkFile.load(DATA['standard_LPS_trk_fname']) assert_tractogram_equal(new_trk.tractogram, new_trk_orig.tractogram) trk_file.seek(0, os.SEEK_SET) assert_equal(trk_file.read(), open(DATA['standard_LPS_trk_fname'], 'rb').read())
def test_write_complex_file(self): # With scalars tractogram = Tractogram(DATA['streamlines'], data_per_point=DATA['data_per_point'], affine_to_rasmm=np.eye(4)) trk_file = BytesIO() trk = TrkFile(tractogram) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, tractogram) # With properties data_per_streamline = DATA['data_per_streamline'] tractogram = Tractogram(DATA['streamlines'], data_per_streamline=data_per_streamline, affine_to_rasmm=np.eye(4)) trk = TrkFile(tractogram) trk_file = BytesIO() trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, tractogram) # With scalars and properties data_per_streamline = DATA['data_per_streamline'] tractogram = Tractogram(DATA['streamlines'], data_per_point=DATA['data_per_point'], data_per_streamline=data_per_streamline, affine_to_rasmm=np.eye(4)) trk_file = BytesIO() trk = TrkFile(tractogram) trk.save(trk_file) trk_file.seek(0, os.SEEK_SET) new_trk = TrkFile.load(trk_file, lazy_load=False) assert_tractogram_equal(new_trk.tractogram, tractogram) new_trk_orig = TrkFile.load(DATA['complex_trk_fname']) assert_tractogram_equal(new_trk.tractogram, new_trk_orig.tractogram) trk_file.seek(0, os.SEEK_SET) assert_equal(trk_file.read(), open(DATA['complex_trk_fname'], 'rb').read())
def test_is_supported_detect_format(): # Test is_supported and detect_format functions # Empty file/string f = BytesIO() assert_false(nib.streamlines.is_supported(f)) assert_false(nib.streamlines.is_supported("")) assert_true(nib.streamlines.detect_format(f) is None) assert_true(nib.streamlines.detect_format("") is None) # Valid file without extension for tfile_cls in nib.streamlines.FORMATS.values(): f = BytesIO() f.write(tfile_cls.MAGIC_NUMBER) f.seek(0, os.SEEK_SET) assert_true(nib.streamlines.is_supported(f)) assert_true(nib.streamlines.detect_format(f) is tfile_cls) # Wrong extension but right magic number for tfile_cls in nib.streamlines.FORMATS.values(): with tempfile.TemporaryFile(mode="w+b", suffix=".txt") as f: f.write(tfile_cls.MAGIC_NUMBER) f.seek(0, os.SEEK_SET) assert_true(nib.streamlines.is_supported(f)) assert_true(nib.streamlines.detect_format(f) is tfile_cls) # Good extension but wrong magic number for ext, tfile_cls in nib.streamlines.FORMATS.items(): with tempfile.TemporaryFile(mode="w+b", suffix=ext) as f: f.write(b"pass") f.seek(0, os.SEEK_SET) assert_false(nib.streamlines.is_supported(f)) assert_true(nib.streamlines.detect_format(f) is None) # Wrong extension, string only f = "my_tractogram.asd" assert_false(nib.streamlines.is_supported(f)) assert_true(nib.streamlines.detect_format(f) is None) # Good extension, string only for ext, tfile_cls in nib.streamlines.FORMATS.items(): f = "my_tractogram" + ext assert_true(nib.streamlines.is_supported(f)) assert_equal(nib.streamlines.detect_format(f), tfile_cls) # Extension should not be case-sensitive. for ext, tfile_cls in nib.streamlines.FORMATS.items(): f = "my_tractogram" + ext.upper() assert_true(nib.streamlines.detect_format(f) is tfile_cls)