Skip to content

Commit

Permalink
Fix reading file with linked TimeSeriesReferenceVectorData (#1865)
Browse files Browse the repository at this point in the history
  • Loading branch information
rly authored Mar 22, 2024
1 parent 5b80bea commit 8b42af3
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# PyNWB Changelog

## PyNWB 2.6.1 (Upcoming)
## PyNWB 2.6.1 (March 25, 2024)

### Bug fixes
- Fix bug with reading file with linked `TimeSeriesReferenceVectorData` @rly [#1865](https://github.com/NeurodataWithoutBorders/pynwb/pull/1865)
- Fix bug where extra keyword arguments could not be passed to `NWBFile.add_{x}_column`` for use in custom `VectorData`` classes. @rly [#1861](https://github.com/NeurodataWithoutBorders/pynwb/pull/1861)

## PyNWB 2.6.0 (February 21, 2024)
Expand Down
8 changes: 7 additions & 1 deletion src/pynwb/io/epoch.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from hdmf.build import LinkBuilder
from hdmf.common.table import VectorData
from hdmf.common.io.table import DynamicTableMap

Expand All @@ -8,13 +9,18 @@

@register_map(TimeIntervals)
class TimeIntervalsMap(DynamicTableMap):
pass

@DynamicTableMap.constructor_arg('columns')
def columns_carg(self, builder, manager):
# handle the case when a TimeIntervals is read with a non-TimeSeriesReferenceVectorData "timeseries" column
# this is the case for NWB schema v2.4 and earlier, where the timeseries column was a regular VectorData.
timeseries_builder = builder.get('timeseries')

# handle the case when the TimeIntervals has a "timeseries" column that is a link (e.g., it exists in
# a different file that was shallow copied to this file).
if isinstance(timeseries_builder, LinkBuilder):
timeseries_builder = timeseries_builder.builder

# if we have a timeseries column and the type is VectorData instead of TimeSeriesReferenceVectorData
if (timeseries_builder is not None and
timeseries_builder.attributes['neurodata_type'] != 'TimeSeriesReferenceVectorData'):
Expand Down
44 changes: 44 additions & 0 deletions tests/integration/hdf5/test_file_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import os
from pynwb.base import TimeSeriesReference
from pynwb import NWBHDF5IO
from pynwb.testing import TestCase
from pynwb.testing.mock.file import mock_NWBFile
from pynwb.testing.mock.base import mock_TimeSeries


class TestFileCopy(TestCase):

def setUp(self):
self.path1 = "test_a.h5"
self.path2 = "test_b.h5"

def tearDown(self):
if os.path.exists(self.path1):
os.remove(self.path1)
if os.path.exists(self.path2):
os.remove(self.path2)

def test_copy_file_link_timeintervals_timeseries(self):
"""Test copying a file with a TimeSeriesReference in a TimeIntervals object and reading that copy.
Based on https://github.com/NeurodataWithoutBorders/pynwb/issues/1863
"""
new_nwb = mock_NWBFile()
test_ts = mock_TimeSeries(name="test_ts", timestamps=[1.0, 2.0, 3.0], data=[1.0, 2.0, 3.0])
new_nwb.add_acquisition(test_ts)
new_nwb.add_trial(start_time=1.0, stop_time=2.0, timeseries=[test_ts])

with NWBHDF5IO(self.path1, 'w') as io:
io.write(new_nwb)

with NWBHDF5IO(self.path1, 'r') as base_io:
# the TimeIntervals object is copied but the TimeSeriesReferenceVectorData is linked
nwb_add = base_io.read().copy()
with NWBHDF5IO(self.path2, 'w', manager=base_io.manager) as out_io:
out_io.write(nwb_add)

with NWBHDF5IO(self.path2, 'r') as io:
nwb = io.read()
ts_val = nwb.trials["timeseries"][0][0]
assert isinstance(ts_val, TimeSeriesReference)
assert ts_val.timeseries is nwb.acquisition["test_ts"]

0 comments on commit 8b42af3

Please sign in to comment.