Skip to content

Commit dbff399

Browse files
stephprincerly
andauthored
Add core namespace to NamespaceCatalog (#2077)
Co-authored-by: Ryan Ly <[email protected]>
1 parent fef82aa commit dbff399

File tree

10 files changed

+60
-31
lines changed

10 files changed

+60
-31
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
- When an external file is detected when initializing an ImageSeries and no format is provided, automatically set format to "external" instead of raising an error. @stephprince [#2060](https://github.com/NeurodataWithoutBorders/pynwb/pull/2060)
1414
- Added mask_type option to `mock_PlaneSegmentation`. @pauladkisson [#2067](https://github.com/NeurodataWithoutBorders/pynwb/pull/2067)
1515
- Improved the documentation of the `spike_times` in the Units table methods @h-mayorquin [#2085](https://github.com/NeurodataWithoutBorders/pynwb/pull/2085)
16+
- Removed core namespace warning unless cached version is newer. @stephprince [#2077](https://github.com/NeurodataWithoutBorders/pynwb/pull/2077)
17+
- Bumped minimum HDMF version to 4.1.0. @stephprince [#2077](https://github.com/NeurodataWithoutBorders/pynwb/pull/2077)
1618

1719
### Bug fixes
1820
- Fixed `add_data_interface` functionality that was mistakenly removed in PyNWB 3.0. @stephprince [#2052](https://github.com/NeurodataWithoutBorders/pynwb/pull/2052)

environment-ros3.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ channels:
66
dependencies:
77
- python==3.13
88
- h5py==3.12.1
9-
- hdmf==3.14.5
9+
- hdmf==4.1.0
1010
- matplotlib==3.9.2
1111
- numpy==2.1.3
1212
- pandas==2.2.3

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ classifiers = [
3434
]
3535
dependencies = [
3636
"h5py>=3.2.0",
37-
"hdmf>=3.14.5,<5",
37+
"hdmf>=4.1.0,<5",
3838
"numpy>=1.24.0",
3939
"pandas>=1.2.0",
4040
"python-dateutil>=2.8.2",

requirements-min.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# minimum versions of package dependencies for installing PyNWB
22
h5py==3.2.0
3-
hdmf==3.14.5
3+
hdmf==4.1.0
44
numpy==1.24.0
55
pandas==1.2.0
66
python-dateutil==2.8.2

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pinned dependencies to reproduce an entire development environment to use PyNWB
22
h5py==3.12.1
3-
hdmf==3.14.5
3+
hdmf==4.1.0
44
numpy==2.1.1; python_version > "3.9" # numpy 2.1+ is not compatible with py3.9
55
numpy==2.0.2; python_version == "3.9"
66
pandas==2.2.3

src/pynwb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def __get_resources() -> dict:
8888
# a global type map
8989
global __TYPE_MAP
9090

91-
__ns_catalog = NamespaceCatalog(NWBGroupSpec, NWBDatasetSpec, NWBNamespace)
91+
__ns_catalog = NamespaceCatalog(NWBGroupSpec, NWBDatasetSpec, NWBNamespace, core_namespaces=[CORE_NAMESPACE])
9292

9393
hdmf_typemap = hdmf.common.get_type_map()
9494
__TYPE_MAP = TypeMap(__ns_catalog)

tests/back_compat/test_read.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,7 @@ class TestReadOldVersions(TestCase):
3939

4040
def get_io(self, path):
4141
"""Get an NWBHDF5IO object for the given path."""
42-
with warnings.catch_warnings():
43-
warnings.filterwarnings(
44-
"ignore",
45-
message=r"Ignoring cached namespace .*",
46-
category=UserWarning,
47-
)
48-
return NWBHDF5IO(str(path), 'r')
42+
return NWBHDF5IO(str(path), 'r')
4943

5044
def test_read(self):
5145
"""Test reading and validating all NWB files in the same folder as this file.

tests/integration/ros3/test_ros3.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,13 @@ def setUp(self):
3030
def test_read(self):
3131
s3_path = 'https://dandiarchive.s3.amazonaws.com/ros3test.nwb'
3232
with warnings.catch_warnings():
33-
warnings.filterwarnings(
34-
"ignore",
35-
message=r"Ignoring cached namespace .*",
36-
category=UserWarning,
37-
)
3833
with NWBHDF5IO(s3_path, mode='r', driver='ros3') as io:
3934
nwbfile = io.read()
4035
test_data = nwbfile.acquisition['ts_name'].data[:]
4136
self.assertEqual(len(test_data), 3)
4237

4338
def test_dandi_read(self):
4439
with warnings.catch_warnings():
45-
warnings.filterwarnings(
46-
"ignore",
47-
message=r"Ignoring cached namespace .*",
48-
category=UserWarning,
49-
)
5040
with NWBHDF5IO(path=self.s3_test_path, mode='r', driver='ros3') as io:
5141
nwbfile = io.read()
5242
test_data = nwbfile.acquisition['TestData'].data[:]

tests/unit/test_extension.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import os
22
import random
33
import string
4+
import warnings
45
from datetime import datetime
56
from dateutil.tz import tzlocal
67
from tempfile import gettempdir
78

8-
from hdmf.spec import RefSpec
9+
from hdmf.spec import RefSpec, NamespaceCatalog
910
from hdmf.utils import get_docval, docval, popargs
1011
from pynwb import get_type_map, TimeSeries, NWBFile, register_class, load_namespaces, get_class
1112
from pynwb.spec import NWBNamespaceBuilder, NWBGroupSpec, NWBAttributeSpec, NWBDatasetSpec
@@ -143,6 +144,10 @@ def setUp(self):
143144
self.ext_source2 = '%s_extension2.yaml' % self.prefix
144145
self.ns_path2 = '%s_namespace2.yaml' % self.prefix
145146

147+
self.ns_catalog = get_type_map().namespace_catalog
148+
self.core_ns = 'core'
149+
self.core_ns_version = self.ns_catalog.get_namespace(self.core_ns)['version']
150+
146151
def tearDown(self):
147152
files = (self.ext_source1,
148153
self.ns_path1,
@@ -169,3 +174,48 @@ def test_catch_dup_name(self):
169174
ns_builder2.export(self.ns_path2, outdir=self.tempdir)
170175
type_map = get_type_map(extensions=os.path.join(self.tempdir, self.ns_path1))
171176
type_map.load_namespaces(os.path.join(self.tempdir, self.ns_path2))
177+
178+
def test_catch_dup_name_core_newer(self):
179+
new_ns_version = '100.0.0'
180+
ns_builder1 = NWBNamespaceBuilder('Extension for us in my Lab', self.core_ns, version=new_ns_version)
181+
ext1 = NWBGroupSpec('A custom ElectricalSeries for my lab',
182+
attributes=[NWBAttributeSpec(name='trode_id', doc='the tetrode id', dtype='int')],
183+
neurodata_type_inc='ElectricalSeries',
184+
neurodata_type_def='TetrodeSeries')
185+
ns_builder1.add_spec(self.ext_source1, ext1)
186+
ns_builder1.export(self.ns_path1, outdir=self.tempdir)
187+
188+
# create new catalog and merge the loaded core namespace catalog
189+
ns_catalog = NamespaceCatalog()
190+
ns_catalog.merge(self.ns_catalog)
191+
192+
# test loading newer namespace than one already loaded will warn
193+
msg = (f'Ignoring the following cached namespace(s) because another version is already loaded:\n'
194+
f'{self.core_ns} - cached version: {new_ns_version}, loaded version: {self.core_ns_version}\n'
195+
f'Please update to the latest package versions.')
196+
with self.assertWarnsWith(UserWarning, msg):
197+
ns_catalog.load_namespaces(os.path.join(self.tempdir, self.ns_path1))
198+
199+
def test_catch_dup_name_core_older(self):
200+
new_ns_version = '0.0.0'
201+
ns_builder1 = NWBNamespaceBuilder('Extension for us in my Lab', self.core_ns, version=new_ns_version)
202+
ext1 = NWBGroupSpec('A custom ElectricalSeries for my lab',
203+
attributes=[NWBAttributeSpec(name='trode_id', doc='the tetrode id', dtype='int')],
204+
neurodata_type_inc='ElectricalSeries',
205+
neurodata_type_def='TetrodeSeries')
206+
ns_builder1.add_spec(self.ext_source1, ext1)
207+
ns_builder1.export(self.ns_path1, outdir=self.tempdir)
208+
209+
# create new catalog and merge the loaded core namespace catalog
210+
ns_catalog = NamespaceCatalog()
211+
ns_catalog.merge(self.ns_catalog)
212+
213+
# test no warning if loading older namespace than one already loaded
214+
msg = (f'Ignoring the following cached namespace(s) because another version is already loaded:\n'
215+
f'{self.core_ns} - cached version: {new_ns_version}, loaded version: {self.core_ns_version}\n'
216+
f'Please update to the latest package versions.')
217+
with warnings.catch_warnings(record=True) as ws:
218+
ns_catalog.load_namespaces(os.path.join(self.tempdir, self.ns_path1))
219+
for w in ws:
220+
self.assertTrue(str(w.message) != msg)
221+
warnings.warn(str(w.message), w.category)

tests/validation/test_validate.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import sys
55
from unittest.mock import patch
66
from io import StringIO
7-
import warnings
87

98
from pynwb.testing import TestCase
109
from pynwb import validate, NWBHDF5IO
@@ -202,13 +201,7 @@ class TestValidateFunction(TestCase):
202201

203202
def get_io(self, path):
204203
"""Get an NWBHDF5IO object for the given path, ignoring the warning about ignoring cached namespaces."""
205-
with warnings.catch_warnings():
206-
warnings.filterwarnings(
207-
"ignore",
208-
message=r"Ignoring cached namespace .*",
209-
category=UserWarning,
210-
)
211-
return NWBHDF5IO(str(path), 'r')
204+
return NWBHDF5IO(str(path), 'r')
212205

213206
def test_validate_io_no_cache(self):
214207
"""Test that validating a file with no cached spec against the core namespace succeeds."""

0 commit comments

Comments
 (0)