Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: Only embed specs/namespaces for types that are included in NWB file on export #615

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
21 changes: 21 additions & 0 deletions +schemes/+utility/listNwbTypeHierarchy.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function parentTypeNames = listNwbTypeHierarchy(nwbTypeName)
% listNwbTypeHierarchy - List the NWB type hierarchy for an NWB type
arguments
nwbTypeName (1,1) string
end

parentTypeNames = string.empty; % Initialize an empty cell array
currentType = nwbTypeName; % Start with the specific type

while ~strcmp(currentType, 'types.untyped.MetaClass')
parentTypeNames(end+1) = currentType; %#ok<AGROW>

% Use MetaClass information to get the parent type
metaClass = meta.class.fromName(currentType);
if isempty(metaClass.SuperclassList)
break; % Reached the base type

Check warning on line 16 in +schemes/+utility/listNwbTypeHierarchy.m

View check run for this annotation

Codecov / codecov/patch

+schemes/+utility/listNwbTypeHierarchy.m#L16

Added line #L16 was not covered by tests
end
% NWB parent type should always be the first superclass in the list
currentType = metaClass.SuperclassList(1).Name;
end
end
59 changes: 56 additions & 3 deletions NwbFile.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ function export(obj, filename, mode)
end

try
jsonSpecs = schemes.exportJson();
io.spec.writeEmbeddedSpecifications(output_file_id, jsonSpecs);
obj.embedSpecifications(output_file_id)
refs = [email protected](obj, output_file_id, '/', {});
obj.resolveReferences(output_file_id, refs);
H5F.close(output_file_id);
Expand Down Expand Up @@ -118,10 +117,49 @@ function export(obj, filename, mode)
typename,...
varargin{:});
end

function nwbTypeNames = listNwbTypes(obj)
% listNwbTypes - List all unique NWB types in file
objectMap = searchProperties(containers.Map, obj, '', '');

objects = objectMap.values();
objectClassNames = cellfun(@(c) string(class(c)), objects);
objectClassNames = unique(objectClassNames);

keep = startsWith(objectClassNames, "types.");
ignore = startsWith(objectClassNames, "types.untyped");

nwbTypeNames = objectClassNames(keep & ~ignore);
end
end

%% PRIVATE
methods(Access=private)
function embedSpecifications(obj, output_file_id)
jsonSpecs = schemes.exportJson();

% Resolve the name of all types and parent types that are
% included in this file, in order to only include the specs for
% namespaces of types that are included in the file.
includedNwbTypes = obj.listNwbTypes();
includedNwbTypesWithParents = string.empty;
for i = 1:numel(includedNwbTypes)
typeHierarchy = schemes.utility.listNwbTypeHierarchy(includedNwbTypes{i});
includedNwbTypesWithParents = [includedNwbTypesWithParents, typeHierarchy]; %#ok<AGROW>
end

% Get the namespace names
namespaceNames = getNamespacesOfTypes(includedNwbTypesWithParents);

% In the specs, the hyphen (-) is used as a word separator, while in
% matnwb the underscore (_) is used. Translate names here:
allMatlabNamespaceNames = strrep({jsonSpecs.name}, '-', '_');
[~, keepIdx] = intersect(allMatlabNamespaceNames, namespaceNames, 'stable');
jsonSpecs = jsonSpecs(keepIdx);

io.spec.writeEmbeddedSpecifications(output_file_id, jsonSpecs);
end

function resolveReferences(obj, fid, references)
while ~isempty(references)
resolved = false(size(references));
Expand Down Expand Up @@ -215,4 +253,19 @@ function resolveReferences(obj, fid, references)
searchProperties(pathToObjectMap, propValue, fullPath, typename, varargin{:});
end
end
end
end

function namespaceNames = getNamespacesOfTypes(nwbTypeNames)
% getNamespacesOfTypes - Get namespace names for a list of nwb types
arguments
nwbTypeNames (1,:) string
end

namespaceNames = repmat("", size(nwbTypeNames));
pattern = '[types.]+\.(\w+)\.';

for i = 1:numel(nwbTypeNames)
namespaceNames(i) = regexp(nwbTypeNames(i), pattern, 'tokens', 'once');
end
namespaceNames = unique(namespaceNames);
end
Loading