From 5afdf2e5a4716631304578ecd8360373e67918bf Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 27 Jan 2025 10:17:34 -0600 Subject: [PATCH 1/4] chore: update .gitignore to include venv/ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 95f08686e..1767f2597 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ _version.py .core_typemap_version core_typemap.pkl + +venv/ From 84223b441c2276fa4c2368ed4e001168bea7523c Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 27 Jan 2025 10:18:29 -0600 Subject: [PATCH 2/4] Add methods for data interface management in ProcessingModule --- src/pynwb/base.py | 40 ++++++++++++++++++++++++++++++++++++++++ tests/unit/test_base.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/pynwb/base.py b/src/pynwb/base.py index 8b4daf48f..e2e4038c0 100644 --- a/src/pynwb/base.py +++ b/src/pynwb/base.py @@ -72,6 +72,46 @@ def get_data_interface(self, **kwargs): warn(PendingDeprecationWarning('get_data_interface will be replaced by get')) return self.get(kwargs['data_interface_name']) + def __len__(self): + """Get the number of data interfaces in this ProcessingModule. + + Returns + ------- + int + Number of data interfaces + """ + return len(self.data_interfaces) + + def keys(self): + """Get the names of data interfaces in this ProcessingModule. + + Returns + ------- + KeysView + View of interface names + """ + return self.data_interfaces.keys() + + def values(self): + """Get the data interfaces in this ProcessingModule. + + Returns + ------- + ValuesView + View of interfaces + """ + return self.data_interfaces.values() + + def items(self): + """Get the (name, interface) pairs in this ProcessingModule. + + Returns + ------- + ItemsView + View of (name, interface) pairs + """ + return self.data_interfaces.items() + @register_class('TimeSeries', CORE_NAMESPACE) class TimeSeries(NWBDataInterface): diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 5af4986ac..623219af7 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -94,6 +94,35 @@ def test_getitem(self): tmp = self.pm["test_ts"] self.assertIs(tmp, ts) + def test_len(self): + """Test that len() returns number of data interfaces.""" + self.assertEqual(len(self.pm), 0) + ts = self._create_time_series() + self.pm.add(ts) + self.assertEqual(len(self.pm), 1) + ts2 = TimeSeries(name="test_ts2", data=[1, 2, 3], unit="unit", rate=1.0) + self.pm.add(ts2) + self.assertEqual(len(self.pm), 2) + + def test_dict_methods(self): + """Test dictionary-like methods (keys, values, items).""" + ts = self._create_time_series() + ts2 = TimeSeries(name="test_ts2", data=[1, 2, 3], unit="unit", rate=1.0) + self.pm.add(ts) + self.pm.add(ts2) + + # Test keys() + keys = self.pm.keys() + self.assertEqual(set(keys), {"test_ts", "test_ts2"}) + + # Test values() + values = self.pm.values() + self.assertEqual(set(values), {ts, ts2}) + + # Test items() + items = self.pm.items() + self.assertEqual(set(items), {("test_ts", ts), ("test_ts2", ts2)}) + class TestTimeSeries(TestCase): def test_init_no_parent(self): From 910011500f0fcdf14163923404dcdad987d44428 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 17 Feb 2025 21:28:01 -0600 Subject: [PATCH 3/4] Enhance documentation and examples for dictionary-like access on ProcessingModule objects --- CHANGELOG.md | 1 + docs/gallery/domain/plot_behavior.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ed9ddac7..93054beb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## PyNWB 3.0.0 (Upcoming) ### Enhancements and minor changes +- Added dictionary-like operations directly on `ProcessingModule` objects (e.g., `len(processing_module)`). @bendichter [#2020](https://github.com/NeurodataWithoutBorders/pynwb/pull/2020) - Added `pynwb.read_nwb` convenience method to simplify reading an NWBFile written with any backend @h-mayorquin [#1994](https://github.com/NeurodataWithoutBorders/pynwb/pull/1994) - Added support for NWB schema 2.8.0. @rly [#2001](https://github.com/NeurodataWithoutBorders/pynwb/pull/2001) - Removed `SpatialSeries.bounds` field that was not functional. This will be fixed in a future release. @rly [#1907](https://github.com/NeurodataWithoutBorders/pynwb/pull/1907), [#1996](https://github.com/NeurodataWithoutBorders/pynwb/pull/1996) diff --git a/docs/gallery/domain/plot_behavior.py b/docs/gallery/domain/plot_behavior.py index 8f341bea1..311601862 100644 --- a/docs/gallery/domain/plot_behavior.py +++ b/docs/gallery/domain/plot_behavior.py @@ -396,7 +396,9 @@ with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io: read_nwbfile = io.read() - print(read_nwbfile.processing["behavior"].children) + behavior_module = read_nwbfile.processing["behavior"] + + print(f"Available data interfaces: {list(behavior_module.values())}") #################### # For instance, we can access the :py:class:`~pynwb.behavior.SpatialSeries` data @@ -410,7 +412,12 @@ with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io: read_nwbfile = io.read() - print(read_nwbfile.processing["behavior"]["Position"]["SpatialSeries"]) + behavior_module = read_nwbfile.processing["behavior"] + + # Access Position interface using dictionary-style access + position = behavior_module["Position"] + spatial_series = position["SpatialSeries"] + print(spatial_series) #################### # Data arrays are read passively from the file. From 9a8bdfb4c9f3ac959b26d53dc60931640ae2d098 Mon Sep 17 00:00:00 2001 From: Ben Dichter Date: Mon, 17 Feb 2025 22:29:44 -0500 Subject: [PATCH 4/4] Update docs/gallery/domain/plot_behavior.py --- docs/gallery/domain/plot_behavior.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/gallery/domain/plot_behavior.py b/docs/gallery/domain/plot_behavior.py index 311601862..05ab9e58d 100644 --- a/docs/gallery/domain/plot_behavior.py +++ b/docs/gallery/domain/plot_behavior.py @@ -412,12 +412,7 @@ with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io: read_nwbfile = io.read() - behavior_module = read_nwbfile.processing["behavior"] - - # Access Position interface using dictionary-style access - position = behavior_module["Position"] - spatial_series = position["SpatialSeries"] - print(spatial_series) + print(read_nwbfile.processing["behavior"]["Position"]["SpatialSeries"]) #################### # Data arrays are read passively from the file.