Skip to content

Commit

Permalink
Fix: Cache with map of required properties per neurodata type must be…
Browse files Browse the repository at this point in the history
… version specific (#670)

* Add "version" as property to Namespace class

* Add routine for writing a function for retrieving version of generated namespace

* Regenerate core with version numbers

* Update generateRstForNeurodataTypeClasses.m

Ignore version function when creating list of neurodata types to document

* Add version specificity to cache containing map of required properties
  • Loading branch information
ehennestad authored Feb 17, 2025
1 parent a9fad2d commit fedd2ce
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 10 deletions.
27 changes: 26 additions & 1 deletion +file/writeNamespace.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ function writeNamespace(namespaceName, saveDir)
Namespace = schemes.loadNamespace(namespaceName, saveDir);

classFileDir = fullfile(saveDir, '+types', ['+' misc.str2validName(Namespace.name)]);
writeNamespaceVersion(classFileDir, Namespace.version)

if ~isfolder(classFileDir)
mkdir(classFileDir);
Expand All @@ -29,4 +30,28 @@ function writeNamespace(namespaceName, saveDir)
% pass
end
end
end
end

function writeNamespaceVersion(classFileDir, version)
% writeNamespaceVersion - Write function for retrieving version of
% generated namespace.

functionTemplate = strjoin([...
"function version = %s()", ...
" version = '%s';", ...
"end" ...
], newline);

functionDefinition = sprintf(functionTemplate, ...
matnwb.common.constant.VERSIONFUNCTION, ...
version);

if ~isfolder(classFileDir); mkdir(classFileDir); end
namespaceVersionFilename = fullfile(...
classFileDir, ...
matnwb.common.constant.VERSIONFILE);

fid = fopen(namespaceVersionFilename, 'wt');
fwrite(fid, functionDefinition);
fclose(fid);
end
3 changes: 3 additions & 0 deletions +matnwb/+common/+constant/VERSIONFILE.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function constant = VERSIONFILE()
constant = [matnwb.common.constant.VERSIONFUNCTION, '.m'];
end
3 changes: 3 additions & 0 deletions +matnwb/+common/+constant/VERSIONFUNCTION.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function constant = VERSIONFUNCTION()
constant = 'Version';
end
4 changes: 3 additions & 1 deletion +schemes/Namespace.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
classdef Namespace < handle
properties (SetAccess=private)
name = '' % name of this namespace
version = '' % version of this namespace
dependencies = [] % parent namespaces by [Namespace]
registry = [] % maps name to class
end
Expand All @@ -11,12 +12,13 @@
end

methods
function obj = Namespace(name, deplist, source)
function obj = Namespace(name, version, deplist, source)
if nargin == 0
return
end

obj.name = strrep(name, '-', '_');
obj.version = version;
obj.dependencies = deplist;
namespaceFiles = keys(source);
obj.registry = [];
Expand Down
2 changes: 1 addition & 1 deletion +schemes/loadNamespace.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
ancestry(i) = schemes.loadNamespace(ancestorName, saveDir);
end

Namespace = schemes.Namespace(name, ancestry, Cache.schema);
Namespace = schemes.Namespace(name, Cache.version, ancestry, Cache.schema);
end
3 changes: 3 additions & 0 deletions +types/+core/Version.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function version = Version()
version = '2.8.0';
end
3 changes: 3 additions & 0 deletions +types/+hdmf_common/Version.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function version = Version()
version = '1.8.0';
end
3 changes: 3 additions & 0 deletions +types/+hdmf_experimental/Version.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function version = Version()
version = '0.5.0';
end
39 changes: 32 additions & 7 deletions +types/+untyped/MetaClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ function displayWarningIfMissingRequiredProps(obj)

propertyListStr = obj.prettyPrintPropertyList(missingRequiredProps);
warning('NWB:RequiredPropertyMissing', ...
'The following required properties are missing for instance for type "%s":\n%s', class(obj), propertyListStr)
['The following required properties are missing for ', ...
'instance for type "%s":\n%s'], class(obj), propertyListStr)
end
end

Expand All @@ -202,7 +203,9 @@ function throwErrorIfMissingRequiredProps(obj, fullpath)
if ~isempty( missingRequiredProps )
propertyListStr = obj.prettyPrintPropertyList(missingRequiredProps);
error('NWB:RequiredPropertyMissing', ...
'The following required properties are missing for instance for type "%s" at file location "%s":\n%s', class(obj), fullpath, propertyListStr)
['The following required properties are missing for ', ...
'instance for type "%s" at file location "%s":\n%s' ], ...
class(obj), fullpath, propertyListStr)
end
end

Expand All @@ -211,7 +214,9 @@ function throwErrorIfCustomConstraintUnfulfilled(obj, fullpath)
obj.checkCustomConstraint()
catch ME
error('NWB:CustomConstraintUnfulfilled', ...
'The following error was caught when exporting type "%s" at file location "%s":\n%s', class(obj), fullpath, ME.message)
['The following error was caught when exporting type ', ...
'"%s" at file location "%s":\n%s'], ...
class(obj), fullpath, ME.message)
end
end
end
Expand All @@ -227,16 +232,21 @@ function checkCustomConstraint(obj) %#ok<MANU>
function requiredProps = getRequiredProperties(obj)

% Introspectively retrieve required properties and add to
% persistent map.
% persistent cache/map.

if isKey(obj.REQUIRED, class(obj) )
requiredProps = obj.REQUIRED( class(obj) );
typeClassName = class(obj);
typeNamespaceVersion = getNamespaceVersionForType(typeClassName);

typeKey = sprintf('%s_%s', typeClassName, typeNamespaceVersion);

if isKey(obj.REQUIRED, typeKey)
requiredProps = obj.REQUIRED( typeKey );
else
mc = metaclass(obj);
propertyDescription = {mc.PropertyList.Description};
isRequired = startsWith(propertyDescription, 'REQUIRED');
requiredProps = {mc.PropertyList(isRequired).Name};
obj.REQUIRED( class(obj) ) = requiredProps;
obj.REQUIRED( typeKey ) = requiredProps;
end
end

Expand All @@ -262,3 +272,18 @@ function checkCustomConstraint(obj) %#ok<MANU>
end
end
end

function version = getNamespaceVersionForType(typeClassName)
if strcmp(typeClassName, 'NwbFile')
namespaceName = 'types.core';
else
classNameParts = strsplit(typeClassName, '.');
namespaceName = strjoin(classNameParts(1:end-1), '.');
end
assert(startsWith(namespaceName, 'types.'), ...
'Expected type to belong to namespace.')

version = feval( ...
sprintf('%s.%s', namespaceName, matnwb.common.constant.VERSIONFUNCTION) ...
);
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ function generateRstForNeurodataTypeClasses(namespaceName)
arguments
namespaceName (1,1) string
end

filenameToIgnore = {matnwb.common.constant.VERSIONFILE};

namespaceName = char(namespaceName);

rootDir = misc.getMatnwbDir();
classFiles = dir(fullfile(rootDir, '+types', ['+', namespaceName], '*.m'));
classFiles(ismember({classFiles.name}, filenameToIgnore)) = [];

docsSourceRootDir = fullfile(misc.getMatnwbDir, 'docs', 'source');
exportDir = fullfile(docsSourceRootDir, 'pages', 'neurodata_types', namespaceName);
Expand Down

0 comments on commit fedd2ce

Please sign in to comment.