Skip to content

Commit

Permalink
Started work on reads
Browse files Browse the repository at this point in the history
  • Loading branch information
Lancewiu committed Apr 18, 2018
1 parent bbcdd40 commit 89be61a
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 299 deletions.
2 changes: 1 addition & 1 deletion +file/Attribute.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
%defaults
obj.name = '';
obj.doc = '';
obj.required = true;
obj.required = false;
obj.value = [];
obj.readonly = false;
obj.dtype = [];
Expand Down
2 changes: 1 addition & 1 deletion +file/fillClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
'classdef ' name ' < ' depnm newline... %header, dependencies
'% ' name ' ' class.doc]; %name, docstr
propsDef = strjoin({...
file.fillProps(ro_props, 'READONLY', 'SetAccess=immutable')...%readonly properties
file.fillProps(ro_props, 'READONLY', 'SetAccess=private')...%readonly properties
file.fillProps(req_props, 'REQUIRED')... %required properties
file.fillProps(opt_props, 'OPTIONAL')... %optional properties
}, newline);
Expand Down
35 changes: 26 additions & 9 deletions +file/fillConstructor.m
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,48 @@
end

function bodystr = fillBody(pname, propwithvals, req_vars, opt_vars, props)
bodystr = ['obj = obj@' pname '(varargin{:});'];
all_vars = [req_vars opt_vars];

upstream = {}; %kwargs to be sent to parent
hardcoded = {}; %hardcoded defaults that should be instantiated now.
for i=1:length(propwithvals)
pnm = propwithvals{i};
prop = props.named(pnm);
[~, status] = str2num(prop.value);
if status
wrapped_assgn = prop.value;
if any(strcmp(all_vars, pnm)) %that is, it's noninherited
[~, status] = str2num(prop.value);
if status
wrapped_assgn = prop.value;
else
wrapped_assgn = ['''' prop.value ''''];
end

hardcoded = [hardcoded {['obj.' pnm ' = ' wrapped_assgn ';']}];
else
wrapped_assgn = ['''' prop.value ''''];
upstream = [upstream {pnm} {prop.value}];
end
bodystr = [bodystr newline 'obj.' pnm ' = ' wrapped_assgn ';'];
end
if isempty(upstream)
bodystr = '';
else
bodystr = ['varargin = [' util.cellPrettyPrint(upstream) ' varargin];' newline];
end
bodystr = [bodystr 'obj = obj@' pname '(varargin{:});'];

if ~isempty(hardcoded)
bodystr = [bodystr newline strjoin(hardcoded, newline)];
end
bodystr = strjoin({bodystr...
'p = inputParser;'...
'p.KeepUnmatched = true;'... %suppress subclass/parent props
'p.PartialMatching = false;'...
'p.StructExpand = false;'}, newline);
all_vars = [req_vars opt_vars];

for i=1:length(all_vars)
var = all_vars{i};
bodystr = [bodystr newline 'addParameter(p, ''' var ''', []);'];
end

req_vars_str = util.cellPrettyPrint(req_vars);
req_empty_vars = setdiff(req_vars, propwithvals); %check required values that don't have a set value
req_vars_str = util.cellPrettyPrint(req_empty_vars);
req_body = strjoin({...
'parse(p, varargin{:});'...
['required = ' req_vars_str ';']...
Expand Down
2 changes: 1 addition & 1 deletion +file/fillSetters.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
fsstr{i} = strjoin({...
['function obj = set.' nm '(obj, val)']...
[' obj.validate_' nm '(val);']...
' obj = val;'...
[' obj.' nm ' = val;']...
'end'}, newline);
end
fsstr = strjoin(fsstr, newline);
Expand Down
10 changes: 10 additions & 0 deletions +io/map2kwargs.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function kwargs = map2kwargs(map)
%containers.Map -> keyword args for types
kwargs = cell(1, map.Count);
mapkeys = keys(map);
for i=1:length(mapkeys)
k = mapkeys{i};
kwargs{(i*2)-1} = k;
kwargs{i*2} = map(k);
end
end
22 changes: 12 additions & 10 deletions +io/parseAttributes.m
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
function [args, typename] = parseAttributes(attr_info)
function [args, typename] = parseAttributes(alist)
%typename is the type of name if it exists. Empty string otherwise
%args is a containers.Map of all valid attributes
args = containers.Map;
typename = '';
type = struct('namespace', '', 'name', '');
for i=1:length(attr_info)
ai = attr_info(i);
if strcmp(ai.Name, 'neurodata_type')
type.name = ai.Value{1};
elseif strcmp(ai.Name, 'namespace')
type.namespace = ai.Value{1};
elseif strcmp(ai.Datatype, 'H5T_STRING')
args(ai.Name) = ai.Value{1};
for i=1:length(alist)
attr = alist(i);
if strcmp(attr.Name, 'neurodata_type')
type.name = attr.Value{1};
elseif strcmp(attr.Name, 'namespace')
type.namespace = attr.Value{1};
elseif strcmp(attr.Datatype, 'H5T_STRING')
args(attr.Name) = attr.Value{1};
elseif iscellstr(attr.Value)
args(attr.Name) = attr.Value{1};
else
args(ai.Name) = ai.Value;
args(attr.Name) = attr.Value;
end
end
if ~isempty(type.namespace) && ~isempty(type.name)
Expand Down
67 changes: 67 additions & 0 deletions +io/parseDataset.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function [parsed, refs] = parseDataset(filename, info, fullpath)
%typed and untyped being container maps containing type and untyped datasets
% the maps store information regarding information and stored data
% NOTE, dataset name is in path format so we need to parse that out.
refs = containers.Map;
name = info.Name;

%check if typed and parse attributes
[attrargs, typename] = io.parseAttributes(info.Attributes);

if isempty(typename) %a Group's properties
parsed = containers.Map;
afields = keys(attrargs);
for j=1:length(afields)
attr = afields{j};
parsed([name '_' attr]) = attrargs(attr);
end
data = h5read(filename, fullpath);
if iscellstr(data)
data = data{1};
elseif iscell(data)
keyboard;
end
parsed(name) = data;
return;
end
% given name, either a:
% direct reference (ElectrodeTableRegion)
% compound data w/ reference (ElectrodeTable)
% All other cases do not exist in this current schema.
props = attrargs;
props('associated_nwbfile') = filename;

fid = H5F.open(filename);
did = H5D.open(fid, fullpath);
data = H5D.read(did); %this way, references are not automatically resolved

datatype = info.Datatype;
if strcmp(datatype.Class, 'H5T_REFERENCE')
reftype = datatype.Type;
switch reftype
case 'H5R_OBJECT'
%TODO when included in schema
case 'H5R_DATASET_REGION'
sid = H5R.get_region(did, reftype, data);
[start, finish] = H5S.get_select_bounds(sid);
props('target') = H5R.get_name(did, reftype, data);
props('region') = [start+1 finish];
H5S.close(sid);
end
elseif strcmp(datatype.Class, 'H5T_COMPOUND')
t = table;
compound = datatype.Type.Member;
isref = logical(size(compound));
for j=1:length(compound)
comp = compound(j);
if strcmp(comp.Datatype.Class, 'H5T_REFERENCE')
isref(j) = true;
end
end
end
kwargs = io.map2kwargs(props);
parsed = eval([typename '(kwargs{:})']);

H5D.close(did);
H5F.close(fid);
end
63 changes: 0 additions & 63 deletions +io/parseDatasets.m

This file was deleted.

46 changes: 46 additions & 0 deletions +io/parseGroup.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function [parsed, links, refs] = parseGroup(filename, info)
% NOTE, group name is in path format so we need to parse that out.
% parsed is either a containers.Map containing properties mapped to values OR a
% typed value
links = [];
refs = containers.Map;
[~, root] = io.pathParts(info.Name);
[props, typename] = io.parseAttributes(info.Attributes);

%parse datasets
for i=1:length(info.Datasets)
ds_info = info.Datasets(i);
fp = [info.Name '/' ds_info.Name];
[ds, dsrefs] = io.parseDataset(filename, ds_info, fp);
props = [props; ds];
refs = [refs; dsrefs];
end

%parse links if present
for i=1:length(info.Links)
links = [links io.parseLink(info.Links)];
end

%parse subgroups
for i=1:length(info.Groups)
g_info = info.Groups(i);
[~, gname] = io.pathParts(g_info.Name);
[subg, glinks, grefs] = io.parseGroup(filename, g_info);
props(gname) = subg;
links = [links glinks];
refs = [refs; grefs];
end

if isempty(typename)
parsed = containers.Map;
keyboard;
else
%construct as kwargs and instantiate object

if isempty(root)
%we are root
parsed = types.core.NWBFile;
return;
end
end
end
14 changes: 0 additions & 14 deletions +io/parseGroups.m

This file was deleted.

4 changes: 4 additions & 0 deletions +io/parseLink.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
function link = parseLink(info)
% just return a link
link = [];
end
38 changes: 0 additions & 38 deletions +types/+untyped/MetaClass.m
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
classdef MetaClass < handle
properties(Access=protected, Hidden=true)
associated_nwbfile; %determines if this class is actually tied to a file or not.
dynamic_properties; % propname -> prop
dynamic_prop_constraints % propname -> class name
dynamic_constraints; % { classname constraints }
end

methods
function obj = MetaClass(varargin)
obj.dynamic_properties = containers.Map;
obj.dynamic_prop_constraints = containers.Map;
obj.dynamic_constraints = {};
p = inputParser;
p.KeepUnmatched = true;
p.PartialMatching = false;
p.StructExpand = false;
addParameter(p, 'associated_nwbfile', []);
parse(p, varargin);
obj.associated_nwbfile = p.Results.associated_nwbfile;
end

function res = addDynamicProperty(obj, name, val)
if any(strcmp(properties(obj), name))
error('Cannot add a dynamic property with the same name as an object property.');
end

validate_res = obj.validateDynamicProperty(val);
res = ~isempty(validate_res);

if res
obj.dynamic_properties(name) = val;
obj.dynamic_prop_constraints(name) = validate_res;
end
end

function res = getDynamicProperty(obj, name)
res = [];
if isKey(obj.dynamic_properties, name)
res = obj.dynamic_properties(name);
end
end

function export(~, loc_id)
Expand Down
9 changes: 8 additions & 1 deletion +util/cellPrettyPrint.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
function s = cellPrettyPrint(val)
s = '';
for i=1:length(val)
s = [s ' ''' val{i} ''''];
v = val{i};
[~, status] = str2num(v);
if status
wrapped_v = v;
else
wrapped_v = ['''' v ''''];
end
s = [s ' ' wrapped_v];
end
s = ['{ ' strtrim(s) ' }'];
end
Loading

0 comments on commit 89be61a

Please sign in to comment.