Skip to content

Commit

Permalink
Update tests to fix validation errors and warning (#1839)
Browse files Browse the repository at this point in the history
  • Loading branch information
rly authored Feb 5, 2024
1 parent b54ba1b commit 6e970c4
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version: 2
build:
os: ubuntu-20.04
tools:
python: '3.8'
python: '3.11'

# Build documentation in the docs/ directory with Sphinx
sphinx:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Expose `starting_time` in `mock_ElectricalSeries`. @h-mayorquin [#1805](https://github.com/NeurodataWithoutBorders/pynwb/pull/1805)
- Enhance `get_data_in_units()` to work with objects that have a `channel_conversion` attribute like the `ElectricalSeries`. @h-mayorquin [#1806](https://github.com/NeurodataWithoutBorders/pynwb/pull/1806)
- Refactor validation CLI tests to use `{sys.executable} -m coverage` to use the same Python version and run correctly on Debian systems. @yarikoptic [#1811](https://github.com/NeurodataWithoutBorders/pynwb/pull/1811)
- Fixed tests to address newly caught validation errors. @rly [#1839](https://github.com/NeurodataWithoutBorders/pynwb/pull/1839)

### Bug fixes
- Fix bug where namespaces were loaded in "w-" mode. @h-mayorquin [#1795](https://github.com/NeurodataWithoutBorders/pynwb/pull/1795)
Expand Down
2 changes: 1 addition & 1 deletion docs/source/overview_citing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ If you use PyNWB in your research, please use the following citation:
Using RRID
----------

* ResourceID: `SCR_017452 <https://scicrunch.org/browse/resources/SCR_017452>`_
* ResourceID: `SCR_017452 <https://scicrunch.org/resolver/SCR_017452>`_
* Proper Citation: **(PyNWB, RRID:SCR_017452)**


Expand Down
2 changes: 1 addition & 1 deletion requirements-min.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# minimum versions of package dependencies for installing PyNWB
h5py==2.10 # support for selection of datasets with list of indices added in 2.10
hdmf==3.9.0
hdmf==3.12.0
numpy==1.18
pandas==1.1.5
python-dateutil==2.7.3
Expand Down
10 changes: 5 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# pinned dependencies to reproduce an entire development environment to use PyNWB
h5py==3.8.0
hdmf==3.9.0
numpy==1.24.2
pandas==2.0.0
h5py==3.10.0
hdmf==3.12.0
numpy==1.26.1
pandas==2.1.2
python-dateutil==2.8.2
setuptools==65.5.1
setuptools==65.5.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

reqs = [
'h5py>=2.10',
'hdmf>=3.9.0',
'hdmf>=3.12.0',
'numpy>=1.16',
'pandas>=1.1.5',
'python-dateutil>=2.7.3',
Expand Down
6 changes: 5 additions & 1 deletion src/pynwb/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ def _get_cached_namespaces_to_validate(
is_method=False,
)
def validate(**kwargs):
"""Validate NWB file(s) against a namespace or its cached namespaces."""
"""Validate NWB file(s) against a namespace or its cached namespaces.
NOTE: If an io object is provided and no namespace name is specified, then the file will be validated
against the core namespace, even if use_cached_namespaces is True.
"""
from . import NWBHDF5IO # TODO: modularize to avoid circular import

io, paths, use_cached_namespaces, namespace, verbose, driver = getargs(
Expand Down
6 changes: 6 additions & 0 deletions tests/back_compat/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ class TestReadOldVersions(TestCase):
"- 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):
Expand Down
93 changes: 65 additions & 28 deletions tests/integration/hdf5/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,36 @@ class TestDecompositionSeriesIO(NWBH5IOMixin, TestCase):

def setUpContainer(self):
""" Return the test DecompositionSeries to read/write """
self.timeseries = TimeSeries(name='dummy timeseries', description='desc',
data=np.ones((3, 3)), unit='flibs',
timestamps=np.ones((3,)))
bands = DynamicTable(name='bands', description='band info for LFPSpectralAnalysis', columns=[
VectorData(name='band_name', description='name of bands', data=['alpha', 'beta', 'gamma']),
VectorData(name='band_limits', description='low and high cutoffs in Hz', data=np.ones((3, 2)))
])
spec_anal = DecompositionSeries(name='LFPSpectralAnalysis',
description='my description',
data=np.ones((3, 3, 3)),
timestamps=np.ones((3,)),
source_timeseries=self.timeseries,
metric='amplitude',
bands=bands)
self.timeseries = TimeSeries(
name='dummy timeseries',
description='desc',
data=np.ones((3, 3)),
unit='flibs',
timestamps=np.ones((3,)),
)
bands = DynamicTable(
name='bands',
description='band info for LFPSpectralAnalysis',
columns=[
VectorData(name='band_name', description='name of bands', data=['alpha', 'beta', 'gamma']),
VectorData(name='band_limits', description='low and high cutoffs in Hz', data=np.ones((3, 2))),
VectorData(name='band_mean', description='mean gaussian filters in Hz', data=np.ones((3,))),
VectorData(
name='band_stdev',
description='standard deviation of gaussian filters in Hz',
data=np.ones((3,))
),
],
)
spec_anal = DecompositionSeries(
name='LFPSpectralAnalysis',
description='my description',
data=np.ones((3, 3, 3)),
timestamps=np.ones((3,)),
source_timeseries=self.timeseries,
metric='amplitude',
bands=bands,
)

return spec_anal

Expand All @@ -144,27 +160,48 @@ def make_electrode_table(self):
""" Make an electrode table, electrode group, and device """
self.table = get_electrode_table()
self.dev1 = Device(name='dev1')
self.group = ElectrodeGroup(name='tetrode1',
description='tetrode description',
location='tetrode location',
device=self.dev1)
for i in range(4):
self.group = ElectrodeGroup(
name='tetrode1',
description='tetrode description',
location='tetrode location',
device=self.dev1
)
for _ in range(4):
self.table.add_row(location='CA1', group=self.group, group_name='tetrode1')

def setUpContainer(self):
""" Return the test ElectricalSeries to read/write """
self.make_electrode_table(self)
region = DynamicTableRegion(name='source_channels',
data=[0, 2],
description='the first and third electrodes',
table=self.table)
region = DynamicTableRegion(
name='source_channels',
data=[0, 2],
description='the first and third electrodes',
table=self.table
)
data = np.random.randn(100, 2, 30)
timestamps = np.arange(100)/100
ds = DecompositionSeries(name='test_DS',
data=data,
source_channels=region,
timestamps=timestamps,
metric='amplitude')
bands = DynamicTable(
name='bands',
description='band info for LFPSpectralAnalysis',
columns=[
VectorData(name='band_name', description='name of bands', data=['alpha', 'beta', 'gamma']),
VectorData(name='band_limits', description='low and high cutoffs in Hz', data=np.ones((3, 2))),
VectorData(name='band_mean', description='mean gaussian filters in Hz', data=np.ones((3,))),
VectorData(
name='band_stdev',
description='standard deviation of gaussian filters in Hz',
data=np.ones((3,))
),
],
)
ds = DecompositionSeries(
name='test_DS',
data=data,
source_channels=region,
timestamps=timestamps,
metric='amplitude',
bands=bands,
)
return ds

def addContainer(self, nwbfile):
Expand Down
29 changes: 21 additions & 8 deletions tests/integration/ros3/test_ros3.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pynwb.testing import TestCase
import urllib.request
import h5py
import warnings


class TestRos3Streaming(TestCase):
Expand All @@ -28,16 +29,28 @@ def setUp(self):

def test_read(self):
s3_path = 'https://dandiarchive.s3.amazonaws.com/ros3test.nwb'
with NWBHDF5IO(s3_path, mode='r', driver='ros3') as io:
nwbfile = io.read()
test_data = nwbfile.acquisition['ts_name'].data[:]
self.assertEqual(len(test_data), 3)
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=r"Ignoring cached namespace .*",
category=UserWarning,
)
with NWBHDF5IO(s3_path, mode='r', driver='ros3') as io:
nwbfile = io.read()
test_data = nwbfile.acquisition['ts_name'].data[:]
self.assertEqual(len(test_data), 3)

def test_dandi_read(self):
with NWBHDF5IO(path=self.s3_test_path, mode='r', driver='ros3') as io:
nwbfile = io.read()
test_data = nwbfile.acquisition['TestData'].data[:]
self.assertEqual(len(test_data), 3)
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message=r"Ignoring cached namespace .*",
category=UserWarning,
)
with NWBHDF5IO(path=self.s3_test_path, mode='r', driver='ros3') as io:
nwbfile = io.read()
test_data = nwbfile.acquisition['TestData'].data[:]
self.assertEqual(len(test_data), 3)

def test_dandi_get_cached_namespaces(self):
expected_namespaces = ["core"]
Expand Down
10 changes: 9 additions & 1 deletion tests/unit/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ def test_init(self):
timestamps=[1., 2., 3.])
bands = DynamicTable(name='bands', description='band info for LFPSpectralAnalysis', columns=[
VectorData(name='band_name', description='name of bands', data=['alpha', 'beta', 'gamma']),
VectorData(name='band_limits', description='low and high cutoffs in Hz', data=np.ones((3, 2)))
VectorData(name='band_limits', description='low and high cutoffs in Hz', data=np.ones((3, 2))),
VectorData(name='band_mean', description='mean gaussian filters in Hz', data=np.ones((3,))),
VectorData(
name='band_stdev',
description='standard deviation of gaussian filters in Hz',
data=np.ones((3,))
),
])
spec_anal = DecompositionSeries(name='LFPSpectralAnalysis',
description='my description',
Expand All @@ -49,6 +55,8 @@ def test_init(self):
np.testing.assert_equal(spec_anal.timestamps, [1., 2., 3.])
self.assertEqual(spec_anal.bands['band_name'].data, ['alpha', 'beta', 'gamma'])
np.testing.assert_equal(spec_anal.bands['band_limits'].data, np.ones((3, 2)))
np.testing.assert_equal(spec_anal.bands['band_mean'].data, np.ones((3,)))
np.testing.assert_equal(spec_anal.bands['band_stdev'].data, np.ones((3,)))
self.assertEqual(spec_anal.source_timeseries, timeseries)
self.assertEqual(spec_anal.metric, 'amplitude')

Expand Down

0 comments on commit 6e970c4

Please sign in to comment.