diff --git a/mriqc/cli/parser.py b/mriqc/cli/parser.py index e20040f6..349dcfab 100644 --- a/mriqc/cli/parser.py +++ b/mriqc/cli/parser.py @@ -172,6 +172,12 @@ def _bids_filter(value): help="A space delimited list of participant identifiers or a single " "identifier (the sub- prefix can be removed).", ) + g_bids.add_argument( + '--bids-filter-file', action='store', type=Path, metavar='PATH', + help='a JSON file describing custom BIDS input filter using pybids ' + '{:{:,...},...} ' + '(https://github.com/bids-standard/pybids/blob/master/bids/layout/config/bids.json)' + ) g_bids.add_argument( "--session-id", action="store", @@ -184,7 +190,7 @@ def _bids_filter(value): action="store", type=int, nargs="*", - help="Filter input dataset by run ID (only integer run IDs are valid).", + help="DEPRECATED - This argument will be disabled. Use ``--bids-filter-file`` instead.", ) g_bids.add_argument( "--task-id", @@ -447,6 +453,8 @@ def parse_args(args=None, namespace=None): """Parse args and run further checks on the command line.""" from logging import DEBUG from contextlib import suppress + from json import loads + from pprint import pformat from niworkflows.utils.bids import collect_data, DEFAULT_BIDS_QUERIES @@ -469,6 +477,10 @@ def parse_args(args=None, namespace=None): "nprocs", config.nipype.nprocs ) + # Load BIDS filters + if opts.bids_filter_file: + config.execution.bids_filters = loads(opts.bids_filter_file.read_text()) + bids_dir = config.execution.bids_dir output_dir = config.execution.output_dir work_dir = config.execution.work_dir @@ -521,20 +533,13 @@ def parse_args(args=None, namespace=None): # List of files to be run lc_modalities = [mod.lower() for mod in config.execution.modalities] - - bids_filters = ( - {mod: {"run": config.execution.run_id} for mod in lc_modalities} - if config.execution.run_id - else {} - ) - bids_dataset, _ = collect_data( config.execution.layout, config.execution.participant_label, session_id=config.execution.session_id, task=config.execution.task_id, group_echos=False, - bids_filters=bids_filters, + bids_filters=config.execution.bids_filters, queries={mod: DEFAULT_BIDS_QUERIES[mod] for mod in lc_modalities} ) @@ -546,12 +551,15 @@ def parse_args(args=None, namespace=None): # Check the query is not empty if not list(config.workflow.inputs.values()): - _j = "\n *" + ffile = ( + "(--bids-filter-file was not set)" if not opts.bids_filter_file + else f"(with '--bids-filter-file {opts.bids_filter_file}')" + ) parser.error( f"""\ Querying BIDS dataset at <{config.execution.bids_dir}> got an empty result. -Please, check out your currently set filters: -{_j.join([''] + [': '.join((k, str(v))) for k, v in bids_filters.items()])}""" +Please, check out your currently set filters {ffile}: +{pformat(config.execution.bids_filters, indent=2, width=99)}""" ) # Check no DWI or others are sneaked into MRIQC diff --git a/mriqc/config.py b/mriqc/config.py index 8f313f61..fe13c37e 100644 --- a/mriqc/config.py +++ b/mriqc/config.py @@ -361,6 +361,8 @@ class execution(_Config): """Wipe out previously existing BIDS indexing caches, forcing re-indexing.""" bids_description_hash = None """Checksum (SHA256) of the ``dataset_description.json`` of the BIDS dataset.""" + bids_filters = None + """A dictionary describing custom BIDS input filter using PyBIDS.""" cwd = os.getcwd() """Current working directory.""" debug = False @@ -436,6 +438,15 @@ class execution(_Config): @classmethod def init(cls): """Create a new BIDS Layout accessible with :attr:`~execution.layout`.""" + + if cls.bids_filters is None: + cls.bids_filters = {} + + # Process --run-id if the argument was provided + if cls.run_id: + for mod in cls.modalities: + cls.bids_filters.setdefault(mod.lower(), {})["run"] = cls.run_id + if cls._layout is None: import re from bids.layout.index import BIDSLayoutIndexer