From d9abb44494b287f0de978dc8b79fe0711f5eef55 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:09:14 +0100 Subject: [PATCH 01/10] Move code files to code folder --- +bot/+internal/test.m | 336 ------------------ .gitignore | 3 + .../+item/+internal/+abstract/Item.m | 0 .../+bot}/+behavior/+item/EphysSession.m | 0 .../+bot}/+behavior/+item/Experiment.m | 0 .../+bot}/+behavior/+item/OphysSession.m | 0 .../FileDownloadProgressMonitor.m | 0 .../+fex/+filedownload/downloadFile.m | 0 .../+external/+fex/+filedownload/license.txt | 0 .../+bot}/+external/+matnwb/+io/getMatType.m | 0 .../+bot}/+internal/+abstract/FileResource.m | 0 .../+internal/+abstract/LocalFileCache.m | 0 .../+internal/+behavior/+cache/CloudCacher.m | 0 .../+behavior/+mixin/HasLinkedFile.m | 0 .../+bot}/+internal/+behavior/Cache.m | 0 .../+bot}/+internal/+behavior/LinkedFile.m | 0 .../+fileresource/+abstract/S3Bucket.m | 0 .../+fileresource/+mixin/HasFileResource.m | 0 .../+visualbehavior/VBEphysS3Bucket.m | 0 .../+visualbehavior/VBOphysS3Bucket.m | 0 .../+visualcoding/VCEphysS3Bucket.m | 0 .../+visualcoding/VCOphysS3Bucket.m | 0 .../+bot}/+internal/+fileresource/WebApi.m | 0 .../+utility/convertStringArrayIdToInteger.m | 0 .../+utility/itemTableTypeConversionMap.m | 0 .../+utility/itemTableVariableRenameMap.m | 0 .../+metadata/VisualBehaviorEphysManifest.m | 0 .../+metadata/VisualBehaviorOphysManifest.m | 0 .../+nwb/+file/+vb/BehaviorNWBFile.m | 0 .../+internal/+nwb/+file/+vb/OphysNWBFile.m | 0 .../+internal/+nwb/+reader/+vb/Contents.m | 0 .../+reader/+vb/read_cell_specimen_table.m | 0 .../+reader/+vb/read_eyetracking_timetable.m | 0 .../+nwb/+reader/+vb/read_lick_timetable.m | 0 .../+nwb/+reader/+vb/read_rewards_timetable.m | 0 .../+nwb/+reader/+vb/read_trials_timetable.m | 0 .../+internal/+nwb/+reader/readDynamicTable.m | 0 .../+nwb/+reader/readGeneralMetadata.m | 0 .../+nwb/+reader/readOphysMetadata.m | 0 .../+internal/+nwb/+reader/readRigMetadata.m | 0 .../+nwb/+reader/readSubjectMetadata.m | 0 .../+internal/+nwb/+reader/readTaskMetadata.m | 0 .../+bot}/+internal/+nwb/LinkedNWBFile.m | 0 .../+nwb/deindex_table_from_datasets.m | 0 {+bot => code/+bot}/+internal/+nwb/has_path.m | 0 .../+bot}/+internal/+nwb/nwb_ephys.m | 0 .../+internal/+nwb/readAttributesToStruct.m | 0 .../+internal/+nwb/readDatasetsToStruct.m | 0 .../+internal/+nwb/struct_from_attributes.m | 0 .../+internal/+nwb/table_from_datasets.m | 0 .../+internal/+nwb/xarray_from_dataset.m | 0 .../+internal/+util/castTableVariables.m | 0 .../+bot}/+internal/+util/getLocalFileSize.m | 0 .../+bot}/+internal/+util/getToolboxVersion.m | 0 .../+bot}/+internal/+util/getWebFileSize.m | 0 .../+bot}/+internal/+util/isVerLessThan.m | 0 .../+bot}/+internal/+util/resolveDataset.m | 0 .../+bot}/+internal/+util/structcat.m | 0 .../+bot}/+internal/+util/structmerge.m | 0 .../+bot}/+internal/+util/toolboxdir.m | 0 {+bot => code/+bot}/+internal/+util/uriJoin.m | 0 .../+internal/BinarySearchSortedList_MATLAB.m | 0 .../BinarySearchSortedList_double_mex.c | 0 .../BinarySearchSortedList_int32_mex.c | 0 .../+bot}/+internal/BrainObservatoryAPI.m | 0 {+bot => code/+bot}/+internal/Cache.m | 0 {+bot => code/+bot}/+internal/CloudCacher.m | 0 {+bot => code/+bot}/+internal/GetUniqueUID.m | 0 {+bot => code/+bot}/+internal/ObjectCacher.m | 0 .../+bot}/+internal/OnDemandProperty.m | 0 {+bot => code/+bot}/+internal/Preferences.m | 0 {+bot => code/+bot}/+internal/README.mlx | Bin {+bot => code/+bot}/+internal/SimpleMap.m | 0 .../+bot}/+internal/fetch_ABO_query.m | 0 .../+bot}/+internal/fetch_mex_handles.m | 0 {+bot => code/+bot}/+internal/merge_tables.m | 0 .../+bot}/+internal/prepareForDemo.m | 0 {+bot => code/+bot}/+internal/reset.m | 0 .../+bot}/+item/+concrete/EphysSession.m | 0 .../+bot}/+item/+concrete/OphysSession.m | 0 .../+bot}/+item/+internal/+abstract/Item.m | 0 .../+internal/+abstract/LinkedFilesItem.m | 0 .../+bot}/+item/+internal/+enum/Dataset.m | 0 .../+bot}/+item/+internal/+enum/DatasetType.m | 0 .../+bot}/+item/+internal/+enum/ItemType.m | 0 .../+item/+internal/+enum/OnDemandState.m | 0 .../+bot}/+item/+internal/+mixin/Metrics.m | 0 .../+item/+internal/+mixin/OnDemandProps.m | 0 .../+bot}/+item/+internal/EphysManifest.m | 0 .../+bot}/+item/+internal/Manifest.m | 0 .../+bot}/+item/+internal/OphysManifest.m | 0 {+bot => code/+bot}/+item/Cell.m | 0 {+bot => code/+bot}/+item/Channel.m | 0 {+bot => code/+bot}/+item/Experiment.m | 0 {+bot => code/+bot}/+item/Probe.m | 0 {+bot => code/+bot}/+item/Session.m | 0 {+bot => code/+bot}/+item/Unit.m | 0 .../+bot}/+util/StimulusAlignedResp.m | 0 .../+bot}/+util/autoConfigureByEnvironment.m | 0 .../+bot}/+util/convertEphysToRaster.m | 0 ...rt_fluorescence_trace_into_raster_format.m | 0 {+bot => code/+bot}/+util/getPreferences.m | 0 .../+bot}/+util/ophyssessionfilter.m | 0 {+bot => code/+bot}/+util/showReferences.m | 0 {+bot => code/+bot}/README.m | 0 {+bot => code/+bot}/getCells.m | 0 {+bot => code/+bot}/getChannels.m | 0 {+bot => code/+bot}/getExperiments.m | 0 {+bot => code/+bot}/getProbes.m | 0 {+bot => code/+bot}/getSessions.m | 0 {+bot => code/+bot}/getUnits.m | 0 {+bot => code/+bot}/listCells.m | 0 {+bot => code/+bot}/listChannels.m | 0 {+bot => code/+bot}/listExperiments.m | 0 {+bot => code/+bot}/listProbes.m | 0 {+bot => code/+bot}/listSessions.m | 0 {+bot => code/+bot}/listUnits.m | 0 .gitattributes => code/.gitattributes | 0 Contents.m => code/Contents.m | 8 +- .../VisualBehavior_OphysQuickstart.mlx | Bin .../VisualCoding_BehaviorTutorial.mlx | Bin .../VisualCoding_DecodingTutorial.mlx | Bin .../examples}/VisualCoding_EphysDemo.mlx | Bin .../VisualCoding_EphysQuickstart.mlx | Bin .../examples}/VisualCoding_EphysTutorial.mlx | Bin .../examples}/VisualCoding_OphysDemo.mlx | Bin .../VisualCoding_OphysQuickstart.mlx | Bin .../examples}/VisualCoding_OphysTutorial.mlx | Bin 128 files changed, 7 insertions(+), 340 deletions(-) delete mode 100644 +bot/+internal/test.m rename {+bot => code/+bot}/+behavior/+item/+internal/+abstract/Item.m (100%) rename {+bot => code/+bot}/+behavior/+item/EphysSession.m (100%) rename {+bot => code/+bot}/+behavior/+item/Experiment.m (100%) rename {+bot => code/+bot}/+behavior/+item/OphysSession.m (100%) rename {+bot => code/+bot}/+external/+fex/+filedownload/FileDownloadProgressMonitor.m (100%) rename {+bot => code/+bot}/+external/+fex/+filedownload/downloadFile.m (100%) rename {+bot => code/+bot}/+external/+fex/+filedownload/license.txt (100%) rename {+bot => code/+bot}/+external/+matnwb/+io/getMatType.m (100%) rename {+bot => code/+bot}/+internal/+abstract/FileResource.m (100%) rename {+bot => code/+bot}/+internal/+abstract/LocalFileCache.m (100%) rename {+bot => code/+bot}/+internal/+behavior/+cache/CloudCacher.m (100%) rename {+bot => code/+bot}/+internal/+behavior/+mixin/HasLinkedFile.m (100%) rename {+bot => code/+bot}/+internal/+behavior/Cache.m (100%) rename {+bot => code/+bot}/+internal/+behavior/LinkedFile.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+abstract/S3Bucket.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+mixin/HasFileResource.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+visualbehavior/VBEphysS3Bucket.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+visualbehavior/VBOphysS3Bucket.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+visualcoding/VCEphysS3Bucket.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/+visualcoding/VCOphysS3Bucket.m (100%) rename {+bot => code/+bot}/+internal/+fileresource/WebApi.m (100%) rename {+bot => code/+bot}/+internal/+metadata/+utility/convertStringArrayIdToInteger.m (100%) rename {+bot => code/+bot}/+internal/+metadata/+utility/itemTableTypeConversionMap.m (100%) rename {+bot => code/+bot}/+internal/+metadata/+utility/itemTableVariableRenameMap.m (100%) rename {+bot => code/+bot}/+internal/+metadata/VisualBehaviorEphysManifest.m (100%) rename {+bot => code/+bot}/+internal/+metadata/VisualBehaviorOphysManifest.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+file/+vb/BehaviorNWBFile.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+file/+vb/OphysNWBFile.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/Contents.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/read_cell_specimen_table.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/read_eyetracking_timetable.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/read_lick_timetable.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/read_rewards_timetable.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/+vb/read_trials_timetable.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readDynamicTable.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readGeneralMetadata.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readOphysMetadata.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readRigMetadata.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readSubjectMetadata.m (100%) rename {+bot => code/+bot}/+internal/+nwb/+reader/readTaskMetadata.m (100%) rename {+bot => code/+bot}/+internal/+nwb/LinkedNWBFile.m (100%) rename {+bot => code/+bot}/+internal/+nwb/deindex_table_from_datasets.m (100%) rename {+bot => code/+bot}/+internal/+nwb/has_path.m (100%) rename {+bot => code/+bot}/+internal/+nwb/nwb_ephys.m (100%) rename {+bot => code/+bot}/+internal/+nwb/readAttributesToStruct.m (100%) rename {+bot => code/+bot}/+internal/+nwb/readDatasetsToStruct.m (100%) rename {+bot => code/+bot}/+internal/+nwb/struct_from_attributes.m (100%) rename {+bot => code/+bot}/+internal/+nwb/table_from_datasets.m (100%) rename {+bot => code/+bot}/+internal/+nwb/xarray_from_dataset.m (100%) rename {+bot => code/+bot}/+internal/+util/castTableVariables.m (100%) rename {+bot => code/+bot}/+internal/+util/getLocalFileSize.m (100%) rename {+bot => code/+bot}/+internal/+util/getToolboxVersion.m (100%) rename {+bot => code/+bot}/+internal/+util/getWebFileSize.m (100%) rename {+bot => code/+bot}/+internal/+util/isVerLessThan.m (100%) rename {+bot => code/+bot}/+internal/+util/resolveDataset.m (100%) rename {+bot => code/+bot}/+internal/+util/structcat.m (100%) rename {+bot => code/+bot}/+internal/+util/structmerge.m (100%) rename {+bot => code/+bot}/+internal/+util/toolboxdir.m (100%) rename {+bot => code/+bot}/+internal/+util/uriJoin.m (100%) rename {+bot => code/+bot}/+internal/BinarySearchSortedList_MATLAB.m (100%) rename {+bot => code/+bot}/+internal/BinarySearchSortedList_double_mex.c (100%) rename {+bot => code/+bot}/+internal/BinarySearchSortedList_int32_mex.c (100%) rename {+bot => code/+bot}/+internal/BrainObservatoryAPI.m (100%) rename {+bot => code/+bot}/+internal/Cache.m (100%) rename {+bot => code/+bot}/+internal/CloudCacher.m (100%) rename {+bot => code/+bot}/+internal/GetUniqueUID.m (100%) rename {+bot => code/+bot}/+internal/ObjectCacher.m (100%) rename {+bot => code/+bot}/+internal/OnDemandProperty.m (100%) rename {+bot => code/+bot}/+internal/Preferences.m (100%) rename {+bot => code/+bot}/+internal/README.mlx (100%) rename {+bot => code/+bot}/+internal/SimpleMap.m (100%) rename {+bot => code/+bot}/+internal/fetch_ABO_query.m (100%) rename {+bot => code/+bot}/+internal/fetch_mex_handles.m (100%) rename {+bot => code/+bot}/+internal/merge_tables.m (100%) rename {+bot => code/+bot}/+internal/prepareForDemo.m (100%) rename {+bot => code/+bot}/+internal/reset.m (100%) rename {+bot => code/+bot}/+item/+concrete/EphysSession.m (100%) rename {+bot => code/+bot}/+item/+concrete/OphysSession.m (100%) rename {+bot => code/+bot}/+item/+internal/+abstract/Item.m (100%) rename {+bot => code/+bot}/+item/+internal/+abstract/LinkedFilesItem.m (100%) rename {+bot => code/+bot}/+item/+internal/+enum/Dataset.m (100%) rename {+bot => code/+bot}/+item/+internal/+enum/DatasetType.m (100%) rename {+bot => code/+bot}/+item/+internal/+enum/ItemType.m (100%) rename {+bot => code/+bot}/+item/+internal/+enum/OnDemandState.m (100%) rename {+bot => code/+bot}/+item/+internal/+mixin/Metrics.m (100%) rename {+bot => code/+bot}/+item/+internal/+mixin/OnDemandProps.m (100%) rename {+bot => code/+bot}/+item/+internal/EphysManifest.m (100%) rename {+bot => code/+bot}/+item/+internal/Manifest.m (100%) rename {+bot => code/+bot}/+item/+internal/OphysManifest.m (100%) rename {+bot => code/+bot}/+item/Cell.m (100%) rename {+bot => code/+bot}/+item/Channel.m (100%) rename {+bot => code/+bot}/+item/Experiment.m (100%) rename {+bot => code/+bot}/+item/Probe.m (100%) rename {+bot => code/+bot}/+item/Session.m (100%) rename {+bot => code/+bot}/+item/Unit.m (100%) rename {+bot => code/+bot}/+util/StimulusAlignedResp.m (100%) rename {+bot => code/+bot}/+util/autoConfigureByEnvironment.m (100%) rename {+bot => code/+bot}/+util/convertEphysToRaster.m (100%) rename {+bot => code/+bot}/+util/convert_fluorescence_trace_into_raster_format.m (100%) rename {+bot => code/+bot}/+util/getPreferences.m (100%) rename {+bot => code/+bot}/+util/ophyssessionfilter.m (100%) rename {+bot => code/+bot}/+util/showReferences.m (100%) rename {+bot => code/+bot}/README.m (100%) rename {+bot => code/+bot}/getCells.m (100%) rename {+bot => code/+bot}/getChannels.m (100%) rename {+bot => code/+bot}/getExperiments.m (100%) rename {+bot => code/+bot}/getProbes.m (100%) rename {+bot => code/+bot}/getSessions.m (100%) rename {+bot => code/+bot}/getUnits.m (100%) rename {+bot => code/+bot}/listCells.m (100%) rename {+bot => code/+bot}/listChannels.m (100%) rename {+bot => code/+bot}/listExperiments.m (100%) rename {+bot => code/+bot}/listProbes.m (100%) rename {+bot => code/+bot}/listSessions.m (100%) rename {+bot => code/+bot}/listUnits.m (100%) rename .gitattributes => code/.gitattributes (100%) rename Contents.m => code/Contents.m (91%) rename {examples => code/examples}/VisualBehavior_OphysQuickstart.mlx (100%) rename {examples => code/examples}/VisualCoding_BehaviorTutorial.mlx (100%) rename {examples => code/examples}/VisualCoding_DecodingTutorial.mlx (100%) rename {examples => code/examples}/VisualCoding_EphysDemo.mlx (100%) rename {examples => code/examples}/VisualCoding_EphysQuickstart.mlx (100%) rename {examples => code/examples}/VisualCoding_EphysTutorial.mlx (100%) rename {examples => code/examples}/VisualCoding_OphysDemo.mlx (100%) rename {examples => code/examples}/VisualCoding_OphysQuickstart.mlx (100%) rename {examples => code/examples}/VisualCoding_OphysTutorial.mlx (100%) diff --git a/+bot/+internal/test.m b/+bot/+internal/test.m deleted file mode 100644 index 2076b9a3..00000000 --- a/+bot/+internal/test.m +++ /dev/null @@ -1,336 +0,0 @@ -%% Test class for BOT -classdef test < matlab.unittest.TestCase - - % Todo: - % [ ] set up test cache... - % [ ] test live scripts - - %% Test methods block - methods (Test) - function testCreateCache(testCase) %#ok<*MANU> - %% Test creating a BOT cache - boc = bot.internal.Cache.instance(); %#ok<*NASGU> - end - - function testOphysTables(testCase) - %% Test retrieving all OPhys manifest tables - bom = bot.item.internal.Manifest.instance('ophys'); - bom = bot.item.internal.OphysManifest.instance(); - bom.ophys_sessions; % Table of all OPhys experimental sessions - bom.ophys_experiments; % Table of all OPhys experimental containers - bom.ophys_cells; % Table of all OPhys cells - end - - function testEphysTables(testCase) - %% Test retrieving EPhys manifest tables - bom = bot.item.internal.Manifest.instance('ephys'); - bom = bot.item.internal.EphysManifest.instance(); - bom.ephys_sessions; % Table of all EPhys experimental sessions - bom.ephys_channels; % Table of all EPhys channels - bom.ephys_probes; % Table of all EPhys probes - bom.ephys_units; % Table of all EPhys units - end - - function testObtainSessionObject(testCase) - %% Test creation of an OPhys session object - sess = bot.listSessions('VisualCoding', 'ophys'); - - % - Get session IDs - vIDs = sess.id; - - % - Create some bot.item.Session objects - bot.getSessions(vIDs(1)); - bot.getSessions(vIDs(1:3)); - bot.getSessions(sess(1, :)); - bot.getSessions(sess(1:3, :)); - - % - Fetch all sessions from one experiment - exps = bot.listExperiments(); - s = bot.getSessions(sess(sess.experiment_container_id == exps.id(1), :)); - end - - function testSessionDataAccess(testCase) - %% Test data access methods of the bot.item.Session class for OPhys data - % - Create a bot.item.Session object - s = bot.getSessions(496934409); - - % - Test summary methods - s.nwb_metadata; - s.session_type; - s.roi_ids; - s.stimulus_list; - - % - Test data access methods - s.fluorescence_timestamps; - s.fluorescence_traces; - s.fluorescence_traces_demixed; - s.fluorescence_traces_dff; - s.corrected_fluorescence_traces; - s.max_projection; - s.motion_correction; - s.neuropil_r; - s.neuropil_traces; - s.roi_mask; - s.roi_mask_array; - s.running_speed; - s.pupil_location; - s.pupil_size; - end - - function testStimulusExtraction(testCase) - %% Test OPhys session stimulus extraction methods - % - Create a bot.session object - s = bot.getSessions(528402271); - - % - Get a vector of fluorescence frame IDs - vnFrameIDs = 1:numel(s.fluorescence_timestamps); - - % - Obtain per-frame stimulus table - s.getStimulusByFrame(vnFrameIDs); - - % - Obtain stimulus summary table - s.stimulus_epoch_table; - - % - Get list of stimuli - cStimuli = s.stimulus_list; - - % - Get a stimulus table for each stimulus - for cThisStim = cStimuli - s.getStimulusTable(cThisStim{1}); - end - - % - Get a natural movie stimulus template - s.getStimulusTemplate('natural_movie_one'); - s.getStimulusTable('natural_movie_one'); - - % - Get a spontantaneous activity stimulus table - s.spontaneous_activity_stimulus_table; - - % - Get an OPhys session with sparse noise - s = bot.getSessions(566752133); - - % - Get the sparse noise stimulus template - s.getStimulusTemplate('locally_sparse_noise_4deg'); - end - - function testOPhysExperiment(testCase) - %% Test obtaining OPhys experiment object - exp_table = bot.listExperiments(); - exp = bot.getExperiments(exp_table.id(1)); - exp = bot.getExperiments(exp_table(1, :)); - exps = bot.getExperiments(exp_table.id(1:3)); - exps = bot.getExperiments(exp_table(1:3, :)); - end - - function testOPhysCell(testCase) - %% Test obtaining OPhys cell object - cell_table = bot.listCells('VisualCoding', true); - cell_table = bot.listCells('VisualCoding', false); - cell = bot.getCells(cell_table.id(1)); - cell = bot.getCells(cell_table(1, :)); - cells = bot.getCells(cell_table(1:3, :)); - cells = bot.getCells(cell_table.id(1:3)); - - assert(~isempty(fieldnames(cells(1).metrics)), '`metrics` property structure was not set properly') - end - - function testEPhysManifest(testCase) - %% Test obtaining EPhys objects - % - Get the EPhys manifest - bom = bot.item.internal.EphysManifest.instance(); - bom = bot.item.internal.Manifest.instance('ephys'); - end - - function test_ophys_cells(testCase) - %% Tect obtaining OPhys cells - cells = bot.listCells(); - c = bot.getCells(cells(1, :)); - c = bot.getCells(cells.id(1)); - c = bot.getCells(cells(1:3, :)); - end - - function test_ephys_sessions(testCase) - %% Test obtaining EPhys objects - % - Get the EPhys manifest - bom = bot.item.internal.Manifest.instance('ephys'); - - % - Get the EPhys sessionts - sessions = bot.listSessions('VisualCoding', 'ephys'); - - % - Get a session - s = bot.getSessions(sessions{1, 'id'}); - s = bot.getSessions(sessions(1, :)); - s = bot.getSessions(sessions{1:3, 'id'}); - s = bot.getSessions(sessions(1:3, :)); - end - - function test_ephys_probes(testCase) - %% Test obtaining EPhys objects - % - Get the EPhys manifest - bom = bot.item.internal.Manifest.instance('ephys'); - - % - Get the probes table - probes = bot.listProbes(); - - % - Get a probe, by ID and by table - p = bot.getProbes(probes{1, 'id'}); - p = bot.getProbes(probes(1, :)); - p = bot.getProbes(probes{1:3, 'id'}); - p = bot.getProbes(probes(1:3, :)); - end - - function test_ephys_channels(testCase) - %% Test obtaining EPhys objects - % - Get the EPhys manifest - bom = bot.item.internal.Manifest.instance('ephys'); - - % - Get the channels table - channels = bot.listChannels(); - - % - Get channels, by ID and by table - c = bot.getChannels(channels{1, 'id'}); - c = bot.getChannels(channels(1, :)); - c = bot.getChannels(channels{1:3, 'id'}); - c = bot.getChannels(channels(1:3, :)); - end - - function test_ephys_units(testCase) - %% Test obtaining EPhys units objects - % - Get the EPhys manifest - bom = bot.item.internal.Manifest.instance('ephys'); - - % - Get the units table - units = bot.listUnits('VisualCoding', true); - units = bot.listUnits('VisualCoding', false); - - % - Get units, by ID and by table - u = bot.getUnits(units{1, 'id'}); - u = bot.getUnits(units(1, :)); - u = bot.getUnits(units{1:3, 'id'}); - u = bot.getUnits(units(1:3, :)); - - assert(~isempty(fieldnames(u(1).metrics)), '`metrics` property structure was not set properly') - end - - function testLFPCSDExtraction(testCase) - %% Test LFP and CSD extraction - % - Get the EPhys manifest - bom = bot.item.internal.Manifest.instance('ephys'); - - % - Get a probe - p = bot.getProbes(bom.ephys_probes{1, 'id'}); - - % - Access LFP data - p.lfpData; - - % - Access CSD data - p.csdData; - end - - function test_ephys_lazy_attributes(testCase) - %% Test reading lazy attributes - bom = bot.item.internal.Manifest.instance('ephys'); - s = bot.getSessions(bom.ephys_sessions{1, 'id'}); - - s.mean_waveforms; - s.optogenetic_stimulation_epochs; - s.inter_presentation_intervals; - s.running_speed; - s.mean_waveforms; - s.stimulus_presentations; - s.stimulus_conditions; - s.session_start_time; - s.spike_amplitudes; - s.invalid_times; - - % s.num_stimulus_presentations; % Not currently implemented, since it requires access to full stimulus table - s.stimulus_names; - s.structure_acronyms; - s.structurewise_unit_counts; - - s.stimulus_templates; - - try - s.optogenetic_stimulation_epochs; - catch - warning('No optogenetic stimulation data was present for this session.'); - end - end - - function test_ephys_session_methods(testCase) - %% Test session data access methods - bom = bot.item.internal.Manifest.instance('ephys'); - s = bot.getSessions(bom.ephys_sessions{1, 'id'}); - - sess = bot.listSessions('VisualCoding', 'ephys'); - s = bot.getSessions(sess(1, :)); - - s.fetch_stimulus_table(); - s.getStimulusEpochsByDuration(); - uid = s.units{1, 'id'}; - s.getPresentationwiseSpikeCounts([0 1], 1, uid); - s.getPresentationwiseSpikeTimes(0, uid); - s.getConditionwiseSpikeStatistics(0, uid); - s.getConditionsByStimulusName("spontaneous"); - end - - function test_factory_functions(testCase) - %% - Test manifest fetch factory functions - exps = bot.listExperiments(); - sess_ephys = bot.listSessions('VisualCoding', 'ephys'); - sess_ophys = bot.listSessions('VisualCoding', 'ophys'); - units = bot.listUnits(); - units = bot.listUnits('VisualCoding', true); - probes = bot.listProbes(); - channels = bot.listChannels(); - cells = bot.listCells(); - cells = bot.listCells('VisualCoding', true); - - % - Test "get object" factory functions - bot.getSessions(sess_ephys{1, 'id'}); - bot.getSessions(sess_ophys{1, 'id'}); - bot.getExperiments(exps{1, 'id'}); - bot.getUnits(units{1, 'id'}); - bot.getProbes(probes{1, 'id'}); - bot.getChannels(channels{1, 'id'}); - bot.getCells(cells{1, 'id'}); - end - - function testFactoryFunctionsVisualBehavior(testCase) - sess_ephys = bot.listSessions('VisualBehavior', 'ephys'); - sess_ophys = bot.listSessions('VisualBehavior', 'ophys'); - - exps = bot.listExperiments('VisualBehavior'); - probes = bot.listProbes('VisualBehavior'); - channels = bot.listChannels('VisualBehavior'); - units = bot.listUnits('VisualBehavior', true); - cells = bot.listCells('VisualBehavior', true); - - % - Test "get object" factory functions - bot.getSessions(sess_ephys{1, 'id'}); - bot.getSessions(sess_ophys{1, 'id'}); - bot.getExperiments(exps{1, 'id'}); - bot.getUnits(units{1, 'id'}); - bot.getProbes(probes{1, 'id'}); - bot.getChannels(channels{1, 'id'}); - bot.getCells(cells{1, 'id'}); - end - - function testFactoryBehaviorOnlySessions(testCase) - vbEphysManifest = bot.internal.metadata.VisualBehaviorEphysManifest.instance(); - vbOphysManifest = bot.internal.metadata.VisualBehaviorOphysManifest.instance(); - - ephysSessionId = vbEphysManifest.BehaviorSessions.id(1); - ophysSessionId = vbOphysManifest.BehaviorSessions.id(1); - - bot.getSessions(ephysSessionId); - bot.getSessions(ophysSessionId); - end - - function testOphysQuickStart(testCase) - captured = evalc('run(''VisualCoding_OphysQuickstart.mlx'')'); - testCase.verifyClass(captured, 'char') - close all - end - end -end \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2b58b48f..ffeca6b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # BOT Data Cache Cache/ +# Ignore everything in docs/reports +docs/reports/* + # Autosave files *.asv *.m~ diff --git a/+bot/+behavior/+item/+internal/+abstract/Item.m b/code/+bot/+behavior/+item/+internal/+abstract/Item.m similarity index 100% rename from +bot/+behavior/+item/+internal/+abstract/Item.m rename to code/+bot/+behavior/+item/+internal/+abstract/Item.m diff --git a/+bot/+behavior/+item/EphysSession.m b/code/+bot/+behavior/+item/EphysSession.m similarity index 100% rename from +bot/+behavior/+item/EphysSession.m rename to code/+bot/+behavior/+item/EphysSession.m diff --git a/+bot/+behavior/+item/Experiment.m b/code/+bot/+behavior/+item/Experiment.m similarity index 100% rename from +bot/+behavior/+item/Experiment.m rename to code/+bot/+behavior/+item/Experiment.m diff --git a/+bot/+behavior/+item/OphysSession.m b/code/+bot/+behavior/+item/OphysSession.m similarity index 100% rename from +bot/+behavior/+item/OphysSession.m rename to code/+bot/+behavior/+item/OphysSession.m diff --git a/+bot/+external/+fex/+filedownload/FileDownloadProgressMonitor.m b/code/+bot/+external/+fex/+filedownload/FileDownloadProgressMonitor.m similarity index 100% rename from +bot/+external/+fex/+filedownload/FileDownloadProgressMonitor.m rename to code/+bot/+external/+fex/+filedownload/FileDownloadProgressMonitor.m diff --git a/+bot/+external/+fex/+filedownload/downloadFile.m b/code/+bot/+external/+fex/+filedownload/downloadFile.m similarity index 100% rename from +bot/+external/+fex/+filedownload/downloadFile.m rename to code/+bot/+external/+fex/+filedownload/downloadFile.m diff --git a/+bot/+external/+fex/+filedownload/license.txt b/code/+bot/+external/+fex/+filedownload/license.txt similarity index 100% rename from +bot/+external/+fex/+filedownload/license.txt rename to code/+bot/+external/+fex/+filedownload/license.txt diff --git a/+bot/+external/+matnwb/+io/getMatType.m b/code/+bot/+external/+matnwb/+io/getMatType.m similarity index 100% rename from +bot/+external/+matnwb/+io/getMatType.m rename to code/+bot/+external/+matnwb/+io/getMatType.m diff --git a/+bot/+internal/+abstract/FileResource.m b/code/+bot/+internal/+abstract/FileResource.m similarity index 100% rename from +bot/+internal/+abstract/FileResource.m rename to code/+bot/+internal/+abstract/FileResource.m diff --git a/+bot/+internal/+abstract/LocalFileCache.m b/code/+bot/+internal/+abstract/LocalFileCache.m similarity index 100% rename from +bot/+internal/+abstract/LocalFileCache.m rename to code/+bot/+internal/+abstract/LocalFileCache.m diff --git a/+bot/+internal/+behavior/+cache/CloudCacher.m b/code/+bot/+internal/+behavior/+cache/CloudCacher.m similarity index 100% rename from +bot/+internal/+behavior/+cache/CloudCacher.m rename to code/+bot/+internal/+behavior/+cache/CloudCacher.m diff --git a/+bot/+internal/+behavior/+mixin/HasLinkedFile.m b/code/+bot/+internal/+behavior/+mixin/HasLinkedFile.m similarity index 100% rename from +bot/+internal/+behavior/+mixin/HasLinkedFile.m rename to code/+bot/+internal/+behavior/+mixin/HasLinkedFile.m diff --git a/+bot/+internal/+behavior/Cache.m b/code/+bot/+internal/+behavior/Cache.m similarity index 100% rename from +bot/+internal/+behavior/Cache.m rename to code/+bot/+internal/+behavior/Cache.m diff --git a/+bot/+internal/+behavior/LinkedFile.m b/code/+bot/+internal/+behavior/LinkedFile.m similarity index 100% rename from +bot/+internal/+behavior/LinkedFile.m rename to code/+bot/+internal/+behavior/LinkedFile.m diff --git a/+bot/+internal/+fileresource/+abstract/S3Bucket.m b/code/+bot/+internal/+fileresource/+abstract/S3Bucket.m similarity index 100% rename from +bot/+internal/+fileresource/+abstract/S3Bucket.m rename to code/+bot/+internal/+fileresource/+abstract/S3Bucket.m diff --git a/+bot/+internal/+fileresource/+mixin/HasFileResource.m b/code/+bot/+internal/+fileresource/+mixin/HasFileResource.m similarity index 100% rename from +bot/+internal/+fileresource/+mixin/HasFileResource.m rename to code/+bot/+internal/+fileresource/+mixin/HasFileResource.m diff --git a/+bot/+internal/+fileresource/+visualbehavior/VBEphysS3Bucket.m b/code/+bot/+internal/+fileresource/+visualbehavior/VBEphysS3Bucket.m similarity index 100% rename from +bot/+internal/+fileresource/+visualbehavior/VBEphysS3Bucket.m rename to code/+bot/+internal/+fileresource/+visualbehavior/VBEphysS3Bucket.m diff --git a/+bot/+internal/+fileresource/+visualbehavior/VBOphysS3Bucket.m b/code/+bot/+internal/+fileresource/+visualbehavior/VBOphysS3Bucket.m similarity index 100% rename from +bot/+internal/+fileresource/+visualbehavior/VBOphysS3Bucket.m rename to code/+bot/+internal/+fileresource/+visualbehavior/VBOphysS3Bucket.m diff --git a/+bot/+internal/+fileresource/+visualcoding/VCEphysS3Bucket.m b/code/+bot/+internal/+fileresource/+visualcoding/VCEphysS3Bucket.m similarity index 100% rename from +bot/+internal/+fileresource/+visualcoding/VCEphysS3Bucket.m rename to code/+bot/+internal/+fileresource/+visualcoding/VCEphysS3Bucket.m diff --git a/+bot/+internal/+fileresource/+visualcoding/VCOphysS3Bucket.m b/code/+bot/+internal/+fileresource/+visualcoding/VCOphysS3Bucket.m similarity index 100% rename from +bot/+internal/+fileresource/+visualcoding/VCOphysS3Bucket.m rename to code/+bot/+internal/+fileresource/+visualcoding/VCOphysS3Bucket.m diff --git a/+bot/+internal/+fileresource/WebApi.m b/code/+bot/+internal/+fileresource/WebApi.m similarity index 100% rename from +bot/+internal/+fileresource/WebApi.m rename to code/+bot/+internal/+fileresource/WebApi.m diff --git a/+bot/+internal/+metadata/+utility/convertStringArrayIdToInteger.m b/code/+bot/+internal/+metadata/+utility/convertStringArrayIdToInteger.m similarity index 100% rename from +bot/+internal/+metadata/+utility/convertStringArrayIdToInteger.m rename to code/+bot/+internal/+metadata/+utility/convertStringArrayIdToInteger.m diff --git a/+bot/+internal/+metadata/+utility/itemTableTypeConversionMap.m b/code/+bot/+internal/+metadata/+utility/itemTableTypeConversionMap.m similarity index 100% rename from +bot/+internal/+metadata/+utility/itemTableTypeConversionMap.m rename to code/+bot/+internal/+metadata/+utility/itemTableTypeConversionMap.m diff --git a/+bot/+internal/+metadata/+utility/itemTableVariableRenameMap.m b/code/+bot/+internal/+metadata/+utility/itemTableVariableRenameMap.m similarity index 100% rename from +bot/+internal/+metadata/+utility/itemTableVariableRenameMap.m rename to code/+bot/+internal/+metadata/+utility/itemTableVariableRenameMap.m diff --git a/+bot/+internal/+metadata/VisualBehaviorEphysManifest.m b/code/+bot/+internal/+metadata/VisualBehaviorEphysManifest.m similarity index 100% rename from +bot/+internal/+metadata/VisualBehaviorEphysManifest.m rename to code/+bot/+internal/+metadata/VisualBehaviorEphysManifest.m diff --git a/+bot/+internal/+metadata/VisualBehaviorOphysManifest.m b/code/+bot/+internal/+metadata/VisualBehaviorOphysManifest.m similarity index 100% rename from +bot/+internal/+metadata/VisualBehaviorOphysManifest.m rename to code/+bot/+internal/+metadata/VisualBehaviorOphysManifest.m diff --git a/+bot/+internal/+nwb/+file/+vb/BehaviorNWBFile.m b/code/+bot/+internal/+nwb/+file/+vb/BehaviorNWBFile.m similarity index 100% rename from +bot/+internal/+nwb/+file/+vb/BehaviorNWBFile.m rename to code/+bot/+internal/+nwb/+file/+vb/BehaviorNWBFile.m diff --git a/+bot/+internal/+nwb/+file/+vb/OphysNWBFile.m b/code/+bot/+internal/+nwb/+file/+vb/OphysNWBFile.m similarity index 100% rename from +bot/+internal/+nwb/+file/+vb/OphysNWBFile.m rename to code/+bot/+internal/+nwb/+file/+vb/OphysNWBFile.m diff --git a/+bot/+internal/+nwb/+reader/+vb/Contents.m b/code/+bot/+internal/+nwb/+reader/+vb/Contents.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/Contents.m rename to code/+bot/+internal/+nwb/+reader/+vb/Contents.m diff --git a/+bot/+internal/+nwb/+reader/+vb/read_cell_specimen_table.m b/code/+bot/+internal/+nwb/+reader/+vb/read_cell_specimen_table.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/read_cell_specimen_table.m rename to code/+bot/+internal/+nwb/+reader/+vb/read_cell_specimen_table.m diff --git a/+bot/+internal/+nwb/+reader/+vb/read_eyetracking_timetable.m b/code/+bot/+internal/+nwb/+reader/+vb/read_eyetracking_timetable.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/read_eyetracking_timetable.m rename to code/+bot/+internal/+nwb/+reader/+vb/read_eyetracking_timetable.m diff --git a/+bot/+internal/+nwb/+reader/+vb/read_lick_timetable.m b/code/+bot/+internal/+nwb/+reader/+vb/read_lick_timetable.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/read_lick_timetable.m rename to code/+bot/+internal/+nwb/+reader/+vb/read_lick_timetable.m diff --git a/+bot/+internal/+nwb/+reader/+vb/read_rewards_timetable.m b/code/+bot/+internal/+nwb/+reader/+vb/read_rewards_timetable.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/read_rewards_timetable.m rename to code/+bot/+internal/+nwb/+reader/+vb/read_rewards_timetable.m diff --git a/+bot/+internal/+nwb/+reader/+vb/read_trials_timetable.m b/code/+bot/+internal/+nwb/+reader/+vb/read_trials_timetable.m similarity index 100% rename from +bot/+internal/+nwb/+reader/+vb/read_trials_timetable.m rename to code/+bot/+internal/+nwb/+reader/+vb/read_trials_timetable.m diff --git a/+bot/+internal/+nwb/+reader/readDynamicTable.m b/code/+bot/+internal/+nwb/+reader/readDynamicTable.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readDynamicTable.m rename to code/+bot/+internal/+nwb/+reader/readDynamicTable.m diff --git a/+bot/+internal/+nwb/+reader/readGeneralMetadata.m b/code/+bot/+internal/+nwb/+reader/readGeneralMetadata.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readGeneralMetadata.m rename to code/+bot/+internal/+nwb/+reader/readGeneralMetadata.m diff --git a/+bot/+internal/+nwb/+reader/readOphysMetadata.m b/code/+bot/+internal/+nwb/+reader/readOphysMetadata.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readOphysMetadata.m rename to code/+bot/+internal/+nwb/+reader/readOphysMetadata.m diff --git a/+bot/+internal/+nwb/+reader/readRigMetadata.m b/code/+bot/+internal/+nwb/+reader/readRigMetadata.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readRigMetadata.m rename to code/+bot/+internal/+nwb/+reader/readRigMetadata.m diff --git a/+bot/+internal/+nwb/+reader/readSubjectMetadata.m b/code/+bot/+internal/+nwb/+reader/readSubjectMetadata.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readSubjectMetadata.m rename to code/+bot/+internal/+nwb/+reader/readSubjectMetadata.m diff --git a/+bot/+internal/+nwb/+reader/readTaskMetadata.m b/code/+bot/+internal/+nwb/+reader/readTaskMetadata.m similarity index 100% rename from +bot/+internal/+nwb/+reader/readTaskMetadata.m rename to code/+bot/+internal/+nwb/+reader/readTaskMetadata.m diff --git a/+bot/+internal/+nwb/LinkedNWBFile.m b/code/+bot/+internal/+nwb/LinkedNWBFile.m similarity index 100% rename from +bot/+internal/+nwb/LinkedNWBFile.m rename to code/+bot/+internal/+nwb/LinkedNWBFile.m diff --git a/+bot/+internal/+nwb/deindex_table_from_datasets.m b/code/+bot/+internal/+nwb/deindex_table_from_datasets.m similarity index 100% rename from +bot/+internal/+nwb/deindex_table_from_datasets.m rename to code/+bot/+internal/+nwb/deindex_table_from_datasets.m diff --git a/+bot/+internal/+nwb/has_path.m b/code/+bot/+internal/+nwb/has_path.m similarity index 100% rename from +bot/+internal/+nwb/has_path.m rename to code/+bot/+internal/+nwb/has_path.m diff --git a/+bot/+internal/+nwb/nwb_ephys.m b/code/+bot/+internal/+nwb/nwb_ephys.m similarity index 100% rename from +bot/+internal/+nwb/nwb_ephys.m rename to code/+bot/+internal/+nwb/nwb_ephys.m diff --git a/+bot/+internal/+nwb/readAttributesToStruct.m b/code/+bot/+internal/+nwb/readAttributesToStruct.m similarity index 100% rename from +bot/+internal/+nwb/readAttributesToStruct.m rename to code/+bot/+internal/+nwb/readAttributesToStruct.m diff --git a/+bot/+internal/+nwb/readDatasetsToStruct.m b/code/+bot/+internal/+nwb/readDatasetsToStruct.m similarity index 100% rename from +bot/+internal/+nwb/readDatasetsToStruct.m rename to code/+bot/+internal/+nwb/readDatasetsToStruct.m diff --git a/+bot/+internal/+nwb/struct_from_attributes.m b/code/+bot/+internal/+nwb/struct_from_attributes.m similarity index 100% rename from +bot/+internal/+nwb/struct_from_attributes.m rename to code/+bot/+internal/+nwb/struct_from_attributes.m diff --git a/+bot/+internal/+nwb/table_from_datasets.m b/code/+bot/+internal/+nwb/table_from_datasets.m similarity index 100% rename from +bot/+internal/+nwb/table_from_datasets.m rename to code/+bot/+internal/+nwb/table_from_datasets.m diff --git a/+bot/+internal/+nwb/xarray_from_dataset.m b/code/+bot/+internal/+nwb/xarray_from_dataset.m similarity index 100% rename from +bot/+internal/+nwb/xarray_from_dataset.m rename to code/+bot/+internal/+nwb/xarray_from_dataset.m diff --git a/+bot/+internal/+util/castTableVariables.m b/code/+bot/+internal/+util/castTableVariables.m similarity index 100% rename from +bot/+internal/+util/castTableVariables.m rename to code/+bot/+internal/+util/castTableVariables.m diff --git a/+bot/+internal/+util/getLocalFileSize.m b/code/+bot/+internal/+util/getLocalFileSize.m similarity index 100% rename from +bot/+internal/+util/getLocalFileSize.m rename to code/+bot/+internal/+util/getLocalFileSize.m diff --git a/+bot/+internal/+util/getToolboxVersion.m b/code/+bot/+internal/+util/getToolboxVersion.m similarity index 100% rename from +bot/+internal/+util/getToolboxVersion.m rename to code/+bot/+internal/+util/getToolboxVersion.m diff --git a/+bot/+internal/+util/getWebFileSize.m b/code/+bot/+internal/+util/getWebFileSize.m similarity index 100% rename from +bot/+internal/+util/getWebFileSize.m rename to code/+bot/+internal/+util/getWebFileSize.m diff --git a/+bot/+internal/+util/isVerLessThan.m b/code/+bot/+internal/+util/isVerLessThan.m similarity index 100% rename from +bot/+internal/+util/isVerLessThan.m rename to code/+bot/+internal/+util/isVerLessThan.m diff --git a/+bot/+internal/+util/resolveDataset.m b/code/+bot/+internal/+util/resolveDataset.m similarity index 100% rename from +bot/+internal/+util/resolveDataset.m rename to code/+bot/+internal/+util/resolveDataset.m diff --git a/+bot/+internal/+util/structcat.m b/code/+bot/+internal/+util/structcat.m similarity index 100% rename from +bot/+internal/+util/structcat.m rename to code/+bot/+internal/+util/structcat.m diff --git a/+bot/+internal/+util/structmerge.m b/code/+bot/+internal/+util/structmerge.m similarity index 100% rename from +bot/+internal/+util/structmerge.m rename to code/+bot/+internal/+util/structmerge.m diff --git a/+bot/+internal/+util/toolboxdir.m b/code/+bot/+internal/+util/toolboxdir.m similarity index 100% rename from +bot/+internal/+util/toolboxdir.m rename to code/+bot/+internal/+util/toolboxdir.m diff --git a/+bot/+internal/+util/uriJoin.m b/code/+bot/+internal/+util/uriJoin.m similarity index 100% rename from +bot/+internal/+util/uriJoin.m rename to code/+bot/+internal/+util/uriJoin.m diff --git a/+bot/+internal/BinarySearchSortedList_MATLAB.m b/code/+bot/+internal/BinarySearchSortedList_MATLAB.m similarity index 100% rename from +bot/+internal/BinarySearchSortedList_MATLAB.m rename to code/+bot/+internal/BinarySearchSortedList_MATLAB.m diff --git a/+bot/+internal/BinarySearchSortedList_double_mex.c b/code/+bot/+internal/BinarySearchSortedList_double_mex.c similarity index 100% rename from +bot/+internal/BinarySearchSortedList_double_mex.c rename to code/+bot/+internal/BinarySearchSortedList_double_mex.c diff --git a/+bot/+internal/BinarySearchSortedList_int32_mex.c b/code/+bot/+internal/BinarySearchSortedList_int32_mex.c similarity index 100% rename from +bot/+internal/BinarySearchSortedList_int32_mex.c rename to code/+bot/+internal/BinarySearchSortedList_int32_mex.c diff --git a/+bot/+internal/BrainObservatoryAPI.m b/code/+bot/+internal/BrainObservatoryAPI.m similarity index 100% rename from +bot/+internal/BrainObservatoryAPI.m rename to code/+bot/+internal/BrainObservatoryAPI.m diff --git a/+bot/+internal/Cache.m b/code/+bot/+internal/Cache.m similarity index 100% rename from +bot/+internal/Cache.m rename to code/+bot/+internal/Cache.m diff --git a/+bot/+internal/CloudCacher.m b/code/+bot/+internal/CloudCacher.m similarity index 100% rename from +bot/+internal/CloudCacher.m rename to code/+bot/+internal/CloudCacher.m diff --git a/+bot/+internal/GetUniqueUID.m b/code/+bot/+internal/GetUniqueUID.m similarity index 100% rename from +bot/+internal/GetUniqueUID.m rename to code/+bot/+internal/GetUniqueUID.m diff --git a/+bot/+internal/ObjectCacher.m b/code/+bot/+internal/ObjectCacher.m similarity index 100% rename from +bot/+internal/ObjectCacher.m rename to code/+bot/+internal/ObjectCacher.m diff --git a/+bot/+internal/OnDemandProperty.m b/code/+bot/+internal/OnDemandProperty.m similarity index 100% rename from +bot/+internal/OnDemandProperty.m rename to code/+bot/+internal/OnDemandProperty.m diff --git a/+bot/+internal/Preferences.m b/code/+bot/+internal/Preferences.m similarity index 100% rename from +bot/+internal/Preferences.m rename to code/+bot/+internal/Preferences.m diff --git a/+bot/+internal/README.mlx b/code/+bot/+internal/README.mlx similarity index 100% rename from +bot/+internal/README.mlx rename to code/+bot/+internal/README.mlx diff --git a/+bot/+internal/SimpleMap.m b/code/+bot/+internal/SimpleMap.m similarity index 100% rename from +bot/+internal/SimpleMap.m rename to code/+bot/+internal/SimpleMap.m diff --git a/+bot/+internal/fetch_ABO_query.m b/code/+bot/+internal/fetch_ABO_query.m similarity index 100% rename from +bot/+internal/fetch_ABO_query.m rename to code/+bot/+internal/fetch_ABO_query.m diff --git a/+bot/+internal/fetch_mex_handles.m b/code/+bot/+internal/fetch_mex_handles.m similarity index 100% rename from +bot/+internal/fetch_mex_handles.m rename to code/+bot/+internal/fetch_mex_handles.m diff --git a/+bot/+internal/merge_tables.m b/code/+bot/+internal/merge_tables.m similarity index 100% rename from +bot/+internal/merge_tables.m rename to code/+bot/+internal/merge_tables.m diff --git a/+bot/+internal/prepareForDemo.m b/code/+bot/+internal/prepareForDemo.m similarity index 100% rename from +bot/+internal/prepareForDemo.m rename to code/+bot/+internal/prepareForDemo.m diff --git a/+bot/+internal/reset.m b/code/+bot/+internal/reset.m similarity index 100% rename from +bot/+internal/reset.m rename to code/+bot/+internal/reset.m diff --git a/+bot/+item/+concrete/EphysSession.m b/code/+bot/+item/+concrete/EphysSession.m similarity index 100% rename from +bot/+item/+concrete/EphysSession.m rename to code/+bot/+item/+concrete/EphysSession.m diff --git a/+bot/+item/+concrete/OphysSession.m b/code/+bot/+item/+concrete/OphysSession.m similarity index 100% rename from +bot/+item/+concrete/OphysSession.m rename to code/+bot/+item/+concrete/OphysSession.m diff --git a/+bot/+item/+internal/+abstract/Item.m b/code/+bot/+item/+internal/+abstract/Item.m similarity index 100% rename from +bot/+item/+internal/+abstract/Item.m rename to code/+bot/+item/+internal/+abstract/Item.m diff --git a/+bot/+item/+internal/+abstract/LinkedFilesItem.m b/code/+bot/+item/+internal/+abstract/LinkedFilesItem.m similarity index 100% rename from +bot/+item/+internal/+abstract/LinkedFilesItem.m rename to code/+bot/+item/+internal/+abstract/LinkedFilesItem.m diff --git a/+bot/+item/+internal/+enum/Dataset.m b/code/+bot/+item/+internal/+enum/Dataset.m similarity index 100% rename from +bot/+item/+internal/+enum/Dataset.m rename to code/+bot/+item/+internal/+enum/Dataset.m diff --git a/+bot/+item/+internal/+enum/DatasetType.m b/code/+bot/+item/+internal/+enum/DatasetType.m similarity index 100% rename from +bot/+item/+internal/+enum/DatasetType.m rename to code/+bot/+item/+internal/+enum/DatasetType.m diff --git a/+bot/+item/+internal/+enum/ItemType.m b/code/+bot/+item/+internal/+enum/ItemType.m similarity index 100% rename from +bot/+item/+internal/+enum/ItemType.m rename to code/+bot/+item/+internal/+enum/ItemType.m diff --git a/+bot/+item/+internal/+enum/OnDemandState.m b/code/+bot/+item/+internal/+enum/OnDemandState.m similarity index 100% rename from +bot/+item/+internal/+enum/OnDemandState.m rename to code/+bot/+item/+internal/+enum/OnDemandState.m diff --git a/+bot/+item/+internal/+mixin/Metrics.m b/code/+bot/+item/+internal/+mixin/Metrics.m similarity index 100% rename from +bot/+item/+internal/+mixin/Metrics.m rename to code/+bot/+item/+internal/+mixin/Metrics.m diff --git a/+bot/+item/+internal/+mixin/OnDemandProps.m b/code/+bot/+item/+internal/+mixin/OnDemandProps.m similarity index 100% rename from +bot/+item/+internal/+mixin/OnDemandProps.m rename to code/+bot/+item/+internal/+mixin/OnDemandProps.m diff --git a/+bot/+item/+internal/EphysManifest.m b/code/+bot/+item/+internal/EphysManifest.m similarity index 100% rename from +bot/+item/+internal/EphysManifest.m rename to code/+bot/+item/+internal/EphysManifest.m diff --git a/+bot/+item/+internal/Manifest.m b/code/+bot/+item/+internal/Manifest.m similarity index 100% rename from +bot/+item/+internal/Manifest.m rename to code/+bot/+item/+internal/Manifest.m diff --git a/+bot/+item/+internal/OphysManifest.m b/code/+bot/+item/+internal/OphysManifest.m similarity index 100% rename from +bot/+item/+internal/OphysManifest.m rename to code/+bot/+item/+internal/OphysManifest.m diff --git a/+bot/+item/Cell.m b/code/+bot/+item/Cell.m similarity index 100% rename from +bot/+item/Cell.m rename to code/+bot/+item/Cell.m diff --git a/+bot/+item/Channel.m b/code/+bot/+item/Channel.m similarity index 100% rename from +bot/+item/Channel.m rename to code/+bot/+item/Channel.m diff --git a/+bot/+item/Experiment.m b/code/+bot/+item/Experiment.m similarity index 100% rename from +bot/+item/Experiment.m rename to code/+bot/+item/Experiment.m diff --git a/+bot/+item/Probe.m b/code/+bot/+item/Probe.m similarity index 100% rename from +bot/+item/Probe.m rename to code/+bot/+item/Probe.m diff --git a/+bot/+item/Session.m b/code/+bot/+item/Session.m similarity index 100% rename from +bot/+item/Session.m rename to code/+bot/+item/Session.m diff --git a/+bot/+item/Unit.m b/code/+bot/+item/Unit.m similarity index 100% rename from +bot/+item/Unit.m rename to code/+bot/+item/Unit.m diff --git a/+bot/+util/StimulusAlignedResp.m b/code/+bot/+util/StimulusAlignedResp.m similarity index 100% rename from +bot/+util/StimulusAlignedResp.m rename to code/+bot/+util/StimulusAlignedResp.m diff --git a/+bot/+util/autoConfigureByEnvironment.m b/code/+bot/+util/autoConfigureByEnvironment.m similarity index 100% rename from +bot/+util/autoConfigureByEnvironment.m rename to code/+bot/+util/autoConfigureByEnvironment.m diff --git a/+bot/+util/convertEphysToRaster.m b/code/+bot/+util/convertEphysToRaster.m similarity index 100% rename from +bot/+util/convertEphysToRaster.m rename to code/+bot/+util/convertEphysToRaster.m diff --git a/+bot/+util/convert_fluorescence_trace_into_raster_format.m b/code/+bot/+util/convert_fluorescence_trace_into_raster_format.m similarity index 100% rename from +bot/+util/convert_fluorescence_trace_into_raster_format.m rename to code/+bot/+util/convert_fluorescence_trace_into_raster_format.m diff --git a/+bot/+util/getPreferences.m b/code/+bot/+util/getPreferences.m similarity index 100% rename from +bot/+util/getPreferences.m rename to code/+bot/+util/getPreferences.m diff --git a/+bot/+util/ophyssessionfilter.m b/code/+bot/+util/ophyssessionfilter.m similarity index 100% rename from +bot/+util/ophyssessionfilter.m rename to code/+bot/+util/ophyssessionfilter.m diff --git a/+bot/+util/showReferences.m b/code/+bot/+util/showReferences.m similarity index 100% rename from +bot/+util/showReferences.m rename to code/+bot/+util/showReferences.m diff --git a/+bot/README.m b/code/+bot/README.m similarity index 100% rename from +bot/README.m rename to code/+bot/README.m diff --git a/+bot/getCells.m b/code/+bot/getCells.m similarity index 100% rename from +bot/getCells.m rename to code/+bot/getCells.m diff --git a/+bot/getChannels.m b/code/+bot/getChannels.m similarity index 100% rename from +bot/getChannels.m rename to code/+bot/getChannels.m diff --git a/+bot/getExperiments.m b/code/+bot/getExperiments.m similarity index 100% rename from +bot/getExperiments.m rename to code/+bot/getExperiments.m diff --git a/+bot/getProbes.m b/code/+bot/getProbes.m similarity index 100% rename from +bot/getProbes.m rename to code/+bot/getProbes.m diff --git a/+bot/getSessions.m b/code/+bot/getSessions.m similarity index 100% rename from +bot/getSessions.m rename to code/+bot/getSessions.m diff --git a/+bot/getUnits.m b/code/+bot/getUnits.m similarity index 100% rename from +bot/getUnits.m rename to code/+bot/getUnits.m diff --git a/+bot/listCells.m b/code/+bot/listCells.m similarity index 100% rename from +bot/listCells.m rename to code/+bot/listCells.m diff --git a/+bot/listChannels.m b/code/+bot/listChannels.m similarity index 100% rename from +bot/listChannels.m rename to code/+bot/listChannels.m diff --git a/+bot/listExperiments.m b/code/+bot/listExperiments.m similarity index 100% rename from +bot/listExperiments.m rename to code/+bot/listExperiments.m diff --git a/+bot/listProbes.m b/code/+bot/listProbes.m similarity index 100% rename from +bot/listProbes.m rename to code/+bot/listProbes.m diff --git a/+bot/listSessions.m b/code/+bot/listSessions.m similarity index 100% rename from +bot/listSessions.m rename to code/+bot/listSessions.m diff --git a/+bot/listUnits.m b/code/+bot/listUnits.m similarity index 100% rename from +bot/listUnits.m rename to code/+bot/listUnits.m diff --git a/.gitattributes b/code/.gitattributes similarity index 100% rename from .gitattributes rename to code/.gitattributes diff --git a/Contents.m b/code/Contents.m similarity index 91% rename from Contents.m rename to code/Contents.m index 9f5067bd..663f86c5 100644 --- a/Contents.m +++ b/code/Contents.m @@ -1,8 +1,8 @@ -% Brain Observatory Toolbox -% Version 0.9.4 19-feb-2024 +% Brain-Observatory-Toolbox +% Version 0.9.4.1 (+) 24-Nov-2024 % -% Copyright (c) 2017, Ethan Meyers -% ---------------------------------- +% Copyright (c) 2024, Ethan Meyers +% -------------------------------- % % A MATLAB toolbox for accessing and using the public neural % recording datasets from the Allen Brain Observatory. diff --git a/examples/VisualBehavior_OphysQuickstart.mlx b/code/examples/VisualBehavior_OphysQuickstart.mlx similarity index 100% rename from examples/VisualBehavior_OphysQuickstart.mlx rename to code/examples/VisualBehavior_OphysQuickstart.mlx diff --git a/examples/VisualCoding_BehaviorTutorial.mlx b/code/examples/VisualCoding_BehaviorTutorial.mlx similarity index 100% rename from examples/VisualCoding_BehaviorTutorial.mlx rename to code/examples/VisualCoding_BehaviorTutorial.mlx diff --git a/examples/VisualCoding_DecodingTutorial.mlx b/code/examples/VisualCoding_DecodingTutorial.mlx similarity index 100% rename from examples/VisualCoding_DecodingTutorial.mlx rename to code/examples/VisualCoding_DecodingTutorial.mlx diff --git a/examples/VisualCoding_EphysDemo.mlx b/code/examples/VisualCoding_EphysDemo.mlx similarity index 100% rename from examples/VisualCoding_EphysDemo.mlx rename to code/examples/VisualCoding_EphysDemo.mlx diff --git a/examples/VisualCoding_EphysQuickstart.mlx b/code/examples/VisualCoding_EphysQuickstart.mlx similarity index 100% rename from examples/VisualCoding_EphysQuickstart.mlx rename to code/examples/VisualCoding_EphysQuickstart.mlx diff --git a/examples/VisualCoding_EphysTutorial.mlx b/code/examples/VisualCoding_EphysTutorial.mlx similarity index 100% rename from examples/VisualCoding_EphysTutorial.mlx rename to code/examples/VisualCoding_EphysTutorial.mlx diff --git a/examples/VisualCoding_OphysDemo.mlx b/code/examples/VisualCoding_OphysDemo.mlx similarity index 100% rename from examples/VisualCoding_OphysDemo.mlx rename to code/examples/VisualCoding_OphysDemo.mlx diff --git a/examples/VisualCoding_OphysQuickstart.mlx b/code/examples/VisualCoding_OphysQuickstart.mlx similarity index 100% rename from examples/VisualCoding_OphysQuickstart.mlx rename to code/examples/VisualCoding_OphysQuickstart.mlx diff --git a/examples/VisualCoding_OphysTutorial.mlx b/code/examples/VisualCoding_OphysTutorial.mlx similarity index 100% rename from examples/VisualCoding_OphysTutorial.mlx rename to code/examples/VisualCoding_OphysTutorial.mlx From df86a84ed66193a9a8cc6b3aaf5a1e75ff671fa4 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:09:33 +0100 Subject: [PATCH 02/10] Add tools folder --- tools/+bottools/projectdir.m | 4 + tools/MLToolboxInfo.json | 14 + tools/tasks/codecheckToolbox.m | 5 + tools/tasks/createTestedWithBadgeforToolbox.m | 8 + tools/tasks/installMatBox.m | 63 ++++ tools/tasks/packageToolbox.m | 9 + tools/tasks/testToolbox.m | 5 + tools/tests/test.m | 336 ++++++++++++++++++ 8 files changed, 444 insertions(+) create mode 100644 tools/+bottools/projectdir.m create mode 100644 tools/MLToolboxInfo.json create mode 100644 tools/tasks/codecheckToolbox.m create mode 100644 tools/tasks/createTestedWithBadgeforToolbox.m create mode 100644 tools/tasks/installMatBox.m create mode 100644 tools/tasks/packageToolbox.m create mode 100644 tools/tasks/testToolbox.m create mode 100644 tools/tests/test.m diff --git a/tools/+bottools/projectdir.m b/tools/+bottools/projectdir.m new file mode 100644 index 00000000..692cc632 --- /dev/null +++ b/tools/+bottools/projectdir.m @@ -0,0 +1,4 @@ +function folderPath = botProjectdir() +% projectdir - Get project root directory for a matlab toolbox code repository + folderPath = fileparts(fileparts(fileparts(mfilename('fullpath')))); +end diff --git a/tools/MLToolboxInfo.json b/tools/MLToolboxInfo.json new file mode 100644 index 00000000..4cc068fc --- /dev/null +++ b/tools/MLToolboxInfo.json @@ -0,0 +1,14 @@ +{ + "Namespace" : "bot", + "ToolboxOptions": { + "Identifier": "85a3255c-4ff5-42ef-9c10-b441318b4322", + "ToolboxName": "Brain-Observatory-Toolbox", + "AuthorName": "Ethan Meyers", + "AuthorEmail": "", + "AuthorCompany": "", + "Summary": "A MATLAB toolbox for interacting with the Allen Brain Observatory", + "Description": "A MATLAB toolbox for accessing and using the neural recording public datasets from the Allen Brain Observatory. Available datasets: Available datasets: Visual Coding, Visual Behavior (Neuropixels and 2-Photon Calcium Imaging)", + "MinimumMatlabRelease": "", + "MaximumMatlabRelease": "" + } +} diff --git a/tools/tasks/codecheckToolbox.m b/tools/tasks/codecheckToolbox.m new file mode 100644 index 00000000..161df5b0 --- /dev/null +++ b/tools/tasks/codecheckToolbox.m @@ -0,0 +1,5 @@ +function codecheckToolbox() + installMatBox() + projectRootDirectory = bottools.projectdir(); + matbox.tasks.codecheckToolbox(projectRootDirectory) +end diff --git a/tools/tasks/createTestedWithBadgeforToolbox.m b/tools/tasks/createTestedWithBadgeforToolbox.m new file mode 100644 index 00000000..c773024b --- /dev/null +++ b/tools/tasks/createTestedWithBadgeforToolbox.m @@ -0,0 +1,8 @@ +function createTestedWithBadgeforToolbox(versionNumber) + arguments + versionNumber (1,1) string + end + installMatBox() + projectRootDirectory = bottools.projectdir(); + matbox.tasks.createTestedWithBadgeforToolbox(versionNumber, projectRootDirectory) +end diff --git a/tools/tasks/installMatBox.m b/tools/tasks/installMatBox.m new file mode 100644 index 00000000..f69ca570 --- /dev/null +++ b/tools/tasks/installMatBox.m @@ -0,0 +1,63 @@ +function installMatBox(mode) +% installMatBox - Install MatBox from latest release or latest commit + +% Todo: +% - If MatBox release has been updated on remote, should reinstall. + + arguments + mode (1,1) string {mustBeMember(mode, ["release", "commit"])} = "release" + end + + if mode == "release" + installFromRelease() % local function + elseif mode == "commit" + installFromCommit() % local function + end +end + +function installFromRelease() + addonsTable = matlab.addons.installedAddons(); + isMatchedAddon = addonsTable.Name == "MatBox"; + + if ~isempty(isMatchedAddon) && any(isMatchedAddon) + matlab.addons.enableAddon('MatBox') + else + info = webread('https://api.github.com/repos/ehennestad/MatBox/releases/latest'); + assetNames = {info.assets.name}; + isMltbx = startsWith(assetNames, 'MatBox'); + + mltbx_URL = info.assets(isMltbx).browser_download_url; + + % Download matbox + tempFilePath = websave(tempname, mltbx_URL); + cleanupObj = onCleanup(@(fp) delete(tempFilePath)); + + % Install toolbox + matlab.addons.install(tempFilePath); + end +end + + +function installFromCommit() + % Download latest zipped version of repo + url = "https://github.com/ehennestad/MatBox/archive/refs/heads/main.zip"; + tempFilePath = websave(tempname, url); + cleanupObj = onCleanup(@(fp) delete(tempFilePath)); + + % Unzip in temporary location + unzippedFiles = unzip(tempFilePath, tempdir); + unzippedFolder = unzippedFiles{1}; + if endsWith(unzippedFolder, filesep) + unzippedFolder = unzippedFolder(1:end-1); + end + + % Move to installation location + [~, repoFolderName] = fileparts(unzippedFolder); + targetFolder = fullfile(userpath, "Add-Ons"); + targetFolder = fullfile(targetFolder, repoFolderName); + if isfolder(targetFolder); rmdir(targetFolder, "s"); end + movefile(unzippedFolder, targetFolder); + + % Add to MATLAB's search path + addpath(genpath(targetFolder)) +end \ No newline at end of file diff --git a/tools/tasks/packageToolbox.m b/tools/tasks/packageToolbox.m new file mode 100644 index 00000000..9035af66 --- /dev/null +++ b/tools/tasks/packageToolbox.m @@ -0,0 +1,9 @@ +function packageToolbox(releaseType, versionString) + arguments + releaseType {mustBeTextScalar,mustBeMember(releaseType,["build","major","minor","patch","specific"])} = "build" + versionString {mustBeTextScalar} = ""; + end + installMatBox() + projectRootDirectory = bottools.projectdir(); + matbox.tasks.packageToolbox(projectRootDirectory, releaseType, versionString) +end diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m new file mode 100644 index 00000000..a4f52378 --- /dev/null +++ b/tools/tasks/testToolbox.m @@ -0,0 +1,5 @@ +function testToolbox(varargin) + installMatBox() + projectRootDirectory = bottools.projectdir(); + matbox.tasks.testToolbox(projectRootDirectory, varargin{:}) +end diff --git a/tools/tests/test.m b/tools/tests/test.m new file mode 100644 index 00000000..2076b9a3 --- /dev/null +++ b/tools/tests/test.m @@ -0,0 +1,336 @@ +%% Test class for BOT +classdef test < matlab.unittest.TestCase + + % Todo: + % [ ] set up test cache... + % [ ] test live scripts + + %% Test methods block + methods (Test) + function testCreateCache(testCase) %#ok<*MANU> + %% Test creating a BOT cache + boc = bot.internal.Cache.instance(); %#ok<*NASGU> + end + + function testOphysTables(testCase) + %% Test retrieving all OPhys manifest tables + bom = bot.item.internal.Manifest.instance('ophys'); + bom = bot.item.internal.OphysManifest.instance(); + bom.ophys_sessions; % Table of all OPhys experimental sessions + bom.ophys_experiments; % Table of all OPhys experimental containers + bom.ophys_cells; % Table of all OPhys cells + end + + function testEphysTables(testCase) + %% Test retrieving EPhys manifest tables + bom = bot.item.internal.Manifest.instance('ephys'); + bom = bot.item.internal.EphysManifest.instance(); + bom.ephys_sessions; % Table of all EPhys experimental sessions + bom.ephys_channels; % Table of all EPhys channels + bom.ephys_probes; % Table of all EPhys probes + bom.ephys_units; % Table of all EPhys units + end + + function testObtainSessionObject(testCase) + %% Test creation of an OPhys session object + sess = bot.listSessions('VisualCoding', 'ophys'); + + % - Get session IDs + vIDs = sess.id; + + % - Create some bot.item.Session objects + bot.getSessions(vIDs(1)); + bot.getSessions(vIDs(1:3)); + bot.getSessions(sess(1, :)); + bot.getSessions(sess(1:3, :)); + + % - Fetch all sessions from one experiment + exps = bot.listExperiments(); + s = bot.getSessions(sess(sess.experiment_container_id == exps.id(1), :)); + end + + function testSessionDataAccess(testCase) + %% Test data access methods of the bot.item.Session class for OPhys data + % - Create a bot.item.Session object + s = bot.getSessions(496934409); + + % - Test summary methods + s.nwb_metadata; + s.session_type; + s.roi_ids; + s.stimulus_list; + + % - Test data access methods + s.fluorescence_timestamps; + s.fluorescence_traces; + s.fluorescence_traces_demixed; + s.fluorescence_traces_dff; + s.corrected_fluorescence_traces; + s.max_projection; + s.motion_correction; + s.neuropil_r; + s.neuropil_traces; + s.roi_mask; + s.roi_mask_array; + s.running_speed; + s.pupil_location; + s.pupil_size; + end + + function testStimulusExtraction(testCase) + %% Test OPhys session stimulus extraction methods + % - Create a bot.session object + s = bot.getSessions(528402271); + + % - Get a vector of fluorescence frame IDs + vnFrameIDs = 1:numel(s.fluorescence_timestamps); + + % - Obtain per-frame stimulus table + s.getStimulusByFrame(vnFrameIDs); + + % - Obtain stimulus summary table + s.stimulus_epoch_table; + + % - Get list of stimuli + cStimuli = s.stimulus_list; + + % - Get a stimulus table for each stimulus + for cThisStim = cStimuli + s.getStimulusTable(cThisStim{1}); + end + + % - Get a natural movie stimulus template + s.getStimulusTemplate('natural_movie_one'); + s.getStimulusTable('natural_movie_one'); + + % - Get a spontantaneous activity stimulus table + s.spontaneous_activity_stimulus_table; + + % - Get an OPhys session with sparse noise + s = bot.getSessions(566752133); + + % - Get the sparse noise stimulus template + s.getStimulusTemplate('locally_sparse_noise_4deg'); + end + + function testOPhysExperiment(testCase) + %% Test obtaining OPhys experiment object + exp_table = bot.listExperiments(); + exp = bot.getExperiments(exp_table.id(1)); + exp = bot.getExperiments(exp_table(1, :)); + exps = bot.getExperiments(exp_table.id(1:3)); + exps = bot.getExperiments(exp_table(1:3, :)); + end + + function testOPhysCell(testCase) + %% Test obtaining OPhys cell object + cell_table = bot.listCells('VisualCoding', true); + cell_table = bot.listCells('VisualCoding', false); + cell = bot.getCells(cell_table.id(1)); + cell = bot.getCells(cell_table(1, :)); + cells = bot.getCells(cell_table(1:3, :)); + cells = bot.getCells(cell_table.id(1:3)); + + assert(~isempty(fieldnames(cells(1).metrics)), '`metrics` property structure was not set properly') + end + + function testEPhysManifest(testCase) + %% Test obtaining EPhys objects + % - Get the EPhys manifest + bom = bot.item.internal.EphysManifest.instance(); + bom = bot.item.internal.Manifest.instance('ephys'); + end + + function test_ophys_cells(testCase) + %% Tect obtaining OPhys cells + cells = bot.listCells(); + c = bot.getCells(cells(1, :)); + c = bot.getCells(cells.id(1)); + c = bot.getCells(cells(1:3, :)); + end + + function test_ephys_sessions(testCase) + %% Test obtaining EPhys objects + % - Get the EPhys manifest + bom = bot.item.internal.Manifest.instance('ephys'); + + % - Get the EPhys sessionts + sessions = bot.listSessions('VisualCoding', 'ephys'); + + % - Get a session + s = bot.getSessions(sessions{1, 'id'}); + s = bot.getSessions(sessions(1, :)); + s = bot.getSessions(sessions{1:3, 'id'}); + s = bot.getSessions(sessions(1:3, :)); + end + + function test_ephys_probes(testCase) + %% Test obtaining EPhys objects + % - Get the EPhys manifest + bom = bot.item.internal.Manifest.instance('ephys'); + + % - Get the probes table + probes = bot.listProbes(); + + % - Get a probe, by ID and by table + p = bot.getProbes(probes{1, 'id'}); + p = bot.getProbes(probes(1, :)); + p = bot.getProbes(probes{1:3, 'id'}); + p = bot.getProbes(probes(1:3, :)); + end + + function test_ephys_channels(testCase) + %% Test obtaining EPhys objects + % - Get the EPhys manifest + bom = bot.item.internal.Manifest.instance('ephys'); + + % - Get the channels table + channels = bot.listChannels(); + + % - Get channels, by ID and by table + c = bot.getChannels(channels{1, 'id'}); + c = bot.getChannels(channels(1, :)); + c = bot.getChannels(channels{1:3, 'id'}); + c = bot.getChannels(channels(1:3, :)); + end + + function test_ephys_units(testCase) + %% Test obtaining EPhys units objects + % - Get the EPhys manifest + bom = bot.item.internal.Manifest.instance('ephys'); + + % - Get the units table + units = bot.listUnits('VisualCoding', true); + units = bot.listUnits('VisualCoding', false); + + % - Get units, by ID and by table + u = bot.getUnits(units{1, 'id'}); + u = bot.getUnits(units(1, :)); + u = bot.getUnits(units{1:3, 'id'}); + u = bot.getUnits(units(1:3, :)); + + assert(~isempty(fieldnames(u(1).metrics)), '`metrics` property structure was not set properly') + end + + function testLFPCSDExtraction(testCase) + %% Test LFP and CSD extraction + % - Get the EPhys manifest + bom = bot.item.internal.Manifest.instance('ephys'); + + % - Get a probe + p = bot.getProbes(bom.ephys_probes{1, 'id'}); + + % - Access LFP data + p.lfpData; + + % - Access CSD data + p.csdData; + end + + function test_ephys_lazy_attributes(testCase) + %% Test reading lazy attributes + bom = bot.item.internal.Manifest.instance('ephys'); + s = bot.getSessions(bom.ephys_sessions{1, 'id'}); + + s.mean_waveforms; + s.optogenetic_stimulation_epochs; + s.inter_presentation_intervals; + s.running_speed; + s.mean_waveforms; + s.stimulus_presentations; + s.stimulus_conditions; + s.session_start_time; + s.spike_amplitudes; + s.invalid_times; + + % s.num_stimulus_presentations; % Not currently implemented, since it requires access to full stimulus table + s.stimulus_names; + s.structure_acronyms; + s.structurewise_unit_counts; + + s.stimulus_templates; + + try + s.optogenetic_stimulation_epochs; + catch + warning('No optogenetic stimulation data was present for this session.'); + end + end + + function test_ephys_session_methods(testCase) + %% Test session data access methods + bom = bot.item.internal.Manifest.instance('ephys'); + s = bot.getSessions(bom.ephys_sessions{1, 'id'}); + + sess = bot.listSessions('VisualCoding', 'ephys'); + s = bot.getSessions(sess(1, :)); + + s.fetch_stimulus_table(); + s.getStimulusEpochsByDuration(); + uid = s.units{1, 'id'}; + s.getPresentationwiseSpikeCounts([0 1], 1, uid); + s.getPresentationwiseSpikeTimes(0, uid); + s.getConditionwiseSpikeStatistics(0, uid); + s.getConditionsByStimulusName("spontaneous"); + end + + function test_factory_functions(testCase) + %% - Test manifest fetch factory functions + exps = bot.listExperiments(); + sess_ephys = bot.listSessions('VisualCoding', 'ephys'); + sess_ophys = bot.listSessions('VisualCoding', 'ophys'); + units = bot.listUnits(); + units = bot.listUnits('VisualCoding', true); + probes = bot.listProbes(); + channels = bot.listChannels(); + cells = bot.listCells(); + cells = bot.listCells('VisualCoding', true); + + % - Test "get object" factory functions + bot.getSessions(sess_ephys{1, 'id'}); + bot.getSessions(sess_ophys{1, 'id'}); + bot.getExperiments(exps{1, 'id'}); + bot.getUnits(units{1, 'id'}); + bot.getProbes(probes{1, 'id'}); + bot.getChannels(channels{1, 'id'}); + bot.getCells(cells{1, 'id'}); + end + + function testFactoryFunctionsVisualBehavior(testCase) + sess_ephys = bot.listSessions('VisualBehavior', 'ephys'); + sess_ophys = bot.listSessions('VisualBehavior', 'ophys'); + + exps = bot.listExperiments('VisualBehavior'); + probes = bot.listProbes('VisualBehavior'); + channels = bot.listChannels('VisualBehavior'); + units = bot.listUnits('VisualBehavior', true); + cells = bot.listCells('VisualBehavior', true); + + % - Test "get object" factory functions + bot.getSessions(sess_ephys{1, 'id'}); + bot.getSessions(sess_ophys{1, 'id'}); + bot.getExperiments(exps{1, 'id'}); + bot.getUnits(units{1, 'id'}); + bot.getProbes(probes{1, 'id'}); + bot.getChannels(channels{1, 'id'}); + bot.getCells(cells{1, 'id'}); + end + + function testFactoryBehaviorOnlySessions(testCase) + vbEphysManifest = bot.internal.metadata.VisualBehaviorEphysManifest.instance(); + vbOphysManifest = bot.internal.metadata.VisualBehaviorOphysManifest.instance(); + + ephysSessionId = vbEphysManifest.BehaviorSessions.id(1); + ophysSessionId = vbOphysManifest.BehaviorSessions.id(1); + + bot.getSessions(ephysSessionId); + bot.getSessions(ophysSessionId); + end + + function testOphysQuickStart(testCase) + captured = evalc('run(''VisualCoding_OphysQuickstart.mlx'')'); + testCase.verifyClass(captured, 'char') + close all + end + end +end \ No newline at end of file From bc48702ad4c112d068fe42ce5bc2823bcdf49669 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:15:15 +0100 Subject: [PATCH 03/10] Add workflows --- .github/workflows/create_release.yml | 176 +++++++++++++++++++++++++++ .github/workflows/run_tests.yml | 91 ++++++++++++++ code/Contents.m | 2 +- 3 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/create_release.yml create mode 100644 .github/workflows/run_tests.yml diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml new file mode 100644 index 00000000..d3da71b7 --- /dev/null +++ b/.github/workflows/create_release.yml @@ -0,0 +1,176 @@ +# Test the toolbox across all supported releases of MATLAB, package toolbox, create release +# Adapted from: https://github.com/mathworks/climatedatastore/blob/main/.github/workflows/release.yml + +name: Create new release + +# Run workflow when a tag is created +on: + push: + tags: + - 'v*' + +jobs: + # This workflow contains: + # 1. a matrixed test job run across a bunch of releases of MATLAB + # 2. a reporting job that summarizes the tests, and updates release badge + test: + strategy: + fail-fast: false + matrix: + MATLABVersion: [R2020b, R2021a, R2021b, R2022a, R2022b, R2023a, R2023b, R2024a, R2024b] + # The type of runner that the job will run on + runs-on: ubuntu-latest + + steps: + # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it + - uses: actions/checkout@v4 + + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v2 + with: + release: ${{ matrix.MATLABVersion }} + + # Runs all tests in the project. Put results in a version specific subdirectory + - name: Run tests + uses: matlab-actions/run-command@v2 + with: + command: | + addpath(genpath("tools")); + testToolbox('ReportSubdirectory',"${{ matrix.MATLABVersion }}", 'CreateBadge', false) + + # Save the contents of the report directory from each release into an artifact. + - name: Save Report Directory + uses: actions/upload-artifact@v4 + if: always() + with: + name: reports-${{ matrix.MATLABVersion }} + path: docs/reports + + # Report on what releases tested successfully. + # Generate a draft release based on the tag + # Recreate the tag with the final version of files + release: + needs: test + if: always() + runs-on: ubuntu-latest + env: + TOOLBOX_FILE_NAME: Brain_Observatory_Toolbox + + steps: + # Use deploy key to push back to protected branch + - name: Checkout repository using deploy key + uses: actions/checkout@v4 + with: + ref: refs/heads/main + ssh-key: ${{ secrets.DEPLOY_KEY }} + + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v2 + + # Copy all the reports down into the container + - uses: actions/download-artifact@v4 + with: + pattern: reports-* + path: docs/reports + merge-multiple: true + + # Generate the JSON for the releases tested badge + - name: Generate tested with badge + uses: matlab-actions/run-command@v2 + with: + command: addpath(genpath("tools")), createTestedWithBadgeforToolbox("${{ github.ref_name }}") + + # Publish test results from all the releases + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + junit_files: "docs/reports/*/test-results.xml" + + # Package the MLTBX + - name: Package Toolbox + uses: matlab-actions/run-command@v2 + with: + command: | + addpath(genpath("tools")); + packageToolbox("specific","${{ github.ref_name }}") + + # Define the versionNumber using underscores, as this is used in the MLTBX + - name: Set version number + id: set_version + run: | + versionNumber=$(echo "${{ github.ref_name }}" | sed 's/\./_/g') + echo "versionNumber=$versionNumber" >> $GITHUB_ENV + + # Save the MLTBX. + - name: Save packaged toolbox + uses: actions/upload-artifact@v4 + with: + name: ${{TOOLBOX_FILE_NAME}}${{ env.versionNumber }}.mltbx + path: releases/${{TOOLBOX_FILE_NAME}}_${{ env.versionNumber }}.mltbx + + # Commit the updated Contents.m + - name: Commit updated Contents.m file + continue-on-error: true + run: | + git config user.name "${{ github.workflow }} by ${{ github.actor }}" + git config user.email "<>" + git status + git add code/Contents.m + git commit -m "Final checkins for release ${{ github.ref_name }}" + git fetch + git push + + # Commit the JSON for the MATLAB releases test badge to gh-badges branch + - name: Checkout gh-badges branch + uses: actions/checkout@v4 + with: + ref: gh-badges + path: gh-badges + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Push to gh-badges + run: | + mkdir -p gh-badges/.github/badges/${{ github.ref_name }} + cp .github/badges/${{ github.ref_name }}/tested_with.json gh-badges/.github/badges/${{ github.ref_name }}/tested_with.json + cd gh-badges + + git config user.name "${{ github.workflow }} by ${{ github.actor }}" + git config user.email "<>" + + # Only proceed with commit and push if changes are detected + if [[ $(git add .github/badges/* --dry-run | wc -l) -gt 0 ]]; then + git add .github/badges/* + git commit -m "Update tested with badge for release" + git push -f + else + echo "Nothing to commit" + fi + + # Retag the repo so that the updated files are included in the release tag + - name: Update tag + if: always() + continue-on-error: true + run: | + git config user.name "${{ github.workflow }} by ${{ github.actor }}" + git config user.email "<>" + + # Delete the existing tag locally and remotely + git tag -d "${{ github.ref_name }}" + git push origin --delete "${{ github.ref_name }}" + + # Recreate the tag with a message, including [skip ci] to prevent CI workflows + git tag -a "${{ github.ref_name }}" -m "Release ${{ github.ref_name }} [skip ci]" + + # Push the new tag to the remote repository + git push origin "${{ github.ref_name }}" + + # Create the release + - name: Create GitHub Release + uses: ncipollo/release-action@v1 + with: + draft: true + artifacts: "releases/${{TOOLBOX_FILE_NAME}}_${{ env.versionNumber }}.mltbx" + generateReleaseNotes: true + body: "![MATLAB Versions Tested](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2F${{github.repository}}%2Fgh-badges%2F.github%2Fbadges%2F${{ github.ref_name }}%2Ftested_with.json)" + diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml new file mode 100644 index 00000000..740a7dec --- /dev/null +++ b/.github/workflows/run_tests.yml @@ -0,0 +1,91 @@ +name: Run tests + +on: + # Triggers the workflow on push or pull request events for the "main" branch + push: + branches: [ "main" ] + paths-ignore: + - '*md' + - '.github/**' + - 'docs/reports/**' + pull_request: + branches: [ "main" ] + + # Allows for manually running this workflow from the Actions tab + workflow_dispatch: + +jobs: + # This workflow contains a single job called "test" + test: + name: Test toolbox code + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it + - name: Check out repo + uses: actions/checkout@v4 + + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v2 + + # Check for MATLAB code issues in the project. + - name: Check for MATLAB code issues + uses: matlab-actions/run-command@v2 + if: always() + with: + command: addpath(genpath("tools")), codecheckToolbox() + + # Upload code issues report + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: docs/reports/code_issues.sarif + + # Runs all tests in the project. + - name: Run tests + uses: matlab-actions/run-command@v2 + if: always() + with: + command: addpath(genpath("tools")), testToolbox() + + # Commit updated SVG badges for the issues and tests (if changed) + - name: Commit svg badges if updated + if: always() + continue-on-error: true + run: | + git config user.name "${{ github.workflow }} by ${{ github.actor }}" + git config user.email "<>" + git fetch + + if [[ $(git add .github/badges/* --dry-run | wc -l) -gt 0 ]]; then + git add .github/badges/* + git commit -m "Update code issues and tests badges" + git push -f + else + echo "Nothing to commit" + fi + + - name: Upload code coverage report to Codecov + uses: codecov/codecov-action@v4 + if: always() + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: docs/reports/codecoverage.xml + + # Publish test results + - name: Publish test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: "docs/reports/test-results.xml" + + # Save the contents of the reports directory as an artifact + - name: Save reports directory + uses: actions/upload-artifact@v4 + if: always() + with: + name: reports + path: docs/reports diff --git a/code/Contents.m b/code/Contents.m index 663f86c5..1728aa4d 100644 --- a/code/Contents.m +++ b/code/Contents.m @@ -1,5 +1,5 @@ % Brain-Observatory-Toolbox -% Version 0.9.4.1 (+) 24-Nov-2024 +% Version 0.9.4 19-feb-2024 % % Copyright (c) 2024, Ethan Meyers % -------------------------------- From b9c1dfee9599887b835c657369c05144b9bc32bb Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:36:28 +0100 Subject: [PATCH 04/10] Fix bugs --- tools/tasks/codecheckToolbox.m | 2 +- tools/tasks/testToolbox.m | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/tasks/codecheckToolbox.m b/tools/tasks/codecheckToolbox.m index 161df5b0..5f2b270c 100644 --- a/tools/tasks/codecheckToolbox.m +++ b/tools/tasks/codecheckToolbox.m @@ -1,5 +1,5 @@ function codecheckToolbox() - installMatBox() + installMatBox("commit") projectRootDirectory = bottools.projectdir(); matbox.tasks.codecheckToolbox(projectRootDirectory) end diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m index a4f52378..6b9b46f6 100644 --- a/tools/tasks/testToolbox.m +++ b/tools/tasks/testToolbox.m @@ -1,5 +1,14 @@ function testToolbox(varargin) installMatBox() projectRootDirectory = bottools.projectdir(); + + botPrefs = bot.util.getPreferences(); + if isempty(botPrefs.CacheDirectory) + botPrefs.DialogMode = "Command Window"; + tempCache = fullfile(tempdir, 'bot-cache'); + if ~isfolder(tempCache); mkdir(tempCache); end + cleanupObj = onCleanup(@(fp) rmdir(tempCache, "s")); + end + matbox.tasks.testToolbox(projectRootDirectory, varargin{:}) end From 44c004151aa73badf3088ac98db8105ed1ef3281 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:42:55 +0100 Subject: [PATCH 05/10] ... --- code/+bot/listSessions.m | 2 +- tools/tasks/testToolbox.m | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/+bot/listSessions.m b/code/+bot/listSessions.m index 5816c5d2..a131318b 100644 --- a/code/+bot/listSessions.m +++ b/code/+bot/listSessions.m @@ -47,7 +47,7 @@ % Note: This function can support returning sessions from multiple % datasets, but this functionality is currently not enabled - datasetNames = [dataset.Name]; + datasetNames = dataset.Name; datasetType = string(datasetType); if options.IncludeBehaviorOnly diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m index 6b9b46f6..cf11bca4 100644 --- a/tools/tasks/testToolbox.m +++ b/tools/tasks/testToolbox.m @@ -2,6 +2,7 @@ function testToolbox(varargin) installMatBox() projectRootDirectory = bottools.projectdir(); + addpath(fullfile(projectRootDirectory, 'code')) botPrefs = bot.util.getPreferences(); if isempty(botPrefs.CacheDirectory) botPrefs.DialogMode = "Command Window"; From 9ef9565c043ac2365cdfc7df48d850539ce5d9cb Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:51:31 +0100 Subject: [PATCH 06/10] ... --- tools/tasks/testToolbox.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m index cf11bca4..f12310d2 100644 --- a/tools/tasks/testToolbox.m +++ b/tools/tasks/testToolbox.m @@ -4,7 +4,7 @@ function testToolbox(varargin) addpath(fullfile(projectRootDirectory, 'code')) botPrefs = bot.util.getPreferences(); - if isempty(botPrefs.CacheDirectory) + if botPrefs.CacheDirectory == "" || ~isfolder(botPrefs.CacheDirectory) botPrefs.DialogMode = "Command Window"; tempCache = fullfile(tempdir, 'bot-cache'); if ~isfolder(tempCache); mkdir(tempCache); end From 12cc12581ce404b6ab838829dd6329ac34d1cb21 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 20:59:18 +0100 Subject: [PATCH 07/10] ... --- tools/tasks/testToolbox.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m index f12310d2..72187607 100644 --- a/tools/tasks/testToolbox.m +++ b/tools/tasks/testToolbox.m @@ -6,9 +6,14 @@ function testToolbox(varargin) botPrefs = bot.util.getPreferences(); if botPrefs.CacheDirectory == "" || ~isfolder(botPrefs.CacheDirectory) botPrefs.DialogMode = "Command Window"; - tempCache = fullfile(tempdir, 'bot-cache'); - if ~isfolder(tempCache); mkdir(tempCache); end + tempCache = fullfile(tempdir, 'bot_cache'); + if ~isfolder(tempCache) + fprintf('Making cache directory "%s"', tempCache) + mkdir(tempCache); + end cleanupObj = onCleanup(@(fp) rmdir(tempCache, "s")); + botPrefs.CacheDirectory = tempCache; + disp(botPrefs) end matbox.tasks.testToolbox(projectRootDirectory, varargin{:}) From fe11a7246e132c6cccb8a15390f39a992de57560 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 21:12:48 +0100 Subject: [PATCH 08/10] ... --- tools/tasks/testToolbox.m | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tasks/testToolbox.m b/tools/tasks/testToolbox.m index 72187607..8530a45e 100644 --- a/tools/tasks/testToolbox.m +++ b/tools/tasks/testToolbox.m @@ -13,6 +13,7 @@ function testToolbox(varargin) end cleanupObj = onCleanup(@(fp) rmdir(tempCache, "s")); botPrefs.CacheDirectory = tempCache; + botPrefs.AutoDownloadNwb = false; disp(botPrefs) end From 1f5b45fd9ef43e1b05190b37f83e0cbf64af2f7e Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 21:51:19 +0100 Subject: [PATCH 09/10] ... --- code/+bot/+behavior/+item/EphysSession.m | 10 +++++++--- code/+bot/+behavior/+item/OphysSession.m | 10 +++++++--- code/+bot/+internal/+util/toolboxdir.m | 8 ++++---- code/+bot/getSessions.m | 8 +++++--- tools/tests/test.m | 7 ++++--- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/code/+bot/+behavior/+item/EphysSession.m b/code/+bot/+behavior/+item/EphysSession.m index f9ab29d2..2297f88b 100644 --- a/code/+bot/+behavior/+item/EphysSession.m +++ b/code/+bot/+behavior/+item/EphysSession.m @@ -1074,9 +1074,13 @@ function displayScalarObject(self) function tableRow = findManifestTableRow(obj, itemId) % Ensure ID is correct type itemId = uint32(round(itemId)); - - tableRow = bot.listSessions(obj.DATASET, obj.DATASET_TYPE, ... - "Id", itemId, "IncludeBehaviorOnly", true); + for i = 0:1 + tableRow = bot.listSessions(obj.DATASET, obj.DATASET_TYPE, ... + "Id", itemId, "IncludeBehaviorOnly", logical(i)); + if ~isempty(tableRow) + break + end + end end end diff --git a/code/+bot/+behavior/+item/OphysSession.m b/code/+bot/+behavior/+item/OphysSession.m index 3081fdf4..1e357f6f 100644 --- a/code/+bot/+behavior/+item/OphysSession.m +++ b/code/+bot/+behavior/+item/OphysSession.m @@ -161,9 +161,13 @@ function initLinkedItems(obj) function tableRow = findManifestTableRow(obj, itemId) % Ensure ID is correct type itemId = uint32(round(itemId)); - - tableRow = bot.listSessions(obj.DATASET, obj.DATASET_TYPE, ... - "Id", itemId, "IncludeBehaviorOnly", true); + for i = 0:1 + tableRow = bot.listSessions(obj.DATASET, obj.DATASET_TYPE, ... + "Id", itemId, "IncludeBehaviorOnly", logical(i)); + if ~isempty(tableRow) + break + end + end end end diff --git a/code/+bot/+internal/+util/toolboxdir.m b/code/+bot/+internal/+util/toolboxdir.m index ea36b193..3df1d4da 100644 --- a/code/+bot/+internal/+util/toolboxdir.m +++ b/code/+bot/+internal/+util/toolboxdir.m @@ -1,8 +1,8 @@ function toolboxFolderPath = toolboxdir() thisFolderPath = fileparts( mfilename('fullpath') ); - splitFolderPath = strsplit(thisFolderPath, filesep); - - % Move 3 folders up: - toolboxFolderPath = fullfile( splitFolderPath{1:end-3} ); + filesepLoc = regexp(thisFolderPath, filesep); + + % Get path of folder 3 levels up: + toolboxFolderPath = extractBefore(thisFolderPath, filesepLoc(end-2)); end diff --git a/code/+bot/getSessions.m b/code/+bot/getSessions.m index 78c9de4c..dc60bb8e 100644 --- a/code/+bot/getSessions.m +++ b/code/+bot/getSessions.m @@ -87,9 +87,11 @@ warning('off', 'BOT:ListSessions:BehaviorOnlyNotPresent') for iName = string(datasetNames') for jType = string(datasetTypes') - sessionTable = bot.listSessions(iName, jType, "IncludeBehaviorOnly", true); - ids = sessionTable.id; - sessionIdMap(ids)={{iName, jType}}; + for k = 0:1 + sessionTable = bot.listSessions(iName, jType, "IncludeBehaviorOnly", logical(k)); + ids = sessionTable.id; + sessionIdMap(ids)={{iName, jType}}; + end end end warning('on', 'BOT:ListSessions:BehaviorOnlyNotPresent') diff --git a/tools/tests/test.m b/tools/tests/test.m index 2076b9a3..bc24423b 100644 --- a/tools/tests/test.m +++ b/tools/tests/test.m @@ -328,9 +328,10 @@ function testFactoryBehaviorOnlySessions(testCase) end function testOphysQuickStart(testCase) - captured = evalc('run(''VisualCoding_OphysQuickstart.mlx'')'); - testCase.verifyClass(captured, 'char') - close all + quickStartPath = fullfile(bot.internal.util.toolboxdir, 'examples', 'VisualCoding_OphysQuickstart.mlx'); + captured = evalc('run(quickStartPath)'); + testCase.verifyClass(captured, 'char') + close all end end end \ No newline at end of file From 638c3919dae8338d1d3bf3bd7c49e789d8f268ff Mon Sep 17 00:00:00 2001 From: ehennestad Date: Sun, 24 Nov 2024 22:24:12 +0100 Subject: [PATCH 10/10] ... --- .github/workflows/run_tests.yml | 2 ++ tools/tests/test.m | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 740a7dec..b58510dd 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -26,6 +26,8 @@ jobs: # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it - name: Check out repo uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} - name: Set up MATLAB uses: matlab-actions/setup-matlab@v2 diff --git a/tools/tests/test.m b/tools/tests/test.m index bc24423b..554c4150 100644 --- a/tools/tests/test.m +++ b/tools/tests/test.m @@ -4,6 +4,7 @@ % Todo: % [ ] set up test cache... % [ ] test live scripts + %% Test methods block methods (Test)