From 73ae13af76e98abc359895af2adedf7abe1126b0 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Tue, 11 Feb 2025 21:57:54 +0100 Subject: [PATCH 1/4] Change warning to error --- +file/fillExport.m | 2 +- +tests/+unit/nwbExportTest.m | 2 +- +types/+core/ImageSeries.m | 2 +- +types/+core/ImagingPlane.m | 4 ++-- +types/+core/ImagingRetinotopy.m | 26 +++++++++++++------------- +types/+core/NWBFile.m | 8 +++++++- +types/+core/TimeSeries.m | 2 +- +types/+untyped/MetaClass.m | 10 ++++------ 8 files changed, 30 insertions(+), 26 deletions(-) diff --git a/+file/fillExport.m b/+file/fillExport.m index cfa21246..f6bd9323 100644 --- a/+file/fillExport.m +++ b/+file/fillExport.m @@ -248,7 +248,7 @@ if prop.required && not(prop.readonly) && not(isParentRequired) dependencyCheck{end+1} = sprintf('~isempty(obj.%s) && isempty(obj.%s)', depPropname, name); warnIfMissingRequiredDependentAttributeStr = ... - sprintf('obj.warnIfRequiredDependencyMissing(''%s'', ''%s'', fullpath)', name, depPropname); + sprintf('obj.throwErrorIfRequiredDependencyMissing(''%s'', ''%s'', fullpath)', name, depPropname); end end diff --git a/+tests/+unit/nwbExportTest.m b/+tests/+unit/nwbExportTest.m index 572ab7f2..3c17e62e 100644 --- a/+tests/+unit/nwbExportTest.m +++ b/+tests/+unit/nwbExportTest.m @@ -88,7 +88,7 @@ function testExportWithMissingRequiredDependentProperty(testCase) % Verify that exporting the file issues warning that a required % property (i.e general_source_script_file_name) is missing - testCase.verifyWarning( ... + testCase.verifyError( ... @(nwbObj, filePath) nwbExport(nwbFile, fileName + "_2.nwb"), ... 'NWB:DependentRequiredPropertyMissing') end diff --git a/+types/+core/ImageSeries.m b/+types/+core/ImageSeries.m index 8f62e4b1..01ef777d 100644 --- a/+types/+core/ImageSeries.m +++ b/+types/+core/ImageSeries.m @@ -243,7 +243,7 @@ function postset_external_file_starting_frame(obj) obj.warnIfPropertyAttributeNotExported('external_file_starting_frame', 'external_file', fullpath) end if ~isempty(obj.external_file) && isempty(obj.external_file_starting_frame) - obj.warnIfRequiredDependencyMissing('external_file_starting_frame', 'external_file', fullpath) + obj.throwErrorIfRequiredDependencyMissing('external_file_starting_frame', 'external_file', fullpath) end if ~isempty(obj.format) if startsWith(class(obj.format), 'types.untyped.') diff --git a/+types/+core/ImagingPlane.m b/+types/+core/ImagingPlane.m index 7e44472e..3fb72b16 100644 --- a/+types/+core/ImagingPlane.m +++ b/+types/+core/ImagingPlane.m @@ -468,7 +468,7 @@ function postset_origin_coords_unit(obj) obj.warnIfPropertyAttributeNotExported('grid_spacing_unit', 'grid_spacing', fullpath) end if ~isempty(obj.grid_spacing) && isempty(obj.grid_spacing_unit) - obj.warnIfRequiredDependencyMissing('grid_spacing_unit', 'grid_spacing', fullpath) + obj.throwErrorIfRequiredDependencyMissing('grid_spacing_unit', 'grid_spacing', fullpath) end if ~isempty(obj.imaging_rate) if startsWith(class(obj.imaging_rate), 'types.untyped.') @@ -514,7 +514,7 @@ function postset_origin_coords_unit(obj) obj.warnIfPropertyAttributeNotExported('origin_coords_unit', 'origin_coords', fullpath) end if ~isempty(obj.origin_coords) && isempty(obj.origin_coords_unit) - obj.warnIfRequiredDependencyMissing('origin_coords_unit', 'origin_coords', fullpath) + obj.throwErrorIfRequiredDependencyMissing('origin_coords_unit', 'origin_coords', fullpath) end if ~isempty(obj.reference_frame) if startsWith(class(obj.reference_frame), 'types.untyped.') diff --git a/+types/+core/ImagingRetinotopy.m b/+types/+core/ImagingRetinotopy.m index 38725740..aa27fccd 100644 --- a/+types/+core/ImagingRetinotopy.m +++ b/+types/+core/ImagingRetinotopy.m @@ -1024,7 +1024,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_1_power_map_dimension', 'axis_1_power_map', fullpath) end if ~isempty(obj.axis_1_power_map) && isempty(obj.axis_1_power_map_dimension) - obj.warnIfRequiredDependencyMissing('axis_1_power_map_dimension', 'axis_1_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_1_power_map_dimension', 'axis_1_power_map', fullpath) end if ~isempty(obj.axis_1_power_map) && ~isa(obj.axis_1_power_map, 'types.untyped.SoftLink') && ~isa(obj.axis_1_power_map, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/axis_1_power_map/field_of_view'], obj.axis_1_power_map_field_of_view, 'forceArray'); @@ -1032,7 +1032,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_1_power_map_field_of_view', 'axis_1_power_map', fullpath) end if ~isempty(obj.axis_1_power_map) && isempty(obj.axis_1_power_map_field_of_view) - obj.warnIfRequiredDependencyMissing('axis_1_power_map_field_of_view', 'axis_1_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_1_power_map_field_of_view', 'axis_1_power_map', fullpath) end if ~isempty(obj.axis_1_power_map) && ~isa(obj.axis_1_power_map, 'types.untyped.SoftLink') && ~isa(obj.axis_1_power_map, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/axis_1_power_map/unit'], obj.axis_1_power_map_unit); @@ -1040,7 +1040,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_1_power_map_unit', 'axis_1_power_map', fullpath) end if ~isempty(obj.axis_1_power_map) && isempty(obj.axis_1_power_map_unit) - obj.warnIfRequiredDependencyMissing('axis_1_power_map_unit', 'axis_1_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_1_power_map_unit', 'axis_1_power_map', fullpath) end if startsWith(class(obj.axis_2_phase_map), 'types.untyped.') refs = obj.axis_2_phase_map.export(fid, [fullpath '/axis_2_phase_map'], refs); @@ -1075,7 +1075,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_2_power_map_dimension', 'axis_2_power_map', fullpath) end if ~isempty(obj.axis_2_power_map) && isempty(obj.axis_2_power_map_dimension) - obj.warnIfRequiredDependencyMissing('axis_2_power_map_dimension', 'axis_2_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_2_power_map_dimension', 'axis_2_power_map', fullpath) end if ~isempty(obj.axis_2_power_map) && ~isa(obj.axis_2_power_map, 'types.untyped.SoftLink') && ~isa(obj.axis_2_power_map, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/axis_2_power_map/field_of_view'], obj.axis_2_power_map_field_of_view, 'forceArray'); @@ -1083,7 +1083,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_2_power_map_field_of_view', 'axis_2_power_map', fullpath) end if ~isempty(obj.axis_2_power_map) && isempty(obj.axis_2_power_map_field_of_view) - obj.warnIfRequiredDependencyMissing('axis_2_power_map_field_of_view', 'axis_2_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_2_power_map_field_of_view', 'axis_2_power_map', fullpath) end if ~isempty(obj.axis_2_power_map) && ~isa(obj.axis_2_power_map, 'types.untyped.SoftLink') && ~isa(obj.axis_2_power_map, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/axis_2_power_map/unit'], obj.axis_2_power_map_unit); @@ -1091,7 +1091,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('axis_2_power_map_unit', 'axis_2_power_map', fullpath) end if ~isempty(obj.axis_2_power_map) && isempty(obj.axis_2_power_map_unit) - obj.warnIfRequiredDependencyMissing('axis_2_power_map_unit', 'axis_2_power_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('axis_2_power_map_unit', 'axis_2_power_map', fullpath) end if startsWith(class(obj.axis_descriptions), 'types.untyped.') refs = obj.axis_descriptions.export(fid, [fullpath '/axis_descriptions'], refs); @@ -1111,7 +1111,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('focal_depth_image_bits_per_pixel', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && isempty(obj.focal_depth_image_bits_per_pixel) - obj.warnIfRequiredDependencyMissing('focal_depth_image_bits_per_pixel', 'focal_depth_image', fullpath) + obj.throwErrorIfRequiredDependencyMissing('focal_depth_image_bits_per_pixel', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && ~isa(obj.focal_depth_image, 'types.untyped.SoftLink') && ~isa(obj.focal_depth_image, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/focal_depth_image/dimension'], obj.focal_depth_image_dimension, 'forceArray'); @@ -1119,7 +1119,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('focal_depth_image_dimension', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && isempty(obj.focal_depth_image_dimension) - obj.warnIfRequiredDependencyMissing('focal_depth_image_dimension', 'focal_depth_image', fullpath) + obj.throwErrorIfRequiredDependencyMissing('focal_depth_image_dimension', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && ~isa(obj.focal_depth_image, 'types.untyped.SoftLink') && ~isa(obj.focal_depth_image, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/focal_depth_image/field_of_view'], obj.focal_depth_image_field_of_view, 'forceArray'); @@ -1127,7 +1127,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('focal_depth_image_field_of_view', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && isempty(obj.focal_depth_image_field_of_view) - obj.warnIfRequiredDependencyMissing('focal_depth_image_field_of_view', 'focal_depth_image', fullpath) + obj.throwErrorIfRequiredDependencyMissing('focal_depth_image_field_of_view', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && ~isa(obj.focal_depth_image, 'types.untyped.SoftLink') && ~isa(obj.focal_depth_image, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/focal_depth_image/focal_depth'], obj.focal_depth_image_focal_depth); @@ -1135,7 +1135,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('focal_depth_image_focal_depth', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && isempty(obj.focal_depth_image_focal_depth) - obj.warnIfRequiredDependencyMissing('focal_depth_image_focal_depth', 'focal_depth_image', fullpath) + obj.throwErrorIfRequiredDependencyMissing('focal_depth_image_focal_depth', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && ~isa(obj.focal_depth_image, 'types.untyped.SoftLink') && ~isa(obj.focal_depth_image, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/focal_depth_image/format'], obj.focal_depth_image_format); @@ -1143,7 +1143,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('focal_depth_image_format', 'focal_depth_image', fullpath) end if ~isempty(obj.focal_depth_image) && isempty(obj.focal_depth_image_format) - obj.warnIfRequiredDependencyMissing('focal_depth_image_format', 'focal_depth_image', fullpath) + obj.throwErrorIfRequiredDependencyMissing('focal_depth_image_format', 'focal_depth_image', fullpath) end if ~isempty(obj.sign_map) if startsWith(class(obj.sign_map), 'types.untyped.') @@ -1158,7 +1158,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('sign_map_dimension', 'sign_map', fullpath) end if ~isempty(obj.sign_map) && isempty(obj.sign_map_dimension) - obj.warnIfRequiredDependencyMissing('sign_map_dimension', 'sign_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('sign_map_dimension', 'sign_map', fullpath) end if ~isempty(obj.sign_map) && ~isa(obj.sign_map, 'types.untyped.SoftLink') && ~isa(obj.sign_map, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/sign_map/field_of_view'], obj.sign_map_field_of_view, 'forceArray'); @@ -1166,7 +1166,7 @@ function postset_vasculature_image_format(obj) obj.warnIfPropertyAttributeNotExported('sign_map_field_of_view', 'sign_map', fullpath) end if ~isempty(obj.sign_map) && isempty(obj.sign_map_field_of_view) - obj.warnIfRequiredDependencyMissing('sign_map_field_of_view', 'sign_map', fullpath) + obj.throwErrorIfRequiredDependencyMissing('sign_map_field_of_view', 'sign_map', fullpath) end if startsWith(class(obj.vasculature_image), 'types.untyped.') refs = obj.vasculature_image.export(fid, [fullpath '/vasculature_image'], refs); diff --git a/+types/+core/NWBFile.m b/+types/+core/NWBFile.m index 1f7e1df7..ef39f930 100644 --- a/+types/+core/NWBFile.m +++ b/+types/+core/NWBFile.m @@ -431,6 +431,12 @@ function postset_general_source_script_file_name(obj) end function set.session_start_time(obj, val) obj.session_start_time = obj.validate_session_start_time(val); + obj.postset_session_start_time() + end + function postset_session_start_time(obj) + if isempty(obj.timestamps_reference_time) + obj.timestamps_reference_time = obj.session_start_time; + end end function set.stimulus_presentation(obj, val) obj.stimulus_presentation = obj.validate_stimulus_presentation(val); @@ -1155,7 +1161,7 @@ function postset_general_source_script_file_name(obj) obj.warnIfPropertyAttributeNotExported('general_source_script_file_name', 'general_source_script', fullpath) end if ~isempty(obj.general_source_script) && isempty(obj.general_source_script_file_name) - obj.warnIfRequiredDependencyMissing('general_source_script_file_name', 'general_source_script', fullpath) + obj.throwErrorIfRequiredDependencyMissing('general_source_script_file_name', 'general_source_script', fullpath) end io.writeGroup(fid, [fullpath '/general']); if ~isempty(obj.general_stimulus) diff --git a/+types/+core/TimeSeries.m b/+types/+core/TimeSeries.m index 3d7725ae..993a0fb5 100644 --- a/+types/+core/TimeSeries.m +++ b/+types/+core/TimeSeries.m @@ -474,7 +474,7 @@ function postset_starting_time_rate(obj) obj.warnIfPropertyAttributeNotExported('starting_time_rate', 'starting_time', fullpath) end if ~isempty(obj.starting_time) && isempty(obj.starting_time_rate) - obj.warnIfRequiredDependencyMissing('starting_time_rate', 'starting_time', fullpath) + obj.throwErrorIfRequiredDependencyMissing('starting_time_rate', 'starting_time', fullpath) end if ~isempty(obj.starting_time) && ~isa(obj.starting_time, 'types.untyped.SoftLink') && ~isa(obj.starting_time, 'types.untyped.ExternalLink') io.writeAttribute(fid, [fullpath '/starting_time/unit'], obj.starting_time_unit); diff --git a/+types/+untyped/MetaClass.m b/+types/+untyped/MetaClass.m index f582d754..fd6b822b 100644 --- a/+types/+untyped/MetaClass.m +++ b/+types/+untyped/MetaClass.m @@ -186,17 +186,15 @@ function displayWarningIfMissingRequiredProps(obj) end end - function warnIfRequiredDependencyMissing(obj, propName, depPropName, fullpath) + function throwErrorIfRequiredDependencyMissing(obj, propName, depPropName, fullpath) if isempty(fullpath); fullpath = 'root'; end - warnState = warning('backtrace', 'off'); - cleanupObj = onCleanup(@(s) warning(warnState)); - warningId = 'NWB:DependentRequiredPropertyMissing'; - warningMessage = sprintf( [ ... + errorId = 'NWB:DependentRequiredPropertyMissing'; + errorMessage = sprintf( [ ... 'The property "%s" of type "%s" in file location "%s" is ' ... 'required when the property "%s" is set. Please add a value ' ... 'for "%s" and re-export.'], ... propName, class(obj), fullpath, depPropName, propName); - warning(warningId, warningMessage) %#ok + error(errorId, errorMessage) %#ok end function throwErrorIfMissingRequiredProps(obj, fullpath) From 32890c9b25c45302e427a07404869975f30b5190 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Tue, 11 Feb 2025 22:04:57 +0100 Subject: [PATCH 2/4] Fix comments --- +tests/+unit/nwbExportTest.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/+tests/+unit/nwbExportTest.m b/+tests/+unit/nwbExportTest.m index 3c17e62e..f48ede42 100644 --- a/+tests/+unit/nwbExportTest.m +++ b/+tests/+unit/nwbExportTest.m @@ -74,7 +74,7 @@ function testExportWithMissingRequiredDependentProperty(testCase) nwbFile = testCase.initNwbFile(); fileName = "testExportWithMissingRequiredDependentProperty"; - % Should work without warning + % Should work without error testCase.verifyWarningFree( ... @(nwbObj, filePath) nwbExport(nwbFile, fileName + "_1.nwb") ) @@ -85,9 +85,8 @@ function testExportWithMissingRequiredDependentProperty(testCase) % property. nwbFile.general_source_script = '.../nwbExportTest.m'; - % Verify that exporting the file issues warning that a required - % property (i.e general_source_script_file_name) is missing - + % Verify that exporting the file throws an error, stating that a + % required property (i.e general_source_script_file_name) is missing testCase.verifyError( ... @(nwbObj, filePath) nwbExport(nwbFile, fileName + "_2.nwb"), ... 'NWB:DependentRequiredPropertyMissing') From f0d65f1da1fdd1271025e565b7de54d63362a6a3 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Tue, 11 Feb 2025 22:05:59 +0100 Subject: [PATCH 3/4] remove verifyWarningFree as its obsolete now --- +tests/+unit/nwbExportTest.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/+tests/+unit/nwbExportTest.m b/+tests/+unit/nwbExportTest.m index f48ede42..5ef8eaa5 100644 --- a/+tests/+unit/nwbExportTest.m +++ b/+tests/+unit/nwbExportTest.m @@ -75,8 +75,7 @@ function testExportWithMissingRequiredDependentProperty(testCase) fileName = "testExportWithMissingRequiredDependentProperty"; % Should work without error - testCase.verifyWarningFree( ... - @(nwbObj, filePath) nwbExport(nwbFile, fileName + "_1.nwb") ) + nwbExport(nwbFile, fileName + "_1.nwb") % Now we add a value to the "general_source_script" property. This % is a dataset with a required attribute called "file_name". From 8be6d7fd53f4dbb0052ce79f60e09494f6f7f948 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Tue, 11 Feb 2025 22:54:39 +0100 Subject: [PATCH 4/4] Fix wrongly generated class file --- +types/+core/NWBFile.m | 6 ------ 1 file changed, 6 deletions(-) diff --git a/+types/+core/NWBFile.m b/+types/+core/NWBFile.m index ef39f930..39593731 100644 --- a/+types/+core/NWBFile.m +++ b/+types/+core/NWBFile.m @@ -431,12 +431,6 @@ function postset_general_source_script_file_name(obj) end function set.session_start_time(obj, val) obj.session_start_time = obj.validate_session_start_time(val); - obj.postset_session_start_time() - end - function postset_session_start_time(obj) - if isempty(obj.timestamps_reference_time) - obj.timestamps_reference_time = obj.session_start_time; - end end function set.stimulus_presentation(obj, val) obj.stimulus_presentation = obj.validate_stimulus_presentation(val);