1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
import numpy as np
from pathlib import Path
import warnings
from pynwb import NWBHDF5IO, validate, TimeSeries
from pynwb.image import ImageSeries
from pynwb.testing import TestCase
class TestReadOldVersions(TestCase):
expected_warnings = {
''
'2.1.0_imageseries_non_external_format.nwb': [(
"ImageSeries 'test_imageseries': Format must be 'external' when external_file is specified."
)],
'2.1.0_imageseries_nonmatch_starting_frame.nwb': [(
"ImageSeries 'test_imageseries': The number of frame indices in 'starting_frame' should have the same "
"length as 'external_file'."
)],
}
expected_errors = {
'1.0.2_str_experimenter.nwb': [("root/general/experimenter (general/experimenter): incorrect shape - expected "
"an array of shape '[None]', got non-array data 'one experimenter'")],
'1.0.3_str_experimenter.nwb': [("root/general/experimenter (general/experimenter): incorrect shape - expected "
"an array of shape '[None]', got non-array data 'one experimenter'")],
'1.0.2_str_pub.nwb': [("root/general/related_publications (general/related_publications): incorrect shape "
"- expected an array of shape '[None]', got non-array data 'one publication'")],
'1.0.3_str_pub.nwb': [("root/general/related_publications (general/related_publications): incorrect shape "
"- expected an array of shape '[None]', got non-array data 'one publication'")],
'1.5.1_timeseries_no_data.nwb': [("TimeSeries/data/data (acquisition/test_timeseries/data): argument missing")],
'1.5.1_timeseries_no_unit.nwb': [("TimeSeries/data/unit (acquisition/test_timeseries/data): argument missing")],
'1.5.1_imageseries_no_data.nwb': [("ImageSeries/data/data (acquisition/test_imageseries/data): "
"argument missing")],
'1.5.1_imageseries_no_unit.nwb': [("ImageSeries/data/unit (acquisition/test_imageseries/data): "
"argument missing")],
}
def get_io(self, path):
"""Get an NWBHDF5IO object for the given path."""
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=r"Ignoring cached namespace .*",
category=UserWarning,
)
return NWBHDF5IO(str(path), 'r')
def test_read(self):
"""Test reading and validating all NWB files in the same folder as this file.
This folder contains NWB files generated by previous versions of NWB using the script
src/pynwb/testing/make_test_files.py
"""
dir_path = Path(__file__).parent
nwb_files = dir_path.glob('*.nwb')
for f in nwb_files:
with self.subTest(file=f.name):
with warnings.catch_warnings(record=True) as warnings_on_read:
warnings.simplefilter("always")
with self.get_io(f) as io:
errors = validate(io)
io.read()
for w in warnings_on_read:
if f.name in self.expected_warnings:
if str(w.message) not in self.expected_warnings[f.name]:
pass
# will replace above with below after the test file is updated
# raise Exception("Unexpected warning: %s: %s" % (f.name, str(w.message)))
else:
pass
# will replace above with below after the test file is updated
# raise Exception("Unexpected warning: %s: %s" % (f.name, str(w.message)))
if errors:
for e in errors:
if f.name in self.expected_errors:
if str(e) not in self.expected_errors[f.name]:
warnings.warn('%s: %s' % (f.name, e))
else:
raise Exception("Unexpected validation error: %s: %s" % (f.name, e))
# TODO uncomment below when validation errors have been fixed
# raise Exception('%d validation error(s). See warnings.' % len(errors))
def test_read_timeseries_no_data(self):
"""Test that a TimeSeries written without data is read with data set to the default value."""
f = Path(__file__).parent / '1.5.1_timeseries_no_data.nwb'
with self.get_io(f) as io:
read_nwbfile = io.read()
np.testing.assert_array_equal(read_nwbfile.acquisition['test_timeseries'].data, TimeSeries.DEFAULT_DATA)
def test_read_timeseries_no_unit(self):
"""Test that an ImageSeries written without unit is read with unit set to the default value."""
f = Path(__file__).parent / '1.5.1_timeseries_no_unit.nwb'
with self.get_io(f) as io:
read_nwbfile = io.read()
self.assertEqual(read_nwbfile.acquisition['test_timeseries'].unit, TimeSeries.DEFAULT_UNIT)
def test_read_imageseries_no_data(self):
"""Test that an ImageSeries written without data is read with data set to the default value."""
f = Path(__file__).parent / '1.5.1_imageseries_no_data.nwb'
with self.get_io(f) as io:
read_nwbfile = io.read()
np.testing.assert_array_equal(read_nwbfile.acquisition['test_imageseries'].data, ImageSeries.DEFAULT_DATA)
def test_read_imageseries_no_unit(self):
"""Test that an ImageSeries written without unit is read with unit set to the default value."""
f = Path(__file__).parent / '1.5.1_imageseries_no_unit.nwb'
with self.get_io(f) as io:
read_nwbfile = io.read()
self.assertEqual(read_nwbfile.acquisition['test_imageseries'].unit, ImageSeries.DEFAULT_UNIT)
def test_read_imageseries_non_external_format(self):
"""Test that reading an ImageSeries with an inconsistent format does not change the value."""
fbase = "2.1.0_imageseries_non_external_format.nwb"
f = Path(__file__).parent / fbase
expected_warning = self.expected_warnings[fbase][0]
with self.assertWarnsWith(UserWarning, expected_warning):
with self.get_io(f) as io:
read_nwbfile = io.read()
self.assertEqual(read_nwbfile.acquisition['test_imageseries'].format, "tiff")
def test_read_imageseries_nonmatch_starting_frame(self):
"""Test that reading an ImageSeries with an inconsistent starting_frame does not change the value."""
fbase = "2.1.0_imageseries_nonmatch_starting_frame.nwb"
f = Path(__file__).parent / fbase
expected_warning = self.expected_warnings[fbase][0]
with self.assertWarnsWith(UserWarning, expected_warning):
with self.get_io(f) as io:
read_nwbfile = io.read()
np.testing.assert_array_equal(read_nwbfile.acquisition['test_imageseries'].starting_frame, [1, 2, 3])
def test_read_subject_no_age__reference(self):
"""Test that reading a Subject without an age__reference set with NWB schema 2.5.0 sets the value to None"""
f = Path(__file__).parent / '2.2.0_subject_no_age__reference.nwb'
with self.get_io(f) as io:
read_nwbfile = io.read()
self.assertIsNone(read_nwbfile.subject.age__reference)
|