diff --git a/.all-contributorsrc b/.all-contributorsrc index 1fec0ea1..9a7ec733 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7,7 +7,7 @@ "contributors": [ { "login": "CerenB", - "name": "CerenB", + "name": "Ceren Battal", "avatar_url": "https://avatars1.githubusercontent.com/u/10451654?v=4", "profile": "https://github.com/CerenB", "contributions": [ @@ -21,7 +21,7 @@ }, { "login": "marcobarilari", - "name": "marcobarilari", + "name": "Marco Barilari", "avatar_url": "https://avatars3.githubusercontent.com/u/38101692?v=4", "profile": "https://github.com/marcobarilari", "contributions": [ @@ -64,7 +64,7 @@ }, { "login": "iqrashahzad14", - "name": "iqrashahzad14", + "name": "Iqra Shahzad", "avatar_url": "https://avatars.githubusercontent.com/u/75671348?v=4", "profile": "https://github.com/iqrashahzad14", "contributions": [ diff --git a/checkCppBidsDependencies.m b/checkCppBidsDependencies.m index e31fc39a..fa27ad95 100644 --- a/checkCppBidsDependencies.m +++ b/checkCppBidsDependencies.m @@ -1,65 +1,16 @@ -% (C) Copyright 2020 CPP_BIDS developers - function checkCppBidsDependencies(cfg) - % - % Adds dependencies to the Matlab / Octave path and make sure we got all of them. - % - % USAGE:: - % - % checkCppBidsDependencies(cfg) - % - % :param cfg: Configuration. See ``checkCFG()``. - % :type cfg: structure - - if nargin < 1 - cfg.verbose = 2; - end - - global CPP_BIDS_INITIALIZED - - if isempty(CPP_BIDS_INITIALIZED) - - GITHUB_WORKSPACE = getenv('GITHUB_WORKSPACE'); - - if strcmp(GITHUB_WORKSPACE, '/github/workspace') - - pth = GITHUB_WORKSPACE; - addpath(genpath(fullfile(pth, 'lib'))); - - elseif isempty(GITHUB_WORKSPACE) % local + % (C) Copyright 2020 CPP_BIDS developers - pth = fullfile(fileparts(mfilename('fullpath'))); - - addpath(pth); - - checkSubmodule(fullfile(pth, 'lib', 'JSONio')); - checkSubmodule(fullfile(pth, 'lib', 'bids-matlab')); - - addpath(genpath(fullfile(pth, 'src'))); - - end - - printCreditsCppBids(cfg); - - CPP_BIDS_INITIALIZED = true(); - - else - if ~isfield(cfg, 'versbose') || cfg.verbose - fprintf(1, '\n\nCPP_BIDS already initialized\n\n'); - end + warning(sprintf(['\n\nDEPRECATION WARNING:\n', ... + '"checkCppBidsDependencies" is deprecated ', ... + 'and will be removed in a future release.\n', ... + '\nPlease use "cpp_bids(''init'')" instead.'])); %#ok + verbose = false; + if nargin > 0 && ~isempty(cfg) && isfield(cfg, 'verbose') && ~isempty(cfg.verbose) + verbose = cfg.verbose; end -end + cpp_bids('init', 'verbose', verbose); -function checkSubmodule(pth) - % If external dir is empty throw an exception - % and ask user to update submodules. - if numel(dir(pth)) <= 2 % Means that the external is empty - error(['Git submodules are not cloned!', ... - 'Try this in your terminal:', ... - ' git submodule update --recursive ']); - else - addpath(pth); - end end diff --git a/cpp_bids.m b/cpp_bids.m new file mode 100644 index 00000000..73f60791 --- /dev/null +++ b/cpp_bids.m @@ -0,0 +1,171 @@ +function cpp_bids(varargin) + % + % General intro function for CPP BIDS + % + % USAGE:: + % + % cpp_bids + % cpp_bids('init') + % cpp_bids('uninit') + % cpp_bids('dev') + % + % :param action: + % :type action: string + % + % :returns: - :action: (type) (dimension) + % + % Example:: + % + % (C) Copyright 2022 CPP_BIDS developers + + p = inputParser; + + defaultAction = 'init'; + + addOptional(p, 'action', defaultAction, @ischar); + addParameter(p, 'verbose', true); + + parse(p, varargin{:}); + + action = p.Results.action; + verbose = p.Results.verbose; + + switch lower(action) + + case 'init' + + initCppBids(verbose); + + case 'uninit' + + uninitCppBids(); + + case 'run_tests' + + runTests(); + + end + +end + +function initCppBids(verbose) + % + % Adds the relevant folders to the path for a given session. + % Has to be run to be able to use CPP_BIDS. + % + % USAGE:: + % + % initCppPtb() + % + % (C) Copyright 2022 CPP_BIDS developers + + thisDirectory = fileparts(mfilename('fullpath')); + + global CPP_BIDS_INITIALIZED + global CPP_BIDS_PATHS + + if isempty(CPP_BIDS_INITIALIZED) + + pathSep = ':'; + if ~isunix + pathSep = ';'; + end + + CPP_BIDS_PATHS = fullfile(thisDirectory); + CPP_BIDS_PATHS = cat(2, CPP_BIDS_PATHS, ... + pathSep, ... + genpath(fullfile(thisDirectory, 'src'))); + assert(isdir(fullfile(thisDirectory, 'lib', 'bids-matlab', '+bids'))); + CPP_BIDS_PATHS = cat(2, CPP_BIDS_PATHS, pathSep, ... + fullfile(thisDirectory, 'lib', 'bids-matlab')); + assert(isdir(fullfile(thisDirectory, 'lib', 'JSONio'))); + CPP_BIDS_PATHS = cat(2, CPP_BIDS_PATHS, pathSep, ... + fullfile(thisDirectory, 'lib', 'JSONio')); + + addpath(CPP_BIDS_PATHS, '-begin'); + + CPP_BIDS_INITIALIZED = true(); + + detectCppBids(); + + if verbose + printCreditsCppBids(); + end + + else + if verbose + fprintf('\n\nCPP_BIDS already initialized\n\n'); + end + + end + +end + +function detectCppBids() + + workflowsDir = cellstr(which('saveEventsFile.m', '-ALL')); + + if isempty(workflowsDir) + error('CPP_BIDS is not in your MATLAB / Octave path.\n'); + + elseif numel(workflowsDir) > 1 + fprintf('CPP_BIDS seems to appear in several different folders:\n'); + for i = 1:numel(workflowsDir) + fprintf(' * %s\n', fullfile(workflowsDir{i}, '..', '..')); + end + error('Remove all but one with ''pathtool'' .\n'); % or ''spm_rmpath + + end +end + +function uninitCppBids() + % + % Removes the added folders from the path for a given session. + % + % USAGE:: + % + % uninitCppPtb() + % + % (C) Copyright 2021 CPP_BIDS developers + + global CPP_BIDS_INITIALIZED + global CPP_BIDS_PATHS + + if isempty(CPP_BIDS_INITIALIZED) || ~CPP_BIDS_INITIALIZED + fprintf('\n\nCPP_BIDS not initialized\n\n'); + return + + else + rmpath(CPP_BIDS_PATHS); + + if isOctave + clear -g; + else + clearvars -GLOBAL; + end + + end + +end + +function retval = isOctave() + % + % Returns true if the environment is Octave. + % + % USAGE:: + % + % retval = isOctave() + % + % :returns: :retval: (boolean) + % + % (C) Copyright 2020 Agah Karakuzu + % (C) Copyright 2022 CPP_BIDS developers + + persistent cacheval % speeds up repeated calls + + if isempty (cacheval) + cacheval = (exist ('OCTAVE_VERSION', 'builtin') > 0); + end + + retval = cacheval; +end diff --git a/docs/source/conf.py b/docs/source/conf.py index 1e7b4ec9..a8f6c34a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -12,17 +12,19 @@ # import os import sys -sys.path.insert(0, os.path.abspath('../..')) + +sys.path.insert(0, os.path.abspath("../..")) # -- Project information ----------------------------------------------------- -project = 'CPP BIDS' -copyright = '2020, the CPP BIDS dev team' -author = 'the CPP BIDS dev team' +project = "CPP BIDS" +copyright = "2020, the CPP BIDS dev team" +author = "the CPP BIDS dev team" # The full version, including alpha/beta/rc tags -release = 'v2.1.2dev' +with open("../../version.txt", encoding="utf-8") as version_file: + release = version_file.read() # -- General configuration --------------------------------------------------- @@ -31,13 +33,16 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinxcontrib.matlab', - 'sphinx.ext.autodoc'] -matlab_src_dir = os.path.dirname(os.path.abspath('../../src')) -primary_domain = 'mat' + "sphinxcontrib.matlab", + "sphinx.ext.autodoc", + "myst_parser", + "sphinx_copybutton", +] +matlab_src_dir = os.path.dirname(os.path.abspath("../../src")) +primary_domain = "mat" # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -45,13 +50,13 @@ exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # The master toctree document. -master_doc = 'index' +master_doc = "index" # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # -- Options for HTML output ------------------------------------------------- @@ -59,14 +64,14 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] -html_logo = '_static/cpp_lab_logo.png' +html_logo = "_static/cpp_lab_logo.png" # html_theme_options = { # 'github_user': 'cpp-lln-lab', @@ -81,11 +86,11 @@ # } html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - 'donate.html', + "**": [ + "about.html", + "navigation.html", + "relations.html", # needs 'show_related': True theme option to display + "searchbox.html", + "donate.html", ] } diff --git a/lib/bids-matlab b/lib/bids-matlab index 5d020cdb..5ee025ce 160000 --- a/lib/bids-matlab +++ b/lib/bids-matlab @@ -1 +1 @@ -Subproject commit 5d020cdba87f80116cf6c3b15d713b5b45513e4d +Subproject commit 5ee025ce38faec001c08b21549d7643f70f810f2 diff --git a/miss_hit.cfg b/miss_hit.cfg index f1d57c50..fb999aaa 100644 --- a/miss_hit.cfg +++ b/miss_hit.cfg @@ -2,7 +2,7 @@ project_root line_length: 100 -regex_function_name: "[a-z]+(([A-Z]){1}[A-Za-z]+)*" +regex_function_name: "[a-z]+(_*[a-zA-Z0-9]+[a-z]*)*" regex_parameter_name: "[a-z0-9]+(([A-Z]){1}[A-Za-z]+)*" exclude_dir: "lib" diff --git a/requirements.txt b/requirements.txt index 258f423e..54ae83ad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,11 @@ Sphinx sphinxcontrib-matlabdomain sphinxcontrib-napoleon sphinx_rtd_theme +myst-parser +sphinx-copybutton + miss_hit==0.9.29 +pre-commit + notebook octave_kernel diff --git a/runTests.m b/runTests.m index 3639e3e6..575d87f4 100644 --- a/runTests.m +++ b/runTests.m @@ -11,7 +11,8 @@ function runTests() cd(thisPath); fprintf('\nHome is %s\n', getenv('HOME')); - warning('OFF'); + warning off; + more off; addpath(fullfile(thisPath, 'lib', 'JSONio')); addpath(fullfile(thisPath, 'lib', 'bids-matlab')); diff --git a/src/checkCFG.m b/src/checkCFG.m index 337bbb81..6978566a 100644 --- a/src/checkCFG.m +++ b/src/checkCFG.m @@ -188,7 +188,7 @@ checkCppBidsDependencies(cfg); - fieldsToSet.verbose = 0; + fieldsToSet.verbose = false; fieldsToSet.useGUI = false; diff --git a/src/miss_hit.cfg b/src/miss_hit.cfg new file mode 100644 index 00000000..60146889 --- /dev/null +++ b/src/miss_hit.cfg @@ -0,0 +1,2 @@ +# camelCase +regex_function_name: "[a-z]+([A-Z0-9]+[a-z]*)*" diff --git a/src/utils/getVersion.m b/src/utils/getVersion.m new file mode 100644 index 00000000..6e1e0e25 --- /dev/null +++ b/src/utils/getVersion.m @@ -0,0 +1,25 @@ +function versionNumber = getVersion() + % + % Reads the version number of the pipeline from the txt file in the root of the + % repository. + % + % USAGE:: + % + % versionNumber = getVersion() + % + % :returns: :versionNumber: (string) Use semantic versioning format (like v0.1.0) + % + % (C) Copyright 2022 CPP_BIDS developers + + try + versionNumber = fileread(fullfile(fileparts(mfilename('fullpath')), ... + '..', '..', 'version.txt')); + catch + + versionNumber = 'v2.1.2dev '; + + end + + % dirty hack to get rid of line return + versionNumber = versionNumber(1:end - 1); +end diff --git a/src/utils/printCreditsCppBids.m b/src/utils/printCreditsCppBids.m index c11f9aa5..3856482f 100644 --- a/src/utils/printCreditsCppBids.m +++ b/src/utils/printCreditsCppBids.m @@ -12,25 +12,30 @@ function printCreditsCppBids(cfg) % % (C) Copyright 2020 CPP_BIDS developers - try - version = fileread(fullfile(fileparts(mfilename('fullpath')), ... - '..', '..', 'version.txt')); - catch - version = 'v1.0.0'; - end + version = getVersion(); verbose = 2; - if ~isempty(cfg) && isfield(cfg, 'verbose') && ~isempty(cfg.verbose) + if nargin > 0 && ~isempty(cfg) && isfield(cfg, 'verbose') && ~isempty(cfg.verbose) verbose = cfg.verbose; end - if verbose > 1 + try + + content = bids.util.jsondecode(fullfile(returnRootDir(), '.all-contributorsrc')); + contributors = {content.contributors.name}'; + contributors = contributors(randperm(numel(contributors))); + contributors = cat(1, contributors, 'Why not be the next?'); - contributors = { ... - 'Remi Gau', ... - 'Marco Barilari', ... - 'Ceren Battal', ... - 'Tomas Lenc'}; + catch + + contributors = {'Remi Gau', ... + 'Marco Barilari', ... + 'Ceren Battal', ... + 'Tomas Lenc', ... + 'Iqra Shahzad'}; + end + + if verbose > 1 DOI_URL = 'https://doi.org/10.5281/zenodo.4007674'; diff --git a/src/utils/returnRootDir.m b/src/utils/returnRootDir.m new file mode 100644 index 00000000..3cdfe562 --- /dev/null +++ b/src/utils/returnRootDir.m @@ -0,0 +1,37 @@ +function rootDir = returnRootDir() + % + % USAGE:: + % + % rootDir = returnRootDir() + % + % (C) Copyright 2022 CPP_BIDS developers + + Mfile = 'cpp_bids.m'; + rootDir = cellstr(which(Mfile, '-ALL')); + + % convert to absolute paths and keep unique ones + for i = 1:numel(rootDir) + rootDir{i} = spm_file(fullfile(fileparts(rootDir{i})), 'cpath'); + end + + rootDir = unique(rootDir); + + if isempty(rootDir) + err.message = 'CPP_BIDS is not in your MATLAB / Octave path.\n'; + err.identifier = 'CPP_BIDS:CppBidsNotInPath'; + error(err); + + elseif numel(rootDir) > 1 + fprintf('CPP_BIDS seems to appear in several different folders:\n'); + for i = 1:numel(rootDir) + fprintf(' * %s\n', fullfile(rootDir{i}, '..', '..')); + end + err.message = 'Remove all but one with ''pathtool''.\n'; % or ''spm_rmpath + err.identifier = 'CPP_BIDS:SeveralCppSpmInPath'; + error(err); + + end + + rootDir = rootDir{1}; + +end diff --git a/tests/test_checkCFG.m b/tests/test_checkCFG.m index 80cf37e2..6745be89 100644 --- a/tests/test_checkCFG.m +++ b/tests/test_checkCFG.m @@ -12,7 +12,7 @@ function test_checkCfgDefault() %% set up cfg.dir.output = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - cfg.verbose = 0; + cfg.verbose = false; cfg = checkCFG(cfg); %% create test data @@ -32,7 +32,7 @@ function test_checkCfgBasic() %% set up outputDir = fullfile(fileparts(mfilename('fullpath')), '..', 'output'); - cfg.verbose = 0; + cfg.verbose = false; cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; @@ -109,7 +109,7 @@ function test_checkCfgBasic() expected.subject.subjectNb = []; expected.subject.ask = {'grp'; 'ses'; 'run'}; - expected.verbose = 0; + expected.verbose = false; expected.useGUI = false; diff --git a/tests/test_utils.m b/tests/test_utils.m deleted file mode 100644 index 2dc86ee2..00000000 --- a/tests/test_utils.m +++ /dev/null @@ -1,19 +0,0 @@ -% (C) Copyright 2020 CPP_BIDS developers - -function test_suite = test_utils %#ok<*STOUT> - try % assignment of 'localfunctions' is necessary in Matlab >= 2016 - test_functions = localfunctions(); %#ok<*NASGU> - catch % no problem; early Matlab versions can use initTestSuite fine - end - initTestSuite; -end - -function test_utilsBasic() - - cfg.verbose = true; - - printCreditsCppBids(cfg); - - checkCppBidsDependencies(cfg); - -end diff --git a/tests/utils/globalTestSetUp.m b/tests/utils/globalTestSetUp.m index 24b1d264..476d84bf 100644 --- a/tests/utils/globalTestSetUp.m +++ b/tests/utils/globalTestSetUp.m @@ -2,7 +2,7 @@ % % (C) Copyright 2020 CPP_BIDS developers - cfg.verbose = 0; + cfg.verbose = false; cfg.subject.subjectNb = 1; cfg.subject.runNb = 1; cfg.task.name = 'test task';