Skip to content

Commit fedd2ce

Browse files
authored
Fix: Cache with map of required properties per neurodata type must be 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
1 parent a9fad2d commit fedd2ce

File tree

10 files changed

+81
-10
lines changed

10 files changed

+81
-10
lines changed

+file/writeNamespace.m

+26-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ function writeNamespace(namespaceName, saveDir)
33
Namespace = schemes.loadNamespace(namespaceName, saveDir);
44

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

78
if ~isfolder(classFileDir)
89
mkdir(classFileDir);
@@ -29,4 +30,28 @@ function writeNamespace(namespaceName, saveDir)
2930
% pass
3031
end
3132
end
32-
end
33+
end
34+
35+
function writeNamespaceVersion(classFileDir, version)
36+
% writeNamespaceVersion - Write function for retrieving version of
37+
% generated namespace.
38+
39+
functionTemplate = strjoin([...
40+
"function version = %s()", ...
41+
" version = '%s';", ...
42+
"end" ...
43+
], newline);
44+
45+
functionDefinition = sprintf(functionTemplate, ...
46+
matnwb.common.constant.VERSIONFUNCTION, ...
47+
version);
48+
49+
if ~isfolder(classFileDir); mkdir(classFileDir); end
50+
namespaceVersionFilename = fullfile(...
51+
classFileDir, ...
52+
matnwb.common.constant.VERSIONFILE);
53+
54+
fid = fopen(namespaceVersionFilename, 'wt');
55+
fwrite(fid, functionDefinition);
56+
fclose(fid);
57+
end
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function constant = VERSIONFILE()
2+
constant = [matnwb.common.constant.VERSIONFUNCTION, '.m'];
3+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function constant = VERSIONFUNCTION()
2+
constant = 'Version';
3+
end

+schemes/Namespace.m

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
classdef Namespace < handle
22
properties (SetAccess=private)
33
name = '' % name of this namespace
4+
version = '' % version of this namespace
45
dependencies = [] % parent namespaces by [Namespace]
56
registry = [] % maps name to class
67
end
@@ -11,12 +12,13 @@
1112
end
1213

1314
methods
14-
function obj = Namespace(name, deplist, source)
15+
function obj = Namespace(name, version, deplist, source)
1516
if nargin == 0
1617
return
1718
end
1819

1920
obj.name = strrep(name, '-', '_');
21+
obj.version = version;
2022
obj.dependencies = deplist;
2123
namespaceFiles = keys(source);
2224
obj.registry = [];

+schemes/loadNamespace.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
ancestry(i) = schemes.loadNamespace(ancestorName, saveDir);
1515
end
1616

17-
Namespace = schemes.Namespace(name, ancestry, Cache.schema);
17+
Namespace = schemes.Namespace(name, Cache.version, ancestry, Cache.schema);
1818
end

+types/+core/Version.m

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function version = Version()
2+
version = '2.8.0';
3+
end

+types/+hdmf_common/Version.m

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function version = Version()
2+
version = '1.8.0';
3+
end

+types/+hdmf_experimental/Version.m

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function version = Version()
2+
version = '0.5.0';
3+
end

+types/+untyped/MetaClass.m

+32-7
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ function displayWarningIfMissingRequiredProps(obj)
182182

183183
propertyListStr = obj.prettyPrintPropertyList(missingRequiredProps);
184184
warning('NWB:RequiredPropertyMissing', ...
185-
'The following required properties are missing for instance for type "%s":\n%s', class(obj), propertyListStr)
185+
['The following required properties are missing for ', ...
186+
'instance for type "%s":\n%s'], class(obj), propertyListStr)
186187
end
187188
end
188189

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

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

229234
% Introspectively retrieve required properties and add to
230-
% persistent map.
235+
% persistent cache/map.
231236

232-
if isKey(obj.REQUIRED, class(obj) )
233-
requiredProps = obj.REQUIRED( class(obj) );
237+
typeClassName = class(obj);
238+
typeNamespaceVersion = getNamespaceVersionForType(typeClassName);
239+
240+
typeKey = sprintf('%s_%s', typeClassName, typeNamespaceVersion);
241+
242+
if isKey(obj.REQUIRED, typeKey)
243+
requiredProps = obj.REQUIRED( typeKey );
234244
else
235245
mc = metaclass(obj);
236246
propertyDescription = {mc.PropertyList.Description};
237247
isRequired = startsWith(propertyDescription, 'REQUIRED');
238248
requiredProps = {mc.PropertyList(isRequired).Name};
239-
obj.REQUIRED( class(obj) ) = requiredProps;
249+
obj.REQUIRED( typeKey ) = requiredProps;
240250
end
241251
end
242252

@@ -262,3 +272,18 @@ function checkCustomConstraint(obj) %#ok<MANU>
262272
end
263273
end
264274
end
275+
276+
function version = getNamespaceVersionForType(typeClassName)
277+
if strcmp(typeClassName, 'NwbFile')
278+
namespaceName = 'types.core';
279+
else
280+
classNameParts = strsplit(typeClassName, '.');
281+
namespaceName = strjoin(classNameParts(1:end-1), '.');
282+
end
283+
assert(startsWith(namespaceName, 'types.'), ...
284+
'Expected type to belong to namespace.')
285+
286+
version = feval( ...
287+
sprintf('%s.%s', namespaceName, matnwb.common.constant.VERSIONFUNCTION) ...
288+
);
289+
end

tools/documentation/private/generateRstForNeurodataTypeClasses.m

+4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ function generateRstForNeurodataTypeClasses(namespaceName)
44
arguments
55
namespaceName (1,1) string
66
end
7+
8+
filenameToIgnore = {matnwb.common.constant.VERSIONFILE};
9+
710
namespaceName = char(namespaceName);
811

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

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

0 commit comments

Comments
 (0)