Skip to content

Commit

Permalink
Fix inherited readonly props (#560)
Browse files Browse the repository at this point in the history
* Define validator method for readonly props

Some readonly props are inherited from superclasses where the same prop is settable. This will override the validator method for such a property to throw an error if someone tries to set a readonly property

* remove debug try/catch

* Fix bug with datetime conversion

* Update linkTest.m

Fix test that broke because of current PR

* Minor fixes

Only add validator for inherited readonly props
Also support boolean read only property values
  • Loading branch information
ehennestad authored Feb 8, 2024
1 parent 9d77234 commit 5396243
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 12 deletions.
2 changes: 1 addition & 1 deletion +file/fillClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
classprops,...
namespace);
setterFcns = file.fillSetters(setdiff(nonInherited, union(readonly, hiddenAndReadonly)));
validatorFcns = file.fillValidators(allProperties, classprops, namespace);
validatorFcns = file.fillValidators(allProperties, classprops, namespace, namespace.getFullClassName(name), inherited);
exporterFcns = file.fillExport(nonInherited, class, depnm);
methodBody = strjoin({constructorBody...
'%% SETTERS' setterFcns...
Expand Down
55 changes: 47 additions & 8 deletions +file/fillValidators.m
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
function validationStr = fillValidators(propnames, props, namespacereg)
function validationStr = fillValidators(propnames, props, namespacereg, className, inherited)
validationStr = '';
for i=1:length(propnames)
nm = propnames{i};
prop = props(nm);

% if readonly and value exists then ignore

if isa(prop, 'file.Attribute') && prop.readonly && ~isempty(prop.value)
continue;
end
if startsWith(class(prop), 'file.')
validationBody = fillUnitValidation(nm, prop, namespacereg);
else % primitive type
validationBody = fillDtypeValidation(nm, prop);
% Need to add a validator for inherited and readonly properties. In
% the superclass these properties might not be read only and due to
% inheritance its not possible to change property attributes
if any(strcmp(nm, inherited))
validationBody = fillReadOnlyValidator(nm, prop.value, className);
else
continue
end
else
if startsWith(class(prop), 'file.')
validationBody = fillUnitValidation(nm, prop, namespacereg);
else % primitive type
validationBody = fillDtypeValidation(nm, prop);
end
end

headerStr = ['function val = validate_' nm '(obj, val)'];
if isempty(validationBody)
funcstionStr = [headerStr newline 'end'];
Expand Down Expand Up @@ -279,4 +288,34 @@
fdvstr = [fdvstr ...
'val = types.util.checkDtype(''' name ''', ''' ts ''', val);'];
end
end

function fdvstr = fillReadOnlyValidator(name, value, className)

classNameSplit = strsplit(className, '.');
shortName = classNameSplit{end};

errorStr = sprintf( 'error(''Unable to set the ''''%s'''' property of class ''''<a href="matlab:doc %s">%s</a>'''' because it is read-only.'')', name, className, shortName);

if ischar(value)
condition = strjoin({ ...
sprintf('if isequal(val, ''%s'')', value), ...
sprintf(' val = ''%s'';', value ), ...
'else' }, newline);
elseif isnumeric(value) || islogical(value)
condition = strjoin({ ...
sprintf('if isequal(val, %d)', value), ...
sprintf(' val = %d;', value ), ...
'else' }, newline);
else
% Note: According to the documentation for Attribute specification keys
% (https://schema-language.readthedocs.io/en/latest/description.html#sec-attributes-spec),
% the above cases should be sufficient.
error('Unhandled case')
end

fdvstr = strjoin({...
condition, ...
sprintf(' %s', errorStr), ...
'end' }, newline );
end
4 changes: 2 additions & 2 deletions +io/timestamp2datetime.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
, 'Day', ymdStamp(7:8) ...
);
end
Datetime.Year = str2double(YmdToken.Year);
Datetime.Month = str2double(YmdToken.Month);
Datetime.Day = str2double(YmdToken.Day);
Datetime.Month = str2double(YmdToken.Month);
Datetime.Year = str2double(YmdToken.Year);
assert(~isnat(Datetime), errorId, sprintf(errorTemplate, 'non-numeric YMD values detected'));

%% HMiS TZ
Expand Down
2 changes: 1 addition & 1 deletion +tests/+unit/linkTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function testExternalResolution(testCase)
'table', types.untyped.ObjectView('/acquisition/es1'),...
'description', 'dtr stub that points to electrical series illegally'); % do not do this at home.
expected = types.core.ElectricalSeries('data', expectedData,...
'data_unit', 'unit',...
'data_unit', 'volts', ...
'electrodes', stubDtr);
nwb.acquisition.set('es1', expected);
nwb.export('test1.nwb');
Expand Down

0 comments on commit 5396243

Please sign in to comment.