Skip to content

Commit 5492118

Browse files
authored
Merge pull request #495 from NeurodataWithoutBorders/494-check-for-multiple-constrained
494 check for multiple constrained
2 parents 16a5411 + 9382c12 commit 5492118

File tree

13 files changed

+420
-273
lines changed

13 files changed

+420
-273
lines changed

+file/+interface/HasProps.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
classdef HasProps < matlab.mixin.Heterogeneous
2+
methods (Abstract)
3+
props = getProps(obj);
4+
end
5+
end
6+

+file/Dataset.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
classdef Dataset
1+
classdef Dataset < file.interface.HasProps
22
properties
33
name;
44
doc;
@@ -108,6 +108,7 @@
108108
obj.linkable = ~isempty(obj.name) && hasNoAttributes;
109109
end
110110

111+
%% HasProps
111112
function props = getProps(obj)
112113
props = containers.Map;
113114

+file/Group.m

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
classdef Group
1+
classdef Group < file.interface.HasProps
22
properties
33
doc;
44
name;
@@ -139,8 +139,9 @@
139139
isempty(obj.attributes);
140140
end
141141

142-
function Prop_Map = getProps(obj)
143-
Prop_Map = containers.Map;
142+
%% HasProps
143+
function PropertyMap = getProps(obj)
144+
PropertyMap = containers.Map;
144145
%typed + constrained
145146
%should never happen
146147

@@ -161,27 +162,27 @@
161162
attr_names = strcat(SubData.name, '_', attr_names);
162163
Sub_Attribute_Map =...
163164
containers.Map(attr_names, num2cell(SubData.attributes));
164-
Prop_Map = [Prop_Map; Sub_Attribute_Map];
165+
PropertyMap = [PropertyMap; Sub_Attribute_Map];
165166
end
166-
Prop_Map(SubData.name) = SubData;
167+
PropertyMap(SubData.name) = SubData;
167168
else
168169
if isempty(SubData.name)
169-
Prop_Map(lower(SubData.type)) = SubData;
170+
PropertyMap(lower(SubData.type)) = SubData;
170171
else
171-
Prop_Map(SubData.name) = SubData;
172+
PropertyMap(SubData.name) = SubData;
172173
end
173174
end
174175
end
175176

176177
%attributes
177178
if ~isempty(obj.attributes)
178-
Prop_Map = [Prop_Map;...
179+
PropertyMap = [PropertyMap;...
179180
containers.Map({obj.attributes.name}, num2cell(obj.attributes))];
180181
end
181182

182183
%links
183184
if ~isempty(obj.links)
184-
Prop_Map = [Prop_Map;...
185+
PropertyMap = [PropertyMap;...
185186
containers.Map({obj.links.name}, num2cell(obj.links))];
186187
end
187188

@@ -200,49 +201,46 @@
200201
%if untyped, check if elided
201202
% if elided, add to prefix and check all subgroups, attributes and datasets.
202203
% otherwise, call getprops and assign to its name.
203-
Sub_Group = obj.subgroups(i);
204-
groupName = Sub_Group.name;
205-
groupType = Sub_Group.type;
204+
SubGroup = obj.subgroups(i);
205+
groupName = SubGroup.name;
206+
groupType = SubGroup.type;
206207
if ~isempty(groupType)
207208
if isempty(groupName)
208-
Prop_Map(lower(groupType)) = Sub_Group;
209+
PropertyMap(lower(groupType)) = SubGroup;
209210
else
210-
Prop_Map(groupName) = Sub_Group;
211+
PropertyMap(groupName) = SubGroup;
211212
end
212213
continue;
213214
end
214215

215-
if ~Sub_Group.elide
216-
Prop_Map(groupName) = Sub_Group;
216+
if ~SubGroup.elide
217+
PropertyMap(groupName) = SubGroup;
217218
continue;
218219
end
219-
220-
Descendant_Map = Sub_Group.getProps;
221-
descendant_names = keys(Descendant_Map);
222-
for iSubGroup = 1:length(descendant_names)
223-
descendantName = descendant_names{iSubGroup};
224-
Descendant = Descendant_Map(descendantName);
220+
221+
DescendantMap = SubGroup.getProps();
222+
descendantNames = keys(DescendantMap);
223+
for iSubGroup = 1:length(descendantNames)
224+
descendantName = descendantNames{iSubGroup};
225+
Descendant = DescendantMap(descendantName);
225226
% hoist constrained sets to the current
226227
% subname.
227228
isPossiblyConstrained =...
228229
isa(Descendant, 'file.Group')...
229230
|| isa(Descendant, 'file.Dataset');
230231
isConstrained = isPossiblyConstrained...
231-
&& strcmpi(descendantName, Descendant.type)...
232-
&& Descendant.isConstrainedSet;
232+
&& all(strcmpi(descendantName, {Descendant.type}))...
233+
&& all(Descendant.isConstrainedSet);
233234
if isConstrained
234-
propName = groupName;
235+
if isKey(PropertyMap, groupName)
236+
SetType = PropertyMap(groupName);
237+
else
238+
SetType = [];
239+
end
240+
PropertyMap(groupName) = [SetType, Descendant];
235241
else
236-
propName = [groupName '_' descendantName];
237-
end
238-
239-
if isKey(Prop_Map, propName) && ~isConstrained
240-
warning(['Generic group `%s` is currently unsupported '...
241-
'in MatNwb and is ignored.'], propName);
242-
continue;
242+
PropertyMap([groupName, '_', descendantName]) = Descendant;
243243
end
244-
245-
Prop_Map(propName) = Descendant_Map(descendantName);
246244
end
247245
end
248246
end

+file/fillClass.m

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,18 @@
1515
for i=1:length(allprops)
1616
pnm = allprops{i};
1717
prop = classprops(pnm);
18+
19+
isRequired = ischar(prop) || isa(prop, 'containers.Map') || isstruct(prop);
20+
iIsPropertyRequired = false;
21+
if isa(prop, 'file.interface.HasProps')
22+
iIsPropertyRequired = false(size(prop));
23+
for iProp = 1:length(prop)
24+
p = prop(iProp);
25+
iIsPropertyRequired(iProp) = p.required;
26+
end
27+
end
1828

19-
if ischar(prop) || isa(prop, 'containers.Map') || isstruct(prop) || prop.required
29+
if isRequired || all(iIsPropertyRequired)
2030
required = [required {pnm}];
2131
else
2232
optional = [optional {pnm}];

+file/fillConstructor.m

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,40 @@
6262
nm = names{i};
6363
prop = props(nm);
6464

65-
if isa(prop, 'file.Group') || isa(prop, 'file.Dataset')
66-
dynamicConstrained(i) = prop.isConstrainedSet && strcmpi(nm, prop.type);
67-
anon(i) = ~prop.isConstrainedSet && isempty(prop.name);
65+
if isa(prop, 'file.Attribute')
66+
isattr(i) = true;
67+
continue;
68+
end
69+
70+
if isa(prop, 'file.interface.HasProps')
71+
isDynamicConstrained = false(size(prop));
72+
isAnon = false(size(prop));
73+
hasType = false(size(prop));
74+
typeNames = cell(size(prop));
75+
for iProp = 1:length(prop)
76+
p = prop(iProp);
77+
isDynamicConstrained(iProp) = p.isConstrainedSet && strcmpi(nm, p.type);
78+
isAnon(iProp) = ~p.isConstrainedSet && isempty(p.name);
79+
hasType(iProp) = ~isempty(p.type);
80+
typeNames{iProp} = p.type;
81+
end
82+
dynamicConstrained(i) = all(isDynamicConstrained);
83+
anon(i) = all(isAnon);
6884

69-
if ~isempty(prop.type)
85+
if all(hasType)
7086
varnames{i} = nm;
87+
typeNameCell = cell(size(prop));
7188
try
72-
typenames{i} = namespace.getFullClassName(prop.type);
89+
for iProp = 1:length(prop)
90+
typeNameCell{iProp} = namespace.getFullClassName(prop(iProp).type);
91+
end
7392
catch ME
7493
if ~strcmp(ME.identifier, 'NWB:Scheme:Namespace:NotFound')
7594
rethrow(ME);
7695
end
7796
end
97+
typenames{i} = misc.cellPrettyPrint(typeNameCell);
7898
end
79-
elseif isa(prop, 'file.Attribute')
80-
isattr(i) = true;
8199
end
82100
end
83101

@@ -132,9 +150,14 @@
132150
defaults = cell(size(names));
133151
for i=1:length(names)
134152
prop = props(names{i});
135-
if (isa(prop, 'file.Group') &&...
136-
(prop.hasAnonData || prop.hasAnonGroups || prop.isConstrainedSet)) ||...
137-
(isa(prop, 'file.Dataset') && prop.isConstrainedSet)
153+
isPluralSet = isa(prop, 'file.interface.HasProps') && ~isscalar(prop);
154+
isGroupSet = ~isPluralSet ...
155+
&& isa(prop, 'file.Group') ...
156+
&& (prop.hasAnonData || prop.hasAnonGroups || prop.isConstrainedSet);
157+
isDataSet = ~isPluralSet ...
158+
&& isa(prop, 'file.Dataset')...
159+
&& prop.isConstrainedSet;
160+
if isPluralSet || isGroupSet || isDataSet
138161
defaults{i} = 'types.untyped.Set()';
139162
else
140163
defaults{i} = '[]';

+file/fillProps.m

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,30 @@
7171
error('Invalid reftype found whilst filling Constructor prop docs.');
7272
end
7373
typeStr = sprintf('%s Reference to %s', refTypeName, prop('target_type'));
74-
elseif isa(prop, 'file.Dataset') && isempty(prop.type)
75-
typeStr = getPropStr(prop.dtype);
76-
elseif isempty(prop.type)
77-
typeStr = 'types.untyped.Set';
74+
elseif isa(prop, 'file.interface.HasProps')
75+
typeStrCell = cell(size(prop));
76+
for iProp = 1:length(typeStrCell)
77+
anonProp = prop(iProp);
78+
if isa(anonProp, 'file.Dataset') && isempty(anonProp.type)
79+
typeStrCell{iProp} = getPropStr(anonProp.dtype);
80+
elseif isempty(anonProp.type)
81+
typeStrCell{iProp} = 'types.untyped.Set';
82+
else
83+
typeStrCell{iProp} = anonProp.type;
84+
end
85+
end
86+
typeStr = strjoin(typeStrCell, '|');
7887
else
7988
typeStr = prop.type;
8089
end
8190

82-
if isa(prop, 'file.Dataset') || isa(prop, 'file.Attribute') || isa(prop, 'file.Group')
91+
if isa(prop, 'file.interface.HasProps')
92+
propStrCell = cell(size(prop));
93+
for iProp = 1:length(prop)
94+
propStrCell{iProp} = prop(iProp).doc;
95+
end
96+
propStr = sprintf('(%s) %s', typeStr, strjoin(propStrCell, ' | '));
97+
elseif isa(prop, 'file.Attribute')
8398
propStr = sprintf('(%s) %s', typeStr, prop.doc);
8499
else
85100
propStr = typeStr;

0 commit comments

Comments
 (0)