Skip to content

Commit

Permalink
Merge pull request #295 from NeurodataWithoutBorders/196-direct-objec…
Browse files Browse the repository at this point in the history
…t-reference

196 direct object reference
  • Loading branch information
lawrence-mbf authored Aug 17, 2021
2 parents e3c8a43 + 33533fd commit 299c345
Show file tree
Hide file tree
Showing 41 changed files with 740 additions and 1,058 deletions.
15 changes: 12 additions & 3 deletions +io/getRefData.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
validPaths = find(~cellfun('isempty', refpaths));
if isa(ref, 'types.untyped.RegionView')
for i=validPaths
did = H5D.open(fid, refpaths{i});
try
did = H5D.open(fid, refpaths{i});
catch ME
error('MatNWB:getRefData:InvalidPath',...
'Reference path `%s` was invalid', refpaths{i});
end
sid = H5D.get_space(did);
%by default, we use block mode.
regionShapes = ref(i).region;
Expand All @@ -21,8 +26,12 @@
typesize = H5T.get_size(ref(1).type);
ref_data = zeros([typesize size(ref)], 'uint8');
for i=validPaths
ref_data(:, i) = H5R.create(fid, ref(i).path, ref(i).reftype, ...
refspace(i));
try
ref_data(:, i) = H5R.create(fid, ref(i).path, ref(i).reftype, refspace(i));
catch ME
error('MatNWB:getRefData:InvalidPath',...
'Reference path `%s` was invalid', ref(i).path);
end
if H5I.is_valid(refspace(i))
H5S.close(refspace(i));
end
Expand Down
9 changes: 3 additions & 6 deletions +tests/+sanity/GenerationTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ function roundtripTest(testCase)
expected = NwbFile('identifier', 'TEST',...
'session_description', 'test nwbfile',...
'session_start_time', datetime());
expected.export('empty.nwb');

actual = nwbRead('empty.nwb');
tests.util.verifyContainerEqual(testCase, actual, expected);
nwbExport(expected, 'empty.nwb');
tests.util.verifyContainerEqual(testCase, nwbRead('empty.nwb'), expected);
end

function dynamicTableMethodsTest(testCase)
Expand All @@ -47,8 +45,7 @@ function dynamicTableMethodsTest(testCase)
'stop_time', stop_time,...
'randomvalues', rand_data,...
'stringdata', {'TRUE'},...
'id', id(i),...
'tablepath', '/intervals/trials');
'id', id(i));
end
t = table(id(101:200), (101:200) .', (102:201) .',...
mat2cell(rand(500,1), repmat(5, 100, 1)), repmat({'TRUE'}, 100, 1),...
Expand Down
2 changes: 1 addition & 1 deletion +tests/+system/AmendTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function testAmend(testCase)
writeContainer = testCase.getContainer(testCase.file);
readFile = nwbRead(filename);
readContainer = testCase.getContainer(readFile);
testCase.verifyContainerEqual(readContainer, writeContainer);
tests.util.verifyContainerEqual(testCase, readContainer, writeContainer);
end
end

Expand Down
3 changes: 1 addition & 2 deletions +tests/+system/DynamicTableTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ function addContainer(~, file)
'stop_time', stop_time,...
'randomvalues', rand_data,...
'stringdata', {'TRUE'},...
'id', id(i),...
'tablepath', '/intervals/trials');
'id', id(i));
end
t = table(id(101:200), (101:200) .', (102:201) .',...
mat2cell(rand(500,1), repmat(5, 100, 1)), repmat({'TRUE'}, 100, 1),...
Expand Down
20 changes: 7 additions & 13 deletions +tests/+system/ElectricalSeriesIOTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,14 @@

methods
function addContainer(testCase, file) %#ok<INUSL>
devnm = 'dev1';
egnm = 'tetrode1';
esnm = 'test_eS';
devBase = '/general/devices/';
ephysBase = '/general/extracellular_ephys/';
devlink = types.untyped.SoftLink([devBase devnm]);
eglink = types.untyped.ObjectView([ephysBase egnm]);
etReg = types.untyped.ObjectView([ephysBase 'electrodes']);
dev = types.core.Device();
file.general_devices.set(devnm, dev);
file.general_devices.set('dev1', dev);

egnm = 'tetrode1';
eg = types.core.ElectrodeGroup( ...
'description', 'tetrode description', ...
'location', 'tetrode location', ...
'device', devlink);
'device', types.untyped.SoftLink(dev));

electrodes = util.createElectrodeTable();
for i = 1:4
Expand All @@ -24,7 +18,7 @@ function addContainer(testCase, file) %#ok<INUSL>
'imp', 1,...
'location', {'CA1'},...
'filtering', 0,...
'group', eglink, 'group_name', {egnm});
'group', types.untyped.ObjectView(eg), 'group_name', {egnm});
end
file.general_extracellular_ephys_electrodes = electrodes;

Expand All @@ -35,9 +29,9 @@ function addContainer(testCase, file) %#ok<INUSL>
'electrodes', ...
types.hdmf_common.DynamicTableRegion(...
'data', [0;2],...
'table', etReg,...
'table', types.untyped.ObjectView(electrodes),...
'description', 'the first and third electrodes'));
file.acquisition.set(esnm, es);
file.acquisition.set('test_eS', es);
end

function c = getContainer(testCase, file) %#ok<INUSL>
Expand Down
2 changes: 1 addition & 1 deletion +tests/+system/ElectrodeGroupIOTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function addContainer(testCase, file) %#ok<INUSL>
eg = types.core.ElectrodeGroup( ...
'description', 'a test ElectrodeGroup', ...
'location', 'a nonexistent place', ...
'device', types.untyped.SoftLink('/general/devices/dev1'));
'device', types.untyped.SoftLink(dev));
file.general_extracellular_ephys.set('elec1', eg);
end

Expand Down
2 changes: 1 addition & 1 deletion +tests/+system/ImagingPlaneIOTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function addContainer(testCase, file) %#ok<INUSL>
ip = types.core.ImagingPlane( ...
'description', 'a fake ImagingPlane', ...
'optchan1', oc, ...
'device', types.untyped.SoftLink('/general/devices/imaging_device_1'), ...
'device', types.untyped.SoftLink(dev), ...
'excitation_lambda', 6.28, ...
'imaging_rate', 2.718, ...
'indicator', 'GFP', ...
Expand Down
74 changes: 1 addition & 73 deletions +tests/+system/NwbTestInterface.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,79 +31,7 @@ function setupMethod(testCase)
function n = className(testCase)
classSplit = strsplit(class(testCase), '.');
n = classSplit{end};
end

function verifyContainerEqual(testCase, actual, expected)
testCase.verifyEqual(class(actual), class(expected));
props = properties(actual);
for i = 1:numel(props)
prop = props{i};
if strcmp(prop, 'file_create_date')
continue;
end
actualVal = actual.(prop);
expectedVal = expected.(prop);
failmsg = ['Values for property ''' prop ''' are not equal'];
if startsWith(class(actualVal), 'types.')...
&& ~startsWith(class(actualVal), 'types.untyped')
verifyContainerEqual(testCase, actualVal, expectedVal);
elseif isa(actualVal, 'types.untyped.Set')
verifySetEqual(testCase, actualVal, expectedVal, failmsg);
elseif isdatetime(actualVal)
testCase.verifyEqual(char(actualVal), char(expectedVal), failmsg);
else
if isa(actualVal, 'types.untyped.DataStub')
actualTrue = actualVal.load();
else
actualTrue = actualVal;
end

if isvector(expectedVal) && isvector(actualTrue) && numel(expectedVal) == numel(actualTrue)
actualTrue = reshape(actualTrue, size(expectedVal));
end

if isinteger(actualTrue) && isinteger(expectedVal)
actualSize = class(actualTrue);
actualSize = str2double(actualSize(4:end));
expectedSize = class(expectedVal);
expectedSize = str2double(expectedSize(4:end));
testCase.verifyGreaterThanOrEqual(actualSize, expectedSize, failmsg);
testCase.verifyEqual(double(actualTrue), double(expectedVal), failmsg);
continue;
end
testCase.verifyEqual(actualTrue, expectedVal, failmsg);
end
end
end

function verifySetEqual(testCase, actual, expected, failmsg)
testCase.verifyEqual(class(actual), class(expected));
ak = actual.keys();
ek = expected.keys();
verifyTrue(testCase, isempty(setxor(ak, ek)), failmsg);
for i=1:numel(ak)
key = ak{i};
verifyContainerEqual(testCase, actual.get(key), ...
expected.get(key));
end
end

function verifyUntypedEqual(testCase, actual, expected)
testCase.verifyEqual(class(actual), class(expected));
props = properties(actual);
for i = 1:numel(props)
prop = props{i};
val1 = actual.(prop);
val2 = expected.(prop);
if isa(val1, 'types.core.NWBContainer') || isa(val1, 'types.core.NWBData')
verifyContainerEqual(testCase, val1, val2);
else
testCase.verifyEqual(val1, val2, ...
['Values for property ''' prop ''' are not equal']);
end
end
end

end
end

methods(Abstract)
Expand Down
12 changes: 6 additions & 6 deletions +tests/+system/PhotonSeriesIOTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ function addContainer(testCase, file) %#ok<INUSL>
ip = types.core.ImagingPlane( ...
'description', 'a fake ImagingPlane', ...
'optchan1', oc, ...
'device', types.untyped.SoftLink('/general/devices/dev1'), ...
'device', types.untyped.SoftLink(dev), ...
'excitation_lambda', 6.28, ...
'imaging_rate', 2.718, ...
'indicator', 'GFP', ...
'location', 'somewhere in the brain');

tps = types.core.TwoPhotonSeries( ...
'data', ones(3,3,3), ...
'imaging_plane', types.untyped.SoftLink('/general/optophysiology/imgpln1'), ...
'imaging_plane', types.untyped.SoftLink(ip), ...
'data_unit', 'image_unit', ...
'format', 'raw', ...
'field_of_view', [2, 2, 5] .', ...
Expand All @@ -37,18 +37,18 @@ function addContainer(testCase, file) %#ok<INUSL>

function appendContainer(~, file)
oldImagingPlane = file.general_optophysiology.get('imgpln1');
file.general_optophysiology.set('imgpln2',...
types.core.ImagingPlane(...
newImagingPlane = types.core.ImagingPlane(...
'description', 'a different imaging plane',...
'device', oldImagingPlane.device,...
'optchan1', oldImagingPlane.opticalchannel.get('optchan1'),...
'excitation_lambda', 1,...
'imaging_rate', 2,...
'indicator', 'ASL',...
'location', 'somewhere else in the brain'));
'location', 'somewhere else in the brain');
file.general_optophysiology.set('imgpln2', newImagingPlane);

hTwoPhotonSeries = file.acquisition.get('test_2ps');
hTwoPhotonSeries.imaging_plane.path = '/general/optophysiology/imgpln2';
hTwoPhotonSeries.imaging_plane = types.untyped.SoftLink(newImagingPlane);
hTwoPhotonSeries.data = hTwoPhotonSeries.data + rand();
end
end
Expand Down
95 changes: 49 additions & 46 deletions +tests/+system/PyNWBIOTest.m
Original file line number Diff line number Diff line change
@@ -1,51 +1,54 @@
classdef PyNWBIOTest < tests.system.RoundTripTest
% Assumes PyNWB and unittest2 has been installed on the system.
%
% To install PyNWB, execute:
% $ pip install pynwb
%
% To install unittest2, execute:
% $ pip install unittest2
methods(Test)
function testOutToPyNWB(testCase)
filename = ['MatNWB.' testCase.className() '.testOutToPyNWB.nwb'];
nwbExport(testCase.file, filename);
[status, cmdout] = testCase.runPyTest('testInFromMatNWB');
if status
testCase.verifyFail(cmdout);
end
% Assumes PyNWB and unittest2 has been installed on the system.
%
% To install PyNWB, execute:
% $ pip install pynwb
%
% To install unittest2, execute:
% $ pip install unittest2
methods(Test)
function testOutToPyNWB(testCase)
filename = ['MatNWB.' testCase.className() '.testOutToPyNWB.nwb'];
nwbExport(testCase.file, filename);
[status, cmdout] = testCase.runPyTest('testInFromMatNWB');
if status
testCase.verifyFail(cmdout);
end
end

function testInFromPyNWB(testCase)
[status, cmdout] = testCase.runPyTest('testOutToMatNWB');
if status
testCase.assertFail(cmdout);
end
filename = ['PyNWB.' testCase.className() '.testOutToMatNWB.nwb'];
pyfile = nwbRead(filename);
pycontainer = testCase.getContainer(pyfile);
matcontainer = testCase.getContainer(testCase.file);
nwbExport(testCase.file, 'temp.nwb'); % hack to fill out ObjectView container paths.
% ignore file_create_date because nwbExport will actually
% mutate the property every export.
tests.util.verifyContainerEqual(testCase, pycontainer, matcontainer, {'file_create_date'});
end
end

function testInFromPyNWB(testCase)
[status, cmdout] = testCase.runPyTest('testOutToMatNWB');
if status
testCase.assertFail(cmdout);
end
filename = ['PyNWB.' testCase.className() '.testOutToMatNWB.nwb'];
pyfile = nwbRead(filename);
pycontainer = testCase.getContainer(pyfile);
matcontainer = testCase.getContainer(testCase.file);
testCase.verifyContainerEqual(pycontainer, matcontainer);
methods
function [status, cmdout] = runPyTest(testCase, testName)
setenv('PYTHONPATH', fileparts(mfilename('fullpath')));

envPath = fullfile('+tests', 'env.mat');
if 2 == exist(envPath, 'file')
Env = load(envPath, '-mat', 'pythonDir');

pythonPath = fullfile(Env.pythonDir, 'python');
else
pythonPath = 'python';
end

cmd = sprintf('"%s" -B -m unittest %s.%s.%s',...
pythonPath,...
'PyNWBIOTest', testCase.className(), testName);
[status, cmdout] = system(cmd);
end
end
end

methods
function [status, cmdout] = runPyTest(testCase, testName)
setenv('PYTHONPATH', fileparts(mfilename('fullpath')));

envPath = fullfile('+tests', 'env.mat');
if 2 == exist(envPath, 'file')
Env = load(envPath, '-mat', 'pythonDir');

pythonPath = fullfile(Env.pythonDir, 'python');
else
pythonPath = 'python';
end

cmd = sprintf('"%s" -B -m unittest %s.%s.%s',...
pythonPath,...
'PyNWBIOTest', testCase.className(), testName);
[status, cmdout] = system(cmd);
end
end
end
2 changes: 1 addition & 1 deletion +tests/+system/RoundTripTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function testRoundTrip(testCase)
writeContainer = testCase.getContainer(testCase.file);
readFile = nwbRead(filename);
readContainer = testCase.getContainer(readFile);
testCase.verifyContainerEqual(readContainer, writeContainer);
tests.util.verifyContainerEqual(testCase, readContainer, writeContainer);
end
end
end
2 changes: 1 addition & 1 deletion +tests/+system/UnitTimesIOTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
function addContainer(~, file)
vdata = rand(10,1);
file.units = types.core.Units('description', 'test Units', 'colnames', {'spike_times'});
file.units.addRow('spike_times', vdata(1), 'tablepath', '/units');
file.units.addRow('spike_times', vdata(1));
file.units.addRow('spike_times', vdata(2:5));
file.units.addRow('spike_times', vdata(6:end));
end
Expand Down
2 changes: 1 addition & 1 deletion +tests/+unit/anonTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function testAnonDataset(testCase)
'session_description', 'anonymous class schema testing',...
'session_start_time', datetime());
nwbExpected.acquisition.set('ag', ag);
nwbExpected.export('testanon.nwb');
nwbExport(nwbExpected, 'testanon.nwb');

tests.util.verifyContainerEqual(testCase, nwbRead('testanon.nwb'), nwbExpected);
end
2 changes: 1 addition & 1 deletion +tests/+unit/dataStubTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function testObjectCopy(testCase)
'identifier', 'DATASTUB',...
'session_description', 'test datastub object copy',...
'session_start_time', datetime());
rc = types.rrs.RefContainer('data', rand(100, 100));
rc = types.rrs.RefContainer('data', types.rrs.RefData('data', rand(100, 100)));
rcPath = '/acquisition/rc';
rcDataPath = [rcPath '/data'];
rcRef = types.cs.CompoundRefData('data', table(...
Expand Down
Loading

0 comments on commit 299c345

Please sign in to comment.