From 15ceb59b8ac998a71601ab170d5e6324d4c28a25 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 07:55:17 -0500 Subject: [PATCH 01/12] Make reading & writing tests subclass from unittest.TestCase --- nrrd/tests/test_reading.py | 2 +- nrrd/tests/test_writing.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index 29efce0..ba895be 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -4,7 +4,7 @@ from nrrd.tests.util import * -class TestReadingFunctions: +class TestReadingFunctions(unittest.TestCase): def setUp(self): self.expected_header = {'dimension': 3, 'encoding': 'raw', diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index 431fbd4..916e8e8 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -7,7 +7,7 @@ from nrrd.tests.util import * -class TestWritingFunctions: +class TestWritingFunctions(unittest.TestCase): def setUp(self): self.temp_write_dir = tempfile.mkdtemp('nrrdtest') self.data_input, _ = nrrd.read(RAW_NRRD_FILE_PATH, index_order=self.index_order) From d79276f4157c70fcfe7abf36c365572098725275 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 07:57:21 -0500 Subject: [PATCH 02/12] Remove Python 2 logic in tests No longer necessary since Python 2 support has been dropped --- nrrd/tests/util.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nrrd/tests/util.py b/nrrd/tests/util.py index 155158d..d09f97b 100644 --- a/nrrd/tests/util.py +++ b/nrrd/tests/util.py @@ -22,8 +22,3 @@ ASCII_1D_NRRD_FILE_PATH = os.path.join(DATA_DIR_PATH, 'test1d_ascii.nrrd') ASCII_2D_NRRD_FILE_PATH = os.path.join(DATA_DIR_PATH, 'test2d_ascii.nrrd') ASCII_1D_CUSTOM_FIELDS_FILE_PATH = os.path.join(DATA_DIR_PATH, 'test_customFields.nrrd') - -# Fix issue with assertRaisesRegex only available in Python 3 while -# assertRaisesRegexp is available in Python 2 (and deprecated in Python 3) -if not hasattr(unittest.TestCase, 'assertRaisesRegex'): - unittest.TestCase.assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegexp') From 1b90a67d625f6c3f59438407689e3a62c32555e6 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 08:02:28 -0500 Subject: [PATCH 03/12] Add typing --- nrrd/tests/test_reading.py | 821 +++++++++++++++++++------------------ nrrd/tests/test_writing.py | 672 +++++++++++++++--------------- 2 files changed, 751 insertions(+), 742 deletions(-) diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index ba895be..d716c67 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -1,464 +1,469 @@ +from typing import ClassVar, Literal + import numpy as np import nrrd from nrrd.tests.util import * -class TestReadingFunctions(unittest.TestCase): - def setUp(self): - self.expected_header = {'dimension': 3, - 'encoding': 'raw', - 'endian': 'little', - 'kinds': ['domain', 'domain', 'domain'], - 'sizes': np.array([30, 30, 30]), - 'space': 'left-posterior-superior', - 'space directions': np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), - 'space origin': np.array([0, 0, 0]), - 'type': 'short'} - - self.expected_data = np.fromfile(RAW_DATA_FILE_PATH, np.int16).reshape((30, 30, 30)) - if self.index_order == 'F': - self.expected_data = self.expected_data.T - - def test_read_header_only(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - - # np.testing.assert_equal is used to compare the headers because it will appropriately handle each - # value in the structure. Since some of the values can be Numpy arrays inside the headers, this must be - # used to compare the two values. - np.testing.assert_equal(self.expected_header, header) - - def test_read_header_only_with_filename(self): - header = nrrd.read_header(RAW_NRRD_FILE_PATH) - - # np.testing.assert_equal is used to compare the headers because it will appropriately handle each - # value in the structure. Since some of the values can be Numpy arrays inside the headers, this must be - # used to compare the two values. - np.testing.assert_equal(self.expected_header, header) - - def test_read_detached_header_only(self): - expected_header = self.expected_header - expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - - with open(RAW_NHDR_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - - np.testing.assert_equal(self.expected_header, header) - - def test_read_header_and_data_filename(self): - data, header = nrrd.read(RAW_NRRD_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_detached_header_and_data(self): - expected_header = self.expected_header - expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - - data, header = nrrd.read(RAW_NHDR_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_detached_header_and_data_with_byteskip_minus1(self): - expected_header = self.expected_header - expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - expected_header['byte skip'] = -1 - - data, header = nrrd.read(RAW_BYTESKIP_NHDR_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_detached_header_and_nifti_data_with_byteskip_minus1(self): - expected_header = self.expected_header - expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - expected_header['byte skip'] = -1 - expected_header['encoding'] = 'gzip' - expected_header['data file'] = 'BallBinary30x30x30.nii.gz' - - data, header = nrrd.read(GZ_BYTESKIP_NIFTI_NHDR_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_detached_header_and_nifti_data(self): - with self.assertRaisesRegex( - nrrd.NRRDError, 'Size of the data does not equal the product of all the dimensions: 27000-27176=-176'): - nrrd.read(GZ_NIFTI_NHDR_FILE_PATH, index_order=self.index_order) - - def test_read_detached_header_and_data_with_byteskip_minus5(self): - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid byteskip, allowed values are greater than or equal to -1'): - nrrd.read(RAW_INVALID_BYTESKIP_NHDR_FILE_PATH, index_order=self.index_order) - - def test_read_header_and_gz_compressed_data(self): - expected_header = self.expected_header - expected_header['encoding'] = 'gzip' - - data, header = nrrd.read(GZ_NRRD_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) +class Abstract: + class TestReadingFunctions(unittest.TestCase): + index_order: ClassVar[Literal['F', 'C']] + + def setUp(self): + self.expected_header = {'dimension': 3, + 'encoding': 'raw', + 'endian': 'little', + 'kinds': ['domain', 'domain', 'domain'], + 'sizes': np.array([30, 30, 30]), + 'space': 'left-posterior-superior', + 'space directions': np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), + 'space origin': np.array([0, 0, 0]), + 'type': 'short'} + + self.expected_data = np.fromfile(RAW_DATA_FILE_PATH, np.int16).reshape((30, 30, 30)) + if self.index_order == 'F': + self.expected_data = self.expected_data.T + + def test_read_header_only(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + + # np.testing.assert_equal is used to compare the headers because it will appropriately handle each + # value in the structure. Since some of the values can be Numpy arrays inside the headers, this must be + # used to compare the two values. + np.testing.assert_equal(self.expected_header, header) - def test_read_header_and_gz_compressed_data_with_byteskip_minus1(self): - expected_header = self.expected_header - expected_header['encoding'] = 'gzip' - expected_header['type'] = 'int16' - expected_header['byte skip'] = -1 + def test_read_header_only_with_filename(self): + header = nrrd.read_header(RAW_NRRD_FILE_PATH) - data, header = nrrd.read(GZ_BYTESKIP_NRRD_FILE_PATH, index_order=self.index_order) + # np.testing.assert_equal is used to compare the headers because it will appropriately handle each + # value in the structure. Since some of the values can be Numpy arrays inside the headers, this must be + # used to compare the two values. + np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) + def test_read_detached_header_only(self): + expected_header = self.expected_header + expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) + with open(RAW_NHDR_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) - def test_read_header_and_bz2_compressed_data(self): - expected_header = self.expected_header - expected_header['encoding'] = 'bzip2' + np.testing.assert_equal(self.expected_header, header) - data, header = nrrd.read(BZ2_NRRD_FILE_PATH, index_order=self.index_order) + def test_read_header_and_data_filename(self): + data, header = nrrd.read(RAW_NRRD_FILE_PATH, index_order=self.index_order) - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) + np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - def test_read_header_and_gz_compressed_data_with_lineskip3(self): - expected_header = self.expected_header - expected_header['encoding'] = 'gzip' - expected_header['line skip'] = 3 + def test_read_detached_header_and_data(self): + expected_header = self.expected_header + expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) - data, header = nrrd.read(GZ_LINESKIP_NRRD_FILE_PATH, index_order=self.index_order) + data, header = nrrd.read(RAW_NHDR_FILE_PATH, index_order=self.index_order) - np.testing.assert_equal(self.expected_header, header) - np.testing.assert_equal(data, self.expected_data) + np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - def test_read_raw_header(self): - expected_header = {'type': 'float', 'dimension': 3, 'min': 0, 'max': 35.4} - header = nrrd.read_header(('NRRD0005', 'type: float', 'dimension: 3', 'min: 0', 'max: 35.4')) - self.assertEqual(expected_header, header) + def test_read_detached_header_and_data_with_byteskip_minus1(self): + expected_header = self.expected_header + expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) + expected_header['byte skip'] = -1 - expected_header = {'my extra info': 'my : colon-separated : values'} - header = nrrd.read_header(('NRRD0005', 'my extra info:=my : colon-separated : values')) - np.testing.assert_equal(expected_header, header) + data, header = nrrd.read(RAW_BYTESKIP_NHDR_FILE_PATH, index_order=self.index_order) - def test_read_dup_field_error_and_warn(self): - expected_header = {'type': 'float', 'dimension': 3} - header_txt_tuple = ('NRRD0005', 'type: float', 'dimension: 3', 'type: float') + np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - with self.assertRaisesRegex(nrrd.NRRDError, "Duplicate header field: 'type'"): - header = nrrd.read_header(header_txt_tuple) + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - import warnings - with warnings.catch_warnings(record=True) as w: - nrrd.reader.ALLOW_DUPLICATE_FIELD = True - header = nrrd.read_header(header_txt_tuple) + def test_read_detached_header_and_nifti_data_with_byteskip_minus1(self): + expected_header = self.expected_header + expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) + expected_header['byte skip'] = -1 + expected_header['encoding'] = 'gzip' + expected_header['data file'] = 'BallBinary30x30x30.nii.gz' - self.assertTrue("Duplicate header field: 'type'" in str(w[0].message)) + data, header = nrrd.read(GZ_BYTESKIP_NIFTI_NHDR_FILE_PATH, index_order=self.index_order) - self.assertEqual(expected_header, header) - nrrd.reader.ALLOW_DUPLICATE_FIELD = False - - def test_read_header_and_ascii_1d_data(self): - expected_header = {'dimension': 1, - 'encoding': 'ASCII', - 'kinds': ['domain'], - 'sizes': [27], - 'spacings': [1.0458000000000001], - 'type': 'unsigned char'} - - data, header = nrrd.read(ASCII_1D_NRRD_FILE_PATH, index_order=self.index_order) - - self.assertEqual(header, expected_header) - np.testing.assert_equal(data.dtype, np.uint8) - np.testing.assert_equal(data, np.arange(1, 28)) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_header_and_ascii_2d_data(self): - expected_header = {'dimension': 2, - 'encoding': 'ASCII', - 'kinds': ['domain', 'domain'], - 'sizes': [3, 9], - 'spacings': [1.0458000000000001, 2], - 'type': 'unsigned short'} - - data, header = nrrd.read(ASCII_2D_NRRD_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(header, expected_header) - np.testing.assert_equal(data.dtype, np.uint16) - - expected_shape = (3, 9) if self.index_order == 'F' else (9, 3) - np.testing.assert_equal(data, np.arange(1, 28).reshape(expected_shape, order=self.index_order)) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_read_simple_4d_nrrd(self): - expected_header = {'type': 'double', - 'dimension': 4, - 'space': 'right-anterior-superior', - 'sizes': np.array([1, 1, 1, 1]), - 'space directions': np.array([[1.5, 0., 0.], - [0., 1.5, 0.], - [0., 0., 1.], - [np.NaN, np.NaN, np.NaN]]), - 'endian': 'little', - 'encoding': 'raw', - 'measurement frame': np.array([[1.0001, 0., 0.], - [0., 1.0000000006, 0.], - [0., 0., 1.000000000000009]])} - - data, header = nrrd.read(RAW_4D_NRRD_FILE_PATH, index_order=self.index_order) - - np.testing.assert_equal(header, expected_header) - np.testing.assert_equal(data.dtype, np.float64) - np.testing.assert_equal(header['measurement frame'].dtype, np.float64) - np.testing.assert_equal(data, np.array([[[[0.76903426]]]])) - - # Test that the data read is able to be edited - self.assertTrue(data.flags['WRITEABLE']) - - def test_custom_fields_without_field_map(self): - expected_header = {'dimension': 1, - 'encoding': 'ASCII', - 'kinds': ['domain'], - 'sizes': [27], - 'spacings': [1.0458000000000001], - 'int': '24', - 'double': '25.5566', - 'string': 'This is a long string of information that is important.', - 'int list': '1 2 3 4 5 100', - 'double list': '0.2 0.502 0.8', - 'string list': 'words are split by space in list', - 'int vector': '(100, 200, -300)', - 'double vector': '(100.5,200.3,-300.99)', - 'int matrix': '(1,0,0) (0,1,0) (0,0,1)', - 'double matrix': '(1.2,0.3,0) (0,1.5,0) (0,-0.55,1.6)', - 'type': 'unsigned char'} - - header = nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH) - - self.assertEqual(header, expected_header) - - def test_custom_fields_with_field_map(self): - expected_header = {'dimension': 1, - 'encoding': 'ASCII', - 'kinds': ['domain'], - 'sizes': [27], - 'spacings': [1.0458000000000001], - 'int': 24, - 'double': 25.5566, - 'string': 'This is a long string of information that is important.', - 'int list': np.array([1, 2, 3, 4, 5, 100]), - 'double list': np.array([0.2, 0.502, 0.8]), - 'string list': ['words', 'are', 'split', 'by', 'space', 'in', 'list'], - 'int vector': np.array([100, 200, -300]), - 'double vector': np.array([100.5, 200.3, -300.99]), - 'int matrix': np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), - 'double matrix': np.array([[1.2, 0.3, 0.0], [0.0, 1.5, 0.0], [0.0, -0.55, 1.6]]), - 'type': 'unsigned char'} - - custom_field_map = {'int': 'int', - 'double': 'double', - 'string': 'string', - 'int list': 'int list', - 'double list': 'double list', - 'string list': 'string list', - 'int vector': 'int vector', - 'double vector': 'double vector', - 'int matrix': 'int matrix', - 'double matrix': 'double matrix'} - header = nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map) - - np.testing.assert_equal(header, expected_header) - - def test_invalid_custom_field(self): - custom_field_map = {'int': 'fake'} - - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid field type given: fake'): - nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map) - - def test_invalid_magic_line(self): - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid NRRD magic line. Is this an NRRD file?'): - nrrd.read_header(('invalid magic line', 'my extra info:=my : colon-separated : values')) - - def test_invalid_magic_line2(self): - with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported NRRD file version \\(version: 2000\\). This library ' - 'only supports v5 and below.'): - nrrd.read_header(('NRRD2000', 'my extra info:=my : colon-separated : values')) - - def test_invalid_magic_line3(self): - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid NRRD magic line: NRRDnono'): - nrrd.read_header(('NRRDnono', 'my extra info:=my : colon-separated : values')) - - def test_missing_required_field(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # Delete required field - del header['type'] + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - with self.assertRaisesRegex(nrrd.NRRDError, 'Header is missing required field: "type".'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + def test_read_detached_header_and_nifti_data(self): + with self.assertRaisesRegex( + nrrd.NRRDError, 'Size of the data does not equal the product of all the dimensions: 27000-27176=-176'): + nrrd.read(GZ_NIFTI_NHDR_FILE_PATH, index_order=self.index_order) - def test_wrong_sizes(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - np.testing.assert_equal(self.expected_header, header) + def test_read_detached_header_and_data_with_byteskip_minus5(self): + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid byteskip, allowed values are greater than or equal to -1'): + nrrd.read(RAW_INVALID_BYTESKIP_NHDR_FILE_PATH, index_order=self.index_order) - # Make the number of dimensions wrong - header['dimension'] = 2 + def test_read_header_and_gz_compressed_data(self): + expected_header = self.expected_header + expected_header['encoding'] = 'gzip' - with self.assertRaisesRegex(nrrd.NRRDError, 'Number of elements in sizes does not match dimension. ' - 'Dimension: 2, len\\(sizes\\): 3'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + data, header = nrrd.read(GZ_NRRD_FILE_PATH, index_order=self.index_order) - def test_invalid_encoding(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # Set the encoding to be incorrect - header['encoding'] = 'fake' + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported encoding: "fake"'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + def test_read_header_and_gz_compressed_data_with_byteskip_minus1(self): + expected_header = self.expected_header + expected_header['encoding'] = 'gzip' + expected_header['type'] = 'int16' + expected_header['byte skip'] = -1 - def test_detached_header_no_filename(self): - self.expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) + data, header = nrrd.read(GZ_BYTESKIP_NRRD_FILE_PATH, index_order=self.index_order) - with open(RAW_NHDR_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # No filename is specified for read_data - with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data file' - ' path is given'): - nrrd.read_data(header, fh) + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - def test_invalid_lineskip(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - np.testing.assert_equal(self.expected_header, header) + def test_read_header_and_bz2_compressed_data(self): + expected_header = self.expected_header + expected_header['encoding'] = 'bzip2' - # Set the line skip to be incorrect - header['line skip'] = -1 + data, header = nrrd.read(BZ2_NRRD_FILE_PATH, index_order=self.index_order) - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or equal to' - ' 0'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) - - def test_missing_endianness(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - # Delete the endian field from header - # Since our data is short (itemsize = 2), we should receive an error - del header['endian'] + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - with self.assertRaisesRegex(nrrd.NRRDError, 'Header is missing required field: "endian".'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + def test_read_header_and_gz_compressed_data_with_lineskip3(self): + expected_header = self.expected_header + expected_header['encoding'] = 'gzip' + expected_header['line skip'] = 3 - def test_big_endian(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - np.testing.assert_equal(self.expected_header, header) + data, header = nrrd.read(GZ_LINESKIP_NRRD_FILE_PATH, index_order=self.index_order) - # Set endianness to big to verify it is doing correctly - header['endian'] = 'big' + np.testing.assert_equal(self.expected_header, header) + np.testing.assert_equal(data, self.expected_data) - data = nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) - np.testing.assert_equal(data, self.expected_data.byteswap()) + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) - def test_invalid_endian(self): - with open(RAW_NRRD_FILE_PATH, 'rb') as fh: - header = nrrd.read_header(fh) - np.testing.assert_equal(self.expected_header, header) + def test_read_raw_header(self): + expected_header = {'type': 'float', 'dimension': 3, 'min': 0, 'max': 35.4} + header = nrrd.read_header(('NRRD0005', 'type: float', 'dimension: 3', 'min: 0', 'max: 35.4')) + self.assertEqual(expected_header, header) - # Set endianness to fake value - header['endian'] = 'fake' - - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid endian value in header: "fake"'): - nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) - - def test_invalid_index_order(self): - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid index order'): - nrrd.read(RAW_NRRD_FILE_PATH, index_order=None) - - def test_read_quoted_string_header(self): - header = nrrd.read_header([ - 'NRRD0004', - '# Complete NRRD file format specification at:', - '# http://teem.sourceforge.net/nrrd/format.html', - 'type: double', - 'dimension: 3', - 'space dimension: 3', - 'sizes: 32 40 16', - 'encoding: raw', - 'units: "mm" "cm" "in"', - 'space units: "mm" "cm" "in"', - 'labels: "X" "Y" "f(log(X, 10), Y)"', - 'space origin: (-0.79487200000000002,-1,-0.38461499999999998)' - ]) - - # Check that the quoted values were appropriately parsed - self.assertEqual(['mm', 'cm', 'in'], header['units']) - self.assertEqual(['mm', 'cm', 'in'], header['space units']) - self.assertEqual(['X', 'Y', 'f(log(X, 10), Y)'], header['labels']) - - def test_read_quoted_string_header_no_quotes(self): - header = nrrd.read_header([ - 'NRRD0004', - '# Complete NRRD file format specification at:', - '# http://teem.sourceforge.net/nrrd/format.html', - 'type: double', - 'dimension: 3', - 'space dimension: 3', - 'sizes: 32 40 16', - 'encoding: raw', - 'units: mm cm in', - 'space units: mm cm in', - 'labels: X Y f(log(X,10),Y)', - 'space origin: (-0.79487200000000002,-1,-0.38461499999999998)' - ]) - - # Check that the quoted values were appropriately parsed - self.assertEqual(['mm', 'cm', 'in'], header['units']) - self.assertEqual(['mm', 'cm', 'in'], header['space units']) - self.assertEqual(['X', 'Y', 'f(log(X,10),Y)'], header['labels']) - - -class TestReadingFunctionsFortran(TestReadingFunctions, unittest.TestCase): + expected_header = {'my extra info': 'my : colon-separated : values'} + header = nrrd.read_header(('NRRD0005', 'my extra info:=my : colon-separated : values')) + np.testing.assert_equal(expected_header, header) + + def test_read_dup_field_error_and_warn(self): + expected_header = {'type': 'float', 'dimension': 3} + header_txt_tuple = ('NRRD0005', 'type: float', 'dimension: 3', 'type: float') + + with self.assertRaisesRegex(nrrd.NRRDError, "Duplicate header field: 'type'"): + header = nrrd.read_header(header_txt_tuple) + + import warnings + with warnings.catch_warnings(record=True) as w: + nrrd.reader.ALLOW_DUPLICATE_FIELD = True + header = nrrd.read_header(header_txt_tuple) + + self.assertTrue("Duplicate header field: 'type'" in str(w[0].message)) + + self.assertEqual(expected_header, header) + nrrd.reader.ALLOW_DUPLICATE_FIELD = False + + def test_read_header_and_ascii_1d_data(self): + expected_header = {'dimension': 1, + 'encoding': 'ASCII', + 'kinds': ['domain'], + 'sizes': [27], + 'spacings': [1.0458000000000001], + 'type': 'unsigned char'} + + data, header = nrrd.read(ASCII_1D_NRRD_FILE_PATH, index_order=self.index_order) + + self.assertEqual(header, expected_header) + np.testing.assert_equal(data.dtype, np.uint8) + np.testing.assert_equal(data, np.arange(1, 28)) + + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) + + def test_read_header_and_ascii_2d_data(self): + expected_header = {'dimension': 2, + 'encoding': 'ASCII', + 'kinds': ['domain', 'domain'], + 'sizes': [3, 9], + 'spacings': [1.0458000000000001, 2], + 'type': 'unsigned short'} + + data, header = nrrd.read(ASCII_2D_NRRD_FILE_PATH, index_order=self.index_order) + + np.testing.assert_equal(header, expected_header) + np.testing.assert_equal(data.dtype, np.uint16) + + expected_shape = (3, 9) if self.index_order == 'F' else (9, 3) + np.testing.assert_equal(data, np.arange(1, 28).reshape(expected_shape, order=self.index_order)) + + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) + + def test_read_simple_4d_nrrd(self): + expected_header = {'type': 'double', + 'dimension': 4, + 'space': 'right-anterior-superior', + 'sizes': np.array([1, 1, 1, 1]), + 'space directions': np.array([[1.5, 0., 0.], + [0., 1.5, 0.], + [0., 0., 1.], + [np.NaN, np.NaN, np.NaN]]), + 'endian': 'little', + 'encoding': 'raw', + 'measurement frame': np.array([[1.0001, 0., 0.], + [0., 1.0000000006, 0.], + [0., 0., 1.000000000000009]])} + + data, header = nrrd.read(RAW_4D_NRRD_FILE_PATH, index_order=self.index_order) + + np.testing.assert_equal(header, expected_header) + np.testing.assert_equal(data.dtype, np.float64) + np.testing.assert_equal(header['measurement frame'].dtype, np.float64) + np.testing.assert_equal(data, np.array([[[[0.76903426]]]])) + + # Test that the data read is able to be edited + self.assertTrue(data.flags['WRITEABLE']) + + def test_custom_fields_without_field_map(self): + expected_header = {'dimension': 1, + 'encoding': 'ASCII', + 'kinds': ['domain'], + 'sizes': [27], + 'spacings': [1.0458000000000001], + 'int': '24', + 'double': '25.5566', + 'string': 'This is a long string of information that is important.', + 'int list': '1 2 3 4 5 100', + 'double list': '0.2 0.502 0.8', + 'string list': 'words are split by space in list', + 'int vector': '(100, 200, -300)', + 'double vector': '(100.5,200.3,-300.99)', + 'int matrix': '(1,0,0) (0,1,0) (0,0,1)', + 'double matrix': '(1.2,0.3,0) (0,1.5,0) (0,-0.55,1.6)', + 'type': 'unsigned char'} + + header = nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH) + + self.assertEqual(header, expected_header) + + def test_custom_fields_with_field_map(self): + expected_header = {'dimension': 1, + 'encoding': 'ASCII', + 'kinds': ['domain'], + 'sizes': [27], + 'spacings': [1.0458000000000001], + 'int': 24, + 'double': 25.5566, + 'string': 'This is a long string of information that is important.', + 'int list': np.array([1, 2, 3, 4, 5, 100]), + 'double list': np.array([0.2, 0.502, 0.8]), + 'string list': ['words', 'are', 'split', 'by', 'space', 'in', 'list'], + 'int vector': np.array([100, 200, -300]), + 'double vector': np.array([100.5, 200.3, -300.99]), + 'int matrix': np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), + 'double matrix': np.array([[1.2, 0.3, 0.0], [0.0, 1.5, 0.0], [0.0, -0.55, 1.6]]), + 'type': 'unsigned char'} + + custom_field_map = {'int': 'int', + 'double': 'double', + 'string': 'string', + 'int list': 'int list', + 'double list': 'double list', + 'string list': 'string list', + 'int vector': 'int vector', + 'double vector': 'double vector', + 'int matrix': 'int matrix', + 'double matrix': 'double matrix'} + header = nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map) + + np.testing.assert_equal(header, expected_header) + + def test_invalid_custom_field(self): + custom_field_map = {'int': 'fake'} + + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid field type given: fake'): + nrrd.read_header(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map) + + def test_invalid_magic_line(self): + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid NRRD magic line. Is this an NRRD file?'): + nrrd.read_header(('invalid magic line', 'my extra info:=my : colon-separated : values')) + + def test_invalid_magic_line2(self): + with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported NRRD file version \\(version: 2000\\). This library ' + 'only supports v5 and below.'): + nrrd.read_header(('NRRD2000', 'my extra info:=my : colon-separated : values')) + + def test_invalid_magic_line3(self): + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid NRRD magic line: NRRDnono'): + nrrd.read_header(('NRRDnono', 'my extra info:=my : colon-separated : values')) + + def test_missing_required_field(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Delete required field + del header['type'] + + with self.assertRaisesRegex(nrrd.NRRDError, 'Header is missing required field: "type".'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_wrong_sizes(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Make the number of dimensions wrong + header['dimension'] = 2 + + with self.assertRaisesRegex(nrrd.NRRDError, 'Number of elements in sizes does not match dimension. ' + 'Dimension: 2, len\\(sizes\\): 3'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_invalid_encoding(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Set the encoding to be incorrect + header['encoding'] = 'fake' + + with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported encoding: "fake"'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_detached_header_no_filename(self): + self.expected_header['data file'] = os.path.basename(RAW_DATA_FILE_PATH) + + with open(RAW_NHDR_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # No filename is specified for read_data + with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data file' + ' path is given'): + nrrd.read_data(header, fh) + + def test_invalid_lineskip(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Set the line skip to be incorrect + header['line skip'] = -1 + + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or equal to' + ' 0'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_missing_endianness(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Delete the endian field from header + # Since our data is short (itemsize = 2), we should receive an error + del header['endian'] + + with self.assertRaisesRegex(nrrd.NRRDError, 'Header is missing required field: "endian".'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_big_endian(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Set endianness to big to verify it is doing correctly + header['endian'] = 'big' + + data = nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + np.testing.assert_equal(data, self.expected_data.byteswap()) + + def test_invalid_endian(self): + with open(RAW_NRRD_FILE_PATH, 'rb') as fh: + header = nrrd.read_header(fh) + np.testing.assert_equal(self.expected_header, header) + + # Set endianness to fake value + header['endian'] = 'fake' + + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid endian value in header: "fake"'): + nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) + + def test_invalid_index_order(self): + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid index order'): + nrrd.read(RAW_NRRD_FILE_PATH, index_order=None) + + def test_read_quoted_string_header(self): + header = nrrd.read_header([ + 'NRRD0004', + '# Complete NRRD file format specification at:', + '# http://teem.sourceforge.net/nrrd/format.html', + 'type: double', + 'dimension: 3', + 'space dimension: 3', + 'sizes: 32 40 16', + 'encoding: raw', + 'units: "mm" "cm" "in"', + 'space units: "mm" "cm" "in"', + 'labels: "X" "Y" "f(log(X, 10), Y)"', + 'space origin: (-0.79487200000000002,-1,-0.38461499999999998)' + ]) + + # Check that the quoted values were appropriately parsed + self.assertEqual(['mm', 'cm', 'in'], header['units']) + self.assertEqual(['mm', 'cm', 'in'], header['space units']) + self.assertEqual(['X', 'Y', 'f(log(X, 10), Y)'], header['labels']) + + def test_read_quoted_string_header_no_quotes(self): + header = nrrd.read_header([ + 'NRRD0004', + '# Complete NRRD file format specification at:', + '# http://teem.sourceforge.net/nrrd/format.html', + 'type: double', + 'dimension: 3', + 'space dimension: 3', + 'sizes: 32 40 16', + 'encoding: raw', + 'units: mm cm in', + 'space units: mm cm in', + 'labels: X Y f(log(X,10),Y)', + 'space origin: (-0.79487200000000002,-1,-0.38461499999999998)' + ]) + + # Check that the quoted values were appropriately parsed + self.assertEqual(['mm', 'cm', 'in'], header['units']) + self.assertEqual(['mm', 'cm', 'in'], header['space units']) + self.assertEqual(['X', 'Y', 'f(log(X,10),Y)'], header['labels']) + + +class TestReadingFunctionsFortran(Abstract.TestReadingFunctions): index_order = 'F' -class TestReadingFunctionsC(TestReadingFunctions, unittest.TestCase): +class TestReadingFunctionsC(Abstract.TestReadingFunctions): index_order = 'C' diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index 916e8e8..fcdae8a 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -1,5 +1,6 @@ import io import tempfile +from typing import ClassVar, Literal import numpy as np @@ -7,395 +8,398 @@ from nrrd.tests.util import * -class TestWritingFunctions(unittest.TestCase): - def setUp(self): - self.temp_write_dir = tempfile.mkdtemp('nrrdtest') - self.data_input, _ = nrrd.read(RAW_NRRD_FILE_PATH, index_order=self.index_order) +class Abstract: + class TestWritingFunctions(unittest.TestCase): + index_order: ClassVar[Literal['F', 'C']] - with open(RAW_DATA_FILE_PATH, 'rb') as fh: - self.expected_data = fh.read() + def setUp(self): + self.temp_write_dir = tempfile.mkdtemp('nrrdtest') + self.data_input, _ = nrrd.read(RAW_NRRD_FILE_PATH, index_order=self.index_order) - def write_and_read_back(self, encoding=None, level=9): - output_filename = os.path.join(self.temp_write_dir, f'testfile_{encoding}_{str(level)}.nrrd') - headers = {} - if encoding is not None: - headers['encoding'] = encoding - nrrd.write(output_filename, self.data_input, headers, compression_level=level, - index_order=self.index_order) + with open(RAW_DATA_FILE_PATH, 'rb') as fh: + self.expected_data = fh.read() - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header.get('encoding'), encoding or 'gzip') # default is gzip is not specified + def write_and_read_back(self, encoding=None, level=9): + output_filename = os.path.join(self.temp_write_dir, f'testfile_{encoding}_{str(level)}.nrrd') + headers = {} + if encoding is not None: + headers['encoding'] = encoding + nrrd.write(output_filename, self.data_input, headers, compression_level=level, + index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), encoding or 'gzip') # default is gzip is not specified + + return output_filename - return output_filename + def test_write_default_header(self): + self.write_and_read_back() - def test_write_default_header(self): - self.write_and_read_back() + def test_write_raw(self): + self.write_and_read_back('raw') - def test_write_raw(self): - self.write_and_read_back('raw') + def test_write_gz(self): + self.write_and_read_back('gzip') - def test_write_gz(self): - self.write_and_read_back('gzip') + def test_write_bzip2(self): + self.write_and_read_back('bzip2') - def test_write_bzip2(self): - self.write_and_read_back('bzip2') + def test_write_gz_level1(self): + filename = self.write_and_read_back('gzip', level=1) - def test_write_gz_level1(self): - filename = self.write_and_read_back('gzip', level=1) - - self.assertLess(os.path.getsize(GZ_NRRD_FILE_PATH), os.path.getsize(filename)) - - def test_write_bzip2_level1(self): - _ = self.write_and_read_back('bzip2', level=1) - - # note: we don't currently assert reduction here, because with the binary ball test data, - # the output size does not change at different bz2 levels. - # self.assertLess(os.path.getsize(BZ2_NRRD_FILE_PATH), os.path.getsize(fn)) - - def test_write_ascii_1d(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_1d.nrrd') - - x = np.arange(1, 28) - nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['encoding'], 'ascii') - np.testing.assert_equal(data, x) - - def test_write_ascii_2d(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_2d.nrrd') - - x = np.arange(1, 28).reshape((3, 9), order=self.index_order) - nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['encoding'], 'ascii') - np.testing.assert_equal(data, x) - - def test_write_ascii_3d(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_3d.nrrd') - - x = np.arange(1, 28).reshape((3, 3, 3), order=self.index_order) - nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['encoding'], 'ascii') - np.testing.assert_equal(x, data) - - def test_write_custom_fields_without_custom_field_map(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_custom_fields.nrrd') - - data, header = nrrd.read(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, index_order=self.index_order) - nrrd.write(output_filename, data, header, index_order=self.index_order) - - with open(output_filename) as fh: - lines = fh.readlines() - - # Strip newline from end of line - lines = [line.rstrip() for line in lines] - - self.assertEqual(lines[5], 'type: uint8') - self.assertEqual(lines[6], 'dimension: 1') - self.assertEqual(lines[7], 'sizes: 27') - self.assertEqual(lines[8], 'kinds: domain') - self.assertEqual(lines[9], 'encoding: ASCII') - self.assertEqual(lines[10], 'spacings: 1.0458000000000001') - self.assertEqual(lines[11], 'int:=24') - self.assertEqual(lines[12], 'double:=25.5566') - self.assertEqual(lines[13], 'string:=This is a long string of information that is important.') - self.assertEqual(lines[14], 'int list:=1 2 3 4 5 100') - self.assertEqual(lines[15], 'double list:=0.2 0.502 0.8') - self.assertEqual(lines[16], 'string list:=words are split by space in list') - self.assertEqual(lines[17], 'int vector:=(100, 200, -300)') - self.assertEqual(lines[18], 'double vector:=(100.5,200.3,-300.99)') - self.assertEqual(lines[19], 'int matrix:=(1,0,0) (0,1,0) (0,0,1)') - self.assertEqual(lines[20], 'double matrix:=(1.2,0.3,0) (0,1.5,0) (0,-0.55,1.6)') - - def test_write_custom_fields_with_custom_field_map(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_custom_fields.nrrd') - - custom_field_map = {'int': 'int', - 'double': 'double', - 'string': 'string', - 'int list': 'int list', - 'double list': 'double list', - 'string list': 'string list', - 'int vector': 'int vector', - 'double vector': 'double vector', - 'int matrix': 'int matrix', - 'double matrix': 'double matrix'} - - data, header = nrrd.read(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map, index_order=self.index_order) - nrrd.write(output_filename, data, header, custom_field_map=custom_field_map, index_order=self.index_order) - - with open(output_filename) as fh: - lines = fh.readlines() - - # Strip newline from end of line - lines = [line.rstrip() for line in lines] - - self.assertEqual(lines[5], 'type: uint8') - self.assertEqual(lines[6], 'dimension: 1') - self.assertEqual(lines[7], 'sizes: 27') - self.assertEqual(lines[8], 'kinds: domain') - self.assertEqual(lines[9], 'encoding: ASCII') - self.assertEqual(lines[10], 'spacings: 1.0458000000000001') - self.assertEqual(lines[11], 'int:=24') - self.assertEqual(lines[12], 'double:=25.5566') - self.assertEqual(lines[13], 'string:=This is a long string of information that is important.') - self.assertEqual(lines[14], 'int list:=1 2 3 4 5 100') - self.assertEqual(lines[15], 'double list:=0.20000000000000001 0.502 0.80000000000000004') - self.assertEqual(lines[16], 'string list:=words are split by space in list') - self.assertEqual(lines[17], 'int vector:=(100,200,-300)') - self.assertEqual(lines[18], 'double vector:=(100.5,200.30000000000001,-300.99000000000001)') - self.assertEqual(lines[19], 'int matrix:=(1,0,0) (0,1,0) (0,0,1)') - self.assertEqual(lines[20], 'double matrix:=(1.2,0.29999999999999999,0) (0,1.5,0) (0,-0.55000000000000004,' - '1.6000000000000001)') - - def test_write_detached_raw_as_nrrd(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nrrd') - - nrrd.write(output_data_filename, self.data_input, {'encoding': 'raw'}, detached_header=True, - relative_data_path=False, index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'raw') - self.assertEqual(header['data file'], output_data_filename) - - def test_write_detached_raw_odd_extension(self): - output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nrrd2') - - nrrd.write(output_data_filename, self.data_input, {'encoding': 'raw'}, detached_header=True, - index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_data_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'raw') - self.assertEqual('data file' in header, False) - - def test_write_fake_encoding(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid encoding specification while writing NRRD file: fake'): - nrrd.write(output_filename, self.data_input, {'encoding': 'fake'}, index_order=self.index_order) - - def test_write_detached_raw(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - - # Data & header are still detached even though detached_header is False because the filename is .nhdr - # Test also checks detached data filename that it is relative (default value) - nrrd.write(output_filename, self.data_input, {'encoding': 'raw'}, detached_header=False, - index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'raw') - self.assertEqual(header['data file'], 'testfile_detached_raw.raw') - - def test_write_detached_gz(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.raw.gz') - - # Data & header are still detached even though detached_header is False because the filename is .nhdr - # Test also checks detached data filename that it is absolute - nrrd.write(output_filename, self.data_input, {'encoding': 'gz'}, detached_header=False, - relative_data_path=False, index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'gz') - self.assertEqual(header['data file'], output_data_filename) - - def test_write_detached_bz2(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - - # Data & header are still detached even though detached_header is False because the filename is .nhdr - # Test also checks detached data filename that it is relative (default value) - nrrd.write(output_filename, self.data_input, {'encoding': 'bz2'}, detached_header=False, - index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'bz2') - self.assertEqual(header['data file'], 'testfile_detached_raw.raw.bz2') - - def test_write_detached_ascii(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - - # Data & header are still detached even though detached_header is False because the filename is .nhdr - # Test also checks detached data filename that it is relative (default value) - nrrd.write(output_filename, self.data_input, {'encoding': 'txt'}, detached_header=False, - index_order=self.index_order) - - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header['encoding'], 'txt') - self.assertEqual(header['data file'], 'testfile_detached_raw.txt') - - def test_invalid_custom_field(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_invalid_custom_field.nrrd') - header = {'int': 12} - custom_field_map = {'int': 'fake'} - - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid field type given: fake'): - nrrd.write(output_filename, np.zeros((3, 9)), header, custom_field_map=custom_field_map, + self.assertLess(os.path.getsize(GZ_NRRD_FILE_PATH), os.path.getsize(filename)) + + def test_write_bzip2_level1(self): + _ = self.write_and_read_back('bzip2', level=1) + + # note: we don't currently assert reduction here, because with the binary ball test data, + # the output size does not change at different bz2 levels. + # self.assertLess(os.path.getsize(BZ2_NRRD_FILE_PATH), os.path.getsize(fn)) + + def test_write_ascii_1d(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_1d.nrrd') + + x = np.arange(1, 28) + nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['encoding'], 'ascii') + np.testing.assert_equal(data, x) + + def test_write_ascii_2d(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_2d.nrrd') + + x = np.arange(1, 28).reshape((3, 9), order=self.index_order) + nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['encoding'], 'ascii') + np.testing.assert_equal(data, x) + + def test_write_ascii_3d(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_3d.nrrd') + + x = np.arange(1, 28).reshape((3, 3, 3), order=self.index_order) + nrrd.write(output_filename, x, {'encoding': 'ascii'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['encoding'], 'ascii') + np.testing.assert_equal(x, data) + + def test_write_custom_fields_without_custom_field_map(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_custom_fields.nrrd') + + data, header = nrrd.read(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, index_order=self.index_order) + nrrd.write(output_filename, data, header, index_order=self.index_order) + + with open(output_filename) as fh: + lines = fh.readlines() + + # Strip newline from end of line + lines = [line.rstrip() for line in lines] + + self.assertEqual(lines[5], 'type: uint8') + self.assertEqual(lines[6], 'dimension: 1') + self.assertEqual(lines[7], 'sizes: 27') + self.assertEqual(lines[8], 'kinds: domain') + self.assertEqual(lines[9], 'encoding: ASCII') + self.assertEqual(lines[10], 'spacings: 1.0458000000000001') + self.assertEqual(lines[11], 'int:=24') + self.assertEqual(lines[12], 'double:=25.5566') + self.assertEqual(lines[13], 'string:=This is a long string of information that is important.') + self.assertEqual(lines[14], 'int list:=1 2 3 4 5 100') + self.assertEqual(lines[15], 'double list:=0.2 0.502 0.8') + self.assertEqual(lines[16], 'string list:=words are split by space in list') + self.assertEqual(lines[17], 'int vector:=(100, 200, -300)') + self.assertEqual(lines[18], 'double vector:=(100.5,200.3,-300.99)') + self.assertEqual(lines[19], 'int matrix:=(1,0,0) (0,1,0) (0,0,1)') + self.assertEqual(lines[20], 'double matrix:=(1.2,0.3,0) (0,1.5,0) (0,-0.55,1.6)') + + def test_write_custom_fields_with_custom_field_map(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_custom_fields.nrrd') + + custom_field_map = {'int': 'int', + 'double': 'double', + 'string': 'string', + 'int list': 'int list', + 'double list': 'double list', + 'string list': 'string list', + 'int vector': 'int vector', + 'double vector': 'double vector', + 'int matrix': 'int matrix', + 'double matrix': 'double matrix'} + + data, header = nrrd.read(ASCII_1D_CUSTOM_FIELDS_FILE_PATH, custom_field_map, index_order=self.index_order) + nrrd.write(output_filename, data, header, custom_field_map=custom_field_map, index_order=self.index_order) + + with open(output_filename) as fh: + lines = fh.readlines() + + # Strip newline from end of line + lines = [line.rstrip() for line in lines] + + self.assertEqual(lines[5], 'type: uint8') + self.assertEqual(lines[6], 'dimension: 1') + self.assertEqual(lines[7], 'sizes: 27') + self.assertEqual(lines[8], 'kinds: domain') + self.assertEqual(lines[9], 'encoding: ASCII') + self.assertEqual(lines[10], 'spacings: 1.0458000000000001') + self.assertEqual(lines[11], 'int:=24') + self.assertEqual(lines[12], 'double:=25.5566') + self.assertEqual(lines[13], 'string:=This is a long string of information that is important.') + self.assertEqual(lines[14], 'int list:=1 2 3 4 5 100') + self.assertEqual(lines[15], 'double list:=0.20000000000000001 0.502 0.80000000000000004') + self.assertEqual(lines[16], 'string list:=words are split by space in list') + self.assertEqual(lines[17], 'int vector:=(100,200,-300)') + self.assertEqual(lines[18], 'double vector:=(100.5,200.30000000000001,-300.99000000000001)') + self.assertEqual(lines[19], 'int matrix:=(1,0,0) (0,1,0) (0,0,1)') + self.assertEqual(lines[20], 'double matrix:=(1.2,0.29999999999999999,0) (0,1.5,0) (0,-0.55000000000000004,' + '1.6000000000000001)') + + def test_write_detached_raw_as_nrrd(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') + output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nrrd') + + nrrd.write(output_data_filename, self.data_input, {'encoding': 'raw'}, detached_header=True, + relative_data_path=False, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'raw') + self.assertEqual(header['data file'], output_data_filename) + + def test_write_detached_raw_odd_extension(self): + output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nrrd2') + + nrrd.write(output_data_filename, self.data_input, {'encoding': 'raw'}, detached_header=True, index_order=self.index_order) - def test_remove_endianness(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_remove_endianness.nrrd') + # Read back the same file + data, header = nrrd.read(output_data_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'raw') + self.assertEqual('data file' in header, False) - x = np.arange(1, 28) - nrrd.write(output_filename, x, {'encoding': 'ascii', 'endian': 'little', 'space': 'right-anterior-superior', - 'space dimension': 3}, index_order=self.index_order) + def test_write_fake_encoding(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['encoding'], 'ascii') + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid encoding specification while writing NRRD file: fake'): + nrrd.write(output_filename, self.data_input, {'encoding': 'fake'}, index_order=self.index_order) + + def test_write_detached_raw(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') + + # Data & header are still detached even though detached_header is False because the filename is .nhdr + # Test also checks detached data filename that it is relative (default value) + nrrd.write(output_filename, self.data_input, {'encoding': 'raw'}, detached_header=False, + index_order=self.index_order) - # Check for endian and space dimension, both of these should have been removed from the header - # Endian because it is an ASCII encoded file and space dimension because space is specified - self.assertFalse('endian' in header) - self.assertFalse('space dimension' in header) - np.testing.assert_equal(data, x) + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'raw') + self.assertEqual(header['data file'], 'testfile_detached_raw.raw') + + def test_write_detached_gz(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') + output_data_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.raw.gz') + + # Data & header are still detached even though detached_header is False because the filename is .nhdr + # Test also checks detached data filename that it is absolute + nrrd.write(output_filename, self.data_input, {'encoding': 'gz'}, detached_header=False, + relative_data_path=False, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'gz') + self.assertEqual(header['data file'], output_data_filename) + + def test_write_detached_bz2(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') + + # Data & header are still detached even though detached_header is False because the filename is .nhdr + # Test also checks detached data filename that it is relative (default value) + nrrd.write(output_filename, self.data_input, {'encoding': 'bz2'}, detached_header=False, + index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'bz2') + self.assertEqual(header['data file'], 'testfile_detached_raw.raw.bz2') + + def test_write_detached_ascii(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') + + # Data & header are still detached even though detached_header is False because the filename is .nhdr + # Test also checks detached data filename that it is relative (default value) + nrrd.write(output_filename, self.data_input, {'encoding': 'txt'}, detached_header=False, + index_order=self.index_order) - def test_unsupported_encoding(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_unsupported_encoding.nrrd') - header = {'encoding': 'fake'} + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header['encoding'], 'txt') + self.assertEqual(header['data file'], 'testfile_detached_raw.txt') - with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported encoding: "fake"'): - nrrd.write(output_filename, np.zeros((3, 9)), header, index_order=self.index_order) + def test_invalid_custom_field(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_invalid_custom_field.nrrd') + header = {'int': 12} + custom_field_map = {'int': 'fake'} - def test_invalid_index_order(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_invalid_index_order.nrrd') + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid field type given: fake'): + nrrd.write(output_filename, np.zeros((3, 9)), header, custom_field_map=custom_field_map, + index_order=self.index_order) - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid index order'): - nrrd.write(output_filename, np.zeros((3, 9)), index_order=None) + def test_remove_endianness(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_remove_endianness.nrrd') - def test_quoted_string_list_header(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_3d.nrrd') + x = np.arange(1, 28) + nrrd.write(output_filename, x, {'encoding': 'ascii', 'endian': 'little', 'space': 'right-anterior-superior', + 'space dimension': 3}, index_order=self.index_order) - x = np.arange(1, 28).reshape((3, 3, 3), order=self.index_order) - nrrd.write(output_filename, x, { - 'encoding': 'ascii', - 'units': ['mm', 'cm', 'in'], - 'space units': ['mm', 'cm', 'in'], - 'labels': ['X', 'Y', 'f(log(X, 10), Y)'], - }, index_order=self.index_order) + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['encoding'], 'ascii') - with open(output_filename) as fh: - lines = fh.readlines() + # Check for endian and space dimension, both of these should have been removed from the header + # Endian because it is an ASCII encoded file and space dimension because space is specified + self.assertFalse('endian' in header) + self.assertFalse('space dimension' in header) + np.testing.assert_equal(data, x) - # Strip newline from end of line - lines = [line.rstrip() for line in lines] + def test_unsupported_encoding(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_unsupported_encoding.nrrd') + header = {'encoding': 'fake'} - # Note the order of the lines dont matter, we just want to verify theyre outputted correctly - self.assertTrue('units: "mm" "cm" "in"' in lines) - self.assertTrue('space units: "mm" "cm" "in"' in lines) - self.assertTrue('labels: "X" "Y" "f(log(X, 10), Y)"' in lines) + with self.assertRaisesRegex(nrrd.NRRDError, 'Unsupported encoding: "fake"'): + nrrd.write(output_filename, np.zeros((3, 9)), header, index_order=self.index_order) - def test_write_detached_datafile_check(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') + def test_invalid_index_order(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_invalid_index_order.nrrd') - nrrd.write(output_filename, self.data_input, {'datafile': 'testfile_detachedWRONG.gz'}, detached_header=True, - index_order=self.index_order) + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid index order'): + nrrd.write(output_filename, np.zeros((3, 9)), index_order=None) - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['data file'], 'testfile_detached.raw.gz') + def test_quoted_string_list_header(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_3d.nrrd') - def test_write_detached_datafile_check2(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') + x = np.arange(1, 28).reshape((3, 3, 3), order=self.index_order) + nrrd.write(output_filename, x, { + 'encoding': 'ascii', + 'units': ['mm', 'cm', 'in'], + 'space units': ['mm', 'cm', 'in'], + 'labels': ['X', 'Y', 'f(log(X, 10), Y)'], + }, index_order=self.index_order) - nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detachedWRONG.gz'}, detached_header=True, - index_order=self.index_order) + with open(output_filename) as fh: + lines = fh.readlines() - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['data file'], 'testfile_detached.raw.gz') + # Strip newline from end of line + lines = [line.rstrip() for line in lines] - def test_write_detached_datafile_custom_name(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') - # Specify a custom path to write the - output_header_filename = os.path.join(self.temp_write_dir, 'testfile_detachedDifferent.gz') + # Note the order of the lines dont matter, we just want to verify theyre outputted correctly + self.assertTrue('units: "mm" "cm" "in"' in lines) + self.assertTrue('space units: "mm" "cm" "in"' in lines) + self.assertTrue('labels: "X" "Y" "f(log(X, 10), Y)"' in lines) - nrrd.write(output_filename, self.data_input, detached_header=output_header_filename, - index_order=self.index_order) + def test_write_detached_datafile_check(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') - # Read back the same file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertEqual(header['data file'], 'testfile_detachedDifferent.gz') + nrrd.write(output_filename, self.data_input, {'datafile': 'testfile_detachedWRONG.gz'}, detached_header=True, + index_order=self.index_order) - def test_write_check_remove_datafile(self): - output_filename = os.path.join(self.temp_write_dir, 'testfile.nrrd') + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['data file'], 'testfile_detached.raw.gz') - nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detached.gz'}, detached_header=False, - index_order=self.index_order) + def test_write_detached_datafile_check2(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') - # Read back the same file - # The 'data file' parameter should be missing since this is NOT a detached file - data, header = nrrd.read(output_filename, index_order=self.index_order) - self.assertFalse('data file' in header) + nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detachedWRONG.gz'}, detached_header=True, + index_order=self.index_order) - def test_write_memory(self): - default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') - nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['data file'], 'testfile_detached.raw.gz') - memory_nrrd = io.BytesIO() + def test_write_detached_datafile_custom_name(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') + # Specify a custom path to write the + output_header_filename = os.path.join(self.temp_write_dir, 'testfile_detachedDifferent.gz') - nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) + nrrd.write(output_filename, self.data_input, detached_header=output_header_filename, + index_order=self.index_order) - memory_nrrd.seek(0) + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(header['data file'], 'testfile_detachedDifferent.gz') - data, header = nrrd.read(default_output_filename, index_order=self.index_order) - memory_header = nrrd.read_header(memory_nrrd) - memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, index_order=self.index_order) + def test_write_check_remove_datafile(self): + output_filename = os.path.join(self.temp_write_dir, 'testfile.nrrd') - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) - self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) - self.assertSequenceEqual(header, memory_header) + nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detached.gz'}, detached_header=False, + index_order=self.index_order) - def test_write_memory_file_handle(self): - default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') - nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) + # Read back the same file + # The 'data file' parameter should be missing since this is NOT a detached file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertFalse('data file' in header) - default_output_memory_filename = os.path.join(self.temp_write_dir, 'testfile_default_memory_filename.nrrd') + def test_write_memory(self): + default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') + nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) - with open(default_output_memory_filename, mode='wb') as memory_nrrd: + memory_nrrd = io.BytesIO() nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) - data, header = nrrd.read(default_output_filename, index_order=self.index_order) + memory_nrrd.seek(0) - with open(default_output_memory_filename, mode='rb') as memory_nrrd: + data, header = nrrd.read(default_output_filename, index_order=self.index_order) memory_header = nrrd.read_header(memory_nrrd) - memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, - index_order=self.index_order) + memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, index_order=self.index_order) + + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) + self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) + self.assertSequenceEqual(header, memory_header) + + def test_write_memory_file_handle(self): + default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') + nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) + + default_output_memory_filename = os.path.join(self.temp_write_dir, 'testfile_default_memory_filename.nrrd') + + with open(default_output_memory_filename, mode='wb') as memory_nrrd: + + nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) + + data, header = nrrd.read(default_output_filename, index_order=self.index_order) + + with open(default_output_memory_filename, mode='rb') as memory_nrrd: + memory_header = nrrd.read_header(memory_nrrd) + memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, + index_order=self.index_order) - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) - self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) - self.assertSequenceEqual(header, memory_header) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) + self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) + self.assertSequenceEqual(header, memory_header) -class TestWritingFunctionsFortran(TestWritingFunctions, unittest.TestCase): +class TestWritingFunctionsFortran(Abstract.TestWritingFunctions): index_order = 'F' -class TestWritingFunctionsC(TestWritingFunctions, unittest.TestCase): +class TestWritingFunctionsC(Abstract.TestWritingFunctions): index_order = 'C' From 488d153d5767b2a1f83f924d27b6eb84f07f8f9d Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 08:05:30 -0500 Subject: [PATCH 04/12] Formatting fixes --- nrrd/tests/test_reading.py | 8 ++++---- nrrd/tests/test_writing.py | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index d716c67..b8cd37f 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -362,8 +362,8 @@ def test_detached_header_no_filename(self): np.testing.assert_equal(self.expected_header, header) # No filename is specified for read_data - with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data file' - ' path is given'): + with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data ' + 'file path is given'): nrrd.read_data(header, fh) def test_invalid_lineskip(self): @@ -374,8 +374,8 @@ def test_invalid_lineskip(self): # Set the line skip to be incorrect header['line skip'] = -1 - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or equal to' - ' 0'): + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or ' + 'equal to 0'): nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) def test_missing_endianness(self): diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index fcdae8a..8c8821b 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -158,8 +158,8 @@ def test_write_custom_fields_with_custom_field_map(self): self.assertEqual(lines[17], 'int vector:=(100,200,-300)') self.assertEqual(lines[18], 'double vector:=(100.5,200.30000000000001,-300.99000000000001)') self.assertEqual(lines[19], 'int matrix:=(1,0,0) (0,1,0) (0,0,1)') - self.assertEqual(lines[20], 'double matrix:=(1.2,0.29999999999999999,0) (0,1.5,0) (0,-0.55000000000000004,' - '1.6000000000000001)') + self.assertEqual(lines[20], 'double matrix:=(1.2,0.29999999999999999,0) (0,1.5,0) (0,' + '-0.55000000000000004,1.6000000000000001)') def test_write_detached_raw_as_nrrd(self): output_filename = os.path.join(self.temp_write_dir, 'testfile_detached_raw.nhdr') @@ -313,8 +313,8 @@ def test_quoted_string_list_header(self): def test_write_detached_datafile_check(self): output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') - nrrd.write(output_filename, self.data_input, {'datafile': 'testfile_detachedWRONG.gz'}, detached_header=True, - index_order=self.index_order) + nrrd.write(output_filename, self.data_input, {'datafile': 'testfile_detachedWRONG.gz'}, + detached_header=True, index_order=self.index_order) # Read back the same file data, header = nrrd.read(output_filename, index_order=self.index_order) @@ -323,8 +323,8 @@ def test_write_detached_datafile_check(self): def test_write_detached_datafile_check2(self): output_filename = os.path.join(self.temp_write_dir, 'testfile_detached.nhdr') - nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detachedWRONG.gz'}, detached_header=True, - index_order=self.index_order) + nrrd.write(output_filename, self.data_input, {'data file': 'testfile_detachedWRONG.gz'}, + detached_header=True, index_order=self.index_order) # Read back the same file data, header = nrrd.read(output_filename, index_order=self.index_order) @@ -365,7 +365,8 @@ def test_write_memory(self): data, header = nrrd.read(default_output_filename, index_order=self.index_order) memory_header = nrrd.read_header(memory_nrrd) - memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, index_order=self.index_order) + memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, + index_order=self.index_order) self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) From b6ed6df0b6f76471b52f2b0381df416dcd3ddb90 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 08:06:04 -0500 Subject: [PATCH 05/12] Fix empty blank line --- nrrd/tests/test_writing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index 8c8821b..c02cfeb 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -380,7 +380,6 @@ def test_write_memory_file_handle(self): default_output_memory_filename = os.path.join(self.temp_write_dir, 'testfile_default_memory_filename.nrrd') with open(default_output_memory_filename, mode='wb') as memory_nrrd: - nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) data, header = nrrd.read(default_output_filename, index_order=self.index_order) From 74ff04f63be346b6669598788cd1880c2070e0cb Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 08:43:31 -0500 Subject: [PATCH 06/12] Remove write_and_read_back function It was only used in a few instances and it didn't save that many lines of code. --- nrrd/tests/test_writing.py | 62 ++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index c02cfeb..9920351 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -19,44 +19,66 @@ def setUp(self): with open(RAW_DATA_FILE_PATH, 'rb') as fh: self.expected_data = fh.read() - def write_and_read_back(self, encoding=None, level=9): - output_filename = os.path.join(self.temp_write_dir, f'testfile_{encoding}_{str(level)}.nrrd') - headers = {} - if encoding is not None: - headers['encoding'] = encoding - nrrd.write(output_filename, self.data_input, headers, compression_level=level, - index_order=self.index_order) + def test_write_default_header(self): + output_filename = os.path.join(self.temp_write_dir, f'testfile_default.nrrd') + nrrd.write(output_filename, self.data_input, {}, index_order=self.index_order) # Read back the same file data, header = nrrd.read(output_filename, index_order=self.index_order) self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(header.get('encoding'), encoding or 'gzip') # default is gzip is not specified - - return output_filename - - def test_write_default_header(self): - self.write_and_read_back() + self.assertEqual(header.get('encoding'), 'gzip') # default is gzip if not specified def test_write_raw(self): - self.write_and_read_back('raw') + output_filename = os.path.join(self.temp_write_dir, f'testfile_raw.nrrd') + nrrd.write(output_filename, self.data_input, {'encoding': 'raw'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), 'raw') def test_write_gz(self): - self.write_and_read_back('gzip') + output_filename = os.path.join(self.temp_write_dir, f'testfile_gzip.nrrd') + nrrd.write(output_filename, self.data_input, {'encoding': 'gzip'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), 'gzip') def test_write_bzip2(self): - self.write_and_read_back('bzip2') + output_filename = os.path.join(self.temp_write_dir, f'testfile_bzip2.nrrd') + nrrd.write(output_filename, self.data_input, {'encoding': 'bzip2'}, index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), 'bzip2') def test_write_gz_level1(self): - filename = self.write_and_read_back('gzip', level=1) + output_filename = os.path.join(self.temp_write_dir, f'testfile_gzip_1.nrrd') + nrrd.write(output_filename, self.data_input, {'encoding': 'gzip'}, compression_level=1, + index_order=self.index_order) - self.assertLess(os.path.getsize(GZ_NRRD_FILE_PATH), os.path.getsize(filename)) + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), 'gzip') + self.assertLess(os.path.getsize(GZ_NRRD_FILE_PATH), os.path.getsize(output_filename)) def test_write_bzip2_level1(self): - _ = self.write_and_read_back('bzip2', level=1) + output_filename = os.path.join(self.temp_write_dir, f'testfile_bzip2_1.nrrd') + nrrd.write(output_filename, self.data_input, {'encoding': 'bzip2'}, compression_level=1, + index_order=self.index_order) + + # Read back the same file + data, header = nrrd.read(output_filename, index_order=self.index_order) + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(header.get('encoding'), 'bzip2') # note: we don't currently assert reduction here, because with the binary ball test data, # the output size does not change at different bz2 levels. - # self.assertLess(os.path.getsize(BZ2_NRRD_FILE_PATH), os.path.getsize(fn)) + # self.assertLess(os.path.getsize(BZ2_NRRD_FILE_PATH), os.path.getsize(output_filename)) def test_write_ascii_1d(self): output_filename = os.path.join(self.temp_write_dir, 'testfile_ascii_1d.nrrd') From 9f91c6e7ab590ee186b5d66320c4376f0d19ae3f Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 08:58:16 -0500 Subject: [PATCH 07/12] Add more tests for writing to BytesIO memory --- nrrd/tests/test_writing.py | 117 ++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 40 deletions(-) diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index 9920351..8e27004 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -375,46 +375,83 @@ def test_write_check_remove_datafile(self): data, header = nrrd.read(output_filename, index_order=self.index_order) self.assertFalse('data file' in header) - def test_write_memory(self): - default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') - nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) - - memory_nrrd = io.BytesIO() - - nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) - - memory_nrrd.seek(0) - - data, header = nrrd.read(default_output_filename, index_order=self.index_order) - memory_header = nrrd.read_header(memory_nrrd) - memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, - index_order=self.index_order) - - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) - self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) - self.assertSequenceEqual(header, memory_header) - - def test_write_memory_file_handle(self): - default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') - nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) - - default_output_memory_filename = os.path.join(self.temp_write_dir, 'testfile_default_memory_filename.nrrd') - - with open(default_output_memory_filename, mode='wb') as memory_nrrd: - nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) - - data, header = nrrd.read(default_output_filename, index_order=self.index_order) - - with open(default_output_memory_filename, mode='rb') as memory_nrrd: - memory_header = nrrd.read_header(memory_nrrd) - memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, - index_order=self.index_order) - - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) - self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) - self.assertSequenceEqual(header, memory_header) + def test_write_memory_default(self): + kwargs = { + 'header': {}, + 'index_order': self.index_order + } + + memory_nrrd_file = io.BytesIO() + nrrd.write(memory_nrrd_file, self.data_input, **kwargs) + memory_nrrd_file.seek(0) + memory_nrrd = memory_nrrd_file.readlines() + + expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') + nrrd.write(expected_filename, self.data_input, **kwargs) + with open(expected_filename, 'rb') as fh: + expected_nrrd = fh.readlines() + + self.assertEqual(expected_nrrd, memory_nrrd) + + def test_write_memory_raw(self): + kwargs = { + 'header': { + 'encoding': 'raw' + }, + 'index_order': self.index_order + } + + memory_nrrd_file = io.BytesIO() + nrrd.write(memory_nrrd_file, self.data_input, **kwargs) + memory_nrrd_file.seek(0) + memory_nrrd = memory_nrrd_file.readlines() + + expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') + nrrd.write(expected_filename, self.data_input, **kwargs) + with open(expected_filename, 'rb') as fh: + expected_nrrd = fh.readlines() + + self.assertEqual(expected_nrrd, memory_nrrd) + + def test_write_memory_gzip(self): + kwargs = { + 'header': { + 'encoding': 'gzip' + }, + 'index_order': self.index_order + } + + memory_nrrd_file = io.BytesIO() + nrrd.write(memory_nrrd_file, self.data_input, **kwargs) + memory_nrrd_file.seek(0) + memory_nrrd = memory_nrrd_file.readlines() + + expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') + nrrd.write(expected_filename, self.data_input, **kwargs) + with open(expected_filename, 'rb') as fh: + expected_nrrd = fh.readlines() + + self.assertEqual(expected_nrrd, memory_nrrd) + + def test_write_memory_bzip2(self): + kwargs = { + 'header': { + 'encoding': 'bzip2' + }, + 'index_order': self.index_order + } + + memory_nrrd_file = io.BytesIO() + nrrd.write(memory_nrrd_file, self.data_input, **kwargs) + memory_nrrd_file.seek(0) + memory_nrrd = memory_nrrd_file.readlines() + + expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') + nrrd.write(expected_filename, self.data_input, **kwargs) + with open(expected_filename, 'rb') as fh: + expected_nrrd = fh.readlines() + + self.assertEqual(expected_nrrd, memory_nrrd) class TestWritingFunctionsFortran(Abstract.TestWritingFunctions): From 3ad3daad01b03c5675a5e2a1f901ef3bd0732213 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 09:06:33 -0500 Subject: [PATCH 08/12] Fix example for reading from memory to not used named arguments --- docs/source/examples.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/examples.rst b/docs/source/examples.rst index 2fefe8a..dd5da20 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -54,7 +54,7 @@ Example write and read from memory print(header) >>> OrderedDict([('type', 'double'), ('dimension', 1), ('sizes', array([50])), ('endian', 'little'), ('encoding', 'gzip')]) - data2 = nrrd.read_data(header=header, fh=memory_nrrd) + data2 = nrrd.read_data(header, memory_nrrd) print(np.all(data == data2)) >>> True From a43efff6864d753f584ea6c9c77b54e0e19350f5 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 09:14:09 -0500 Subject: [PATCH 09/12] WIP: Have a test that fails due to not being able to read BytesIO --- nrrd/tests/test_reading.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index b8cd37f..3bd1b8a 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -1,3 +1,4 @@ +import io from typing import ClassVar, Literal import numpy as np @@ -458,6 +459,34 @@ def test_read_quoted_string_header_no_quotes(self): self.assertEqual(['mm', 'cm', 'in'], header['space units']) self.assertEqual(['X', 'Y', 'f(log(X,10),Y)'], header['labels']) + def test_read_memory(self): + def test(filename: str): + with open(filename, 'rb') as fh: + # Read into BytesIO and test that + memory_file = io.BytesIO(fh.read()) + memory_header = nrrd.read_header(memory_file) + memory_data = nrrd.read_data(memory_header, memory_file) + + # Read normally via file handle + fh.seek(0) + expected_header = nrrd.read_header(fh) + expected_data = nrrd.read_data(expected_header, fh) + + np.testing.assert_equal(expected_header, memory_header) + np.testing.assert_equal(expected_data, memory_data) + + # Test that the data read is able to be edited + self.assertTrue(memory_data.flags['WRITEABLE']) + + # TODO Repeat this for a bunch of different + paths = [ + RAW_NRRD_FILE_PATH, + ] + + for filename in paths: + with self.subTest(filename): + test(filename) + class TestReadingFunctionsFortran(Abstract.TestReadingFunctions): index_order = 'F' From 9c21eca900ccd2ac9282942433f3a57f5f795d05 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 12:43:08 -0500 Subject: [PATCH 10/12] Fix issue --- nrrd/reader.py | 12 ++++++++++-- nrrd/tests/test_reading.py | 15 +++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/nrrd/reader.py b/nrrd/reader.py index 755e4a7..18e306e 100644 --- a/nrrd/reader.py +++ b/nrrd/reader.py @@ -1,4 +1,5 @@ import bz2 +import io import os import re import shlex @@ -401,9 +402,16 @@ def read_data(header, fh=None, filename=None, index_order='F'): # If a compression encoding is used, then byte skip AFTER decompressing if header['encoding'] == 'raw': - data = np.fromfile(fh, dtype) + if isinstance(fh, io.BytesIO): + raw_data = bytearray(fh.read(total_data_points * dtype.itemsize)) + data = np.frombuffer(raw_data, dtype) + else: + data = np.fromfile(fh, dtype) elif header['encoding'] in ['ASCII', 'ascii', 'text', 'txt']: - data = np.fromfile(fh, dtype, sep=' ') + if isinstance(fh, io.BytesIO): + data = np.fromstring(fh.read(), dtype, sep=' ') + else: + data = np.fromfile(fh, dtype, sep=' ') else: # Handle compressed data now # Construct the decompression object based on encoding diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index 3bd1b8a..011f5fa 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -363,7 +363,7 @@ def test_detached_header_no_filename(self): np.testing.assert_equal(self.expected_header, header) # No filename is specified for read_data - with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data ' + with self.assertRaisesRegex(nrrd.NRRDError, 'Filename parameter must be specified when a relative data ' 'file path is given'): nrrd.read_data(header, fh) @@ -375,7 +375,7 @@ def test_invalid_lineskip(self): # Set the line skip to be incorrect header['line skip'] = -1 - with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or ' + with self.assertRaisesRegex(nrrd.NRRDError, 'Invalid lineskip, allowed values are greater than or ' 'equal to 0'): nrrd.read_data(header, fh, RAW_NRRD_FILE_PATH) @@ -463,7 +463,8 @@ def test_read_memory(self): def test(filename: str): with open(filename, 'rb') as fh: # Read into BytesIO and test that - memory_file = io.BytesIO(fh.read()) + x = fh.read() + memory_file = io.BytesIO(x) memory_header = nrrd.read_header(memory_file) memory_data = nrrd.read_data(memory_header, memory_file) @@ -478,9 +479,15 @@ def test(filename: str): # Test that the data read is able to be edited self.assertTrue(memory_data.flags['WRITEABLE']) - # TODO Repeat this for a bunch of different paths = [ RAW_NRRD_FILE_PATH, + GZ_NRRD_FILE_PATH, + GZ_BYTESKIP_NRRD_FILE_PATH, + GZ_LINESKIP_NRRD_FILE_PATH, + BZ2_NRRD_FILE_PATH, + ASCII_1D_NRRD_FILE_PATH, + ASCII_2D_NRRD_FILE_PATH, + RAW_4D_NRRD_FILE_PATH, ] for filename in paths: From 82a267b39ff4bf6f1d94c315f4900b09d7fdf968 Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 14:09:55 -0500 Subject: [PATCH 11/12] Fix tests after merge --- nrrd/tests/test_writing.py | 46 ++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index 413bbda..cba80be 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -410,14 +410,25 @@ def test_write_memory_raw(self): memory_nrrd_file.seek(0) memory_nrrd = memory_nrrd_file.readlines() - self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) - self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) - self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) - self.assertSequenceEqual(header, memory_header) + expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') + nrrd.write(expected_filename, self.data_input, **kwargs) + with open(expected_filename, 'rb') as fh: + expected_nrrd = fh.readlines() + + self.assertEqual(expected_nrrd, memory_nrrd) - def test_write_memory_file_handle(self): - default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') - nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) + def test_write_memory_gzip(self): + kwargs = { + 'header': { + 'encoding': 'gzip' + }, + 'index_order': self.index_order + } + + memory_nrrd_file = io.BytesIO() + nrrd.write(memory_nrrd_file, self.data_input, **kwargs) + memory_nrrd_file.seek(0) + memory_nrrd = memory_nrrd_file.readlines() expected_filename = os.path.join(self.temp_write_dir, 'testfile_expected.nrrd') nrrd.write(expected_filename, self.data_input, **kwargs) @@ -446,6 +457,27 @@ def test_write_memory_bzip2(self): self.assertEqual(expected_nrrd, memory_nrrd) + def test_write_memory_file_handle(self): + default_output_filename = os.path.join(self.temp_write_dir, 'testfile_default_filename.nrrd') + nrrd.write(default_output_filename, self.data_input, {}, index_order=self.index_order) + + default_output_memory_filename = os.path.join(self.temp_write_dir, 'testfile_default_memory_filename.nrrd') + + with open(default_output_memory_filename, mode='wb') as memory_nrrd: + nrrd.write(memory_nrrd, self.data_input, {}, index_order=self.index_order) + + data, header = nrrd.read(default_output_filename, index_order=self.index_order) + + with open(default_output_memory_filename, mode='rb') as memory_nrrd: + memory_header = nrrd.read_header(memory_nrrd) + memory_data = nrrd.read_data(header=memory_header, fh=memory_nrrd, filename=None, + index_order=self.index_order) + + self.assertEqual(self.expected_data, data.tobytes(order=self.index_order)) + self.assertEqual(self.expected_data, memory_data.tobytes(order=self.index_order)) + self.assertEqual(header.pop('sizes').all(), memory_header.pop('sizes').all()) + self.assertSequenceEqual(header, memory_header) + class TestWritingFunctionsFortran(Abstract.TestWritingFunctions): index_order = 'F' From 74934ceb192b38857da1e3af44d49c2d0b93a8ac Mon Sep 17 00:00:00 2001 From: Addison Elliott Date: Sat, 27 Aug 2022 14:14:52 -0500 Subject: [PATCH 12/12] fix issue --- nrrd/tests/test_reading.py | 2 +- nrrd/tests/test_writing.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nrrd/tests/test_reading.py b/nrrd/tests/test_reading.py index 1593c31..cf45eec 100644 --- a/nrrd/tests/test_reading.py +++ b/nrrd/tests/test_reading.py @@ -1,6 +1,6 @@ +import io import unittest from typing import ClassVar -import io import numpy as np from typing_extensions import Literal diff --git a/nrrd/tests/test_writing.py b/nrrd/tests/test_writing.py index cba80be..7d5946f 100644 --- a/nrrd/tests/test_writing.py +++ b/nrrd/tests/test_writing.py @@ -22,7 +22,7 @@ def setUp(self): self.expected_data = fh.read() def test_write_default_header(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_default.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_default.nrrd') nrrd.write(output_filename, self.data_input, {}, index_order=self.index_order) # Read back the same file @@ -31,7 +31,7 @@ def test_write_default_header(self): self.assertEqual(header.get('encoding'), 'gzip') # default is gzip if not specified def test_write_raw(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_raw.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_raw.nrrd') nrrd.write(output_filename, self.data_input, {'encoding': 'raw'}, index_order=self.index_order) # Read back the same file @@ -40,7 +40,7 @@ def test_write_raw(self): self.assertEqual(header.get('encoding'), 'raw') def test_write_gz(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_gzip.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_gzip.nrrd') nrrd.write(output_filename, self.data_input, {'encoding': 'gzip'}, index_order=self.index_order) # Read back the same file @@ -49,7 +49,7 @@ def test_write_gz(self): self.assertEqual(header.get('encoding'), 'gzip') def test_write_bzip2(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_bzip2.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_bzip2.nrrd') nrrd.write(output_filename, self.data_input, {'encoding': 'bzip2'}, index_order=self.index_order) # Read back the same file @@ -58,7 +58,7 @@ def test_write_bzip2(self): self.assertEqual(header.get('encoding'), 'bzip2') def test_write_gz_level1(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_gzip_1.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_gzip_1.nrrd') nrrd.write(output_filename, self.data_input, {'encoding': 'gzip'}, compression_level=1, index_order=self.index_order) @@ -69,7 +69,7 @@ def test_write_gz_level1(self): self.assertLess(os.path.getsize(GZ_NRRD_FILE_PATH), os.path.getsize(output_filename)) def test_write_bzip2_level1(self): - output_filename = os.path.join(self.temp_write_dir, f'testfile_bzip2_1.nrrd') + output_filename = os.path.join(self.temp_write_dir, 'testfile_bzip2_1.nrrd') nrrd.write(output_filename, self.data_input, {'encoding': 'bzip2'}, compression_level=1, index_order=self.index_order)