We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add command line option for deriv_root
As I develop a Docker App using mne-bids-pipeline, I want a straightforward way to overwrite the bids_root and deriv_root values defined in the configuration file from the command line. This enhancement aims to simplify Docker volume mapping.

Currently, the option to override `bids_root `is already available ([source](https://github.com/mne-tools/mne-bids-pipeline/blob/ea95979fdb0ef807b3cd262da409cf010ada3da3/mne_bids_pipeline/_main.py#L56)), but there is no similar option for `deriv_root`.

I suggest adding a command-line option to the mne-bids-pipeline tool to allow users to specify the deriv_root directory. This behavior is similar to other BidsApps such as `FMRIprep `and `MRIQC`, where command line arguments overwrite configuration files.

If you are interested, I would be happy to contribute by taking care of the pull request.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mne_bids_pipeline/_main.py`
Content:
```
1 import argparse
2 import pathlib
3 from textwrap import dedent
4 import time
5 from typing import List
6 from types import ModuleType, SimpleNamespace
7 
8 import numpy as np
9 
10 from ._config_utils import _get_step_modules
11 from ._config_import import _import_config
12 from ._config_template import create_template_config
13 from ._logging import logger, gen_log_kwargs
14 from ._parallel import get_parallel_backend
15 from ._run import _short_step_path
16 
17 
18 def main():
19     from . import __version__
20 
21     parser = argparse.ArgumentParser()
22     parser.add_argument(
23         "--version", action="version", version=f"%(prog)s {__version__}"
24     )
25     parser.add_argument("config", nargs="?", default=None)
26     parser.add_argument(
27         "--config",
28         dest="config_switch",
29         default=None,
30         metavar="FILE",
31         help="The path of the pipeline configuration file to use.",
32     )
33     parser.add_argument(
34         "--create-config",
35         dest="create_config",
36         default=None,
37         metavar="FILE",
38         help="Create a template configuration file with the specified name. "
39         "If specified, all other parameters will be ignored.",
40     ),
41     parser.add_argument(
42         "--steps",
43         dest="steps",
44         default="all",
45         help=dedent(
46             """\
47         The processing steps to run.
48         Can either be one of the processing groups 'preprocessing', sensor',
49         'source', 'report',  or 'all',  or the name of a processing group plus
50         the desired step sans the step number and
51         filename extension, separated by a '/'. For example, to run ICA, you
52         would pass 'sensor/run_ica`. If unspecified, will run all processing
53         steps. Can also be a tuple of steps."""
54         ),
55     )
56     parser.add_argument(
57         "--root-dir",
58         dest="root_dir",
59         default=None,
60         help="BIDS root directory of the data to process.",
61     )
62     parser.add_argument(
63         "--subject", dest="subject", default=None, help="The subject to process."
64     )
65     parser.add_argument(
66         "--session", dest="session", default=None, help="The session to process."
67     )
68     parser.add_argument(
69         "--task", dest="task", default=None, help="The task to process."
70     )
71     parser.add_argument("--run", dest="run", default=None, help="The run to process.")
72     parser.add_argument(
73         "--n_jobs",
74         dest="n_jobs",
75         type=int,
76         default=None,
77         help="The number of parallel processes to execute.",
78     )
79     parser.add_argument(
80         "--interactive",
81         dest="interactive",
82         action="store_true",
83         help="Enable interactive mode.",
84     )
85     parser.add_argument(
86         "--debug", dest="debug", action="store_true", help="Enable debugging on error."
87     )
88     parser.add_argument(
89         "--no-cache",
90         dest="no_cache",
91         action="store_true",
92         help="Disable caching of intermediate results.",
93     )
94     options = parser.parse_args()
95 
96     if options.create_config is not None:
97         target_path = pathlib.Path(options.create_config)
98         create_template_config(target_path=target_path, overwrite=False)
99         return
100 
101     config = options.config
102     config_switch = options.config_switch
103     bad = False
104     if config is None:
105         if config_switch is None:
106             bad = "neither was provided"
107         else:
108             config = config_switch
109     elif config_switch is not None:
110         bad = "both were provided"
111     if bad:
112         parser.error(
113             "❌ You must specify a configuration file either as a single "
114             f"argument or with --config, but {bad}."
115         )
116     steps = options.steps
117     root_dir = options.root_dir
118     subject, session = options.subject, options.session
119     task, run = options.task, options.run
120     n_jobs = options.n_jobs
121     interactive, debug = options.interactive, options.debug
122     cache = not options.no_cache
123 
124     if isinstance(steps, str) and "," in steps:
125         # Work around limitation in Fire: --steps=foo,bar/baz won't produce a
126         # tuple ('foo', 'bar/baz'), but a string 'foo,bar/baz'.
127         steps = tuple(steps.split(","))
128     elif isinstance(steps, str):
129         steps = (steps,)
130 
131     on_error = "debug" if debug else None
132     cache = "1" if cache else "0"
133 
134     processing_stages = []
135     processing_steps = []
136     for steps_ in steps:
137         if "/" in steps_:
138             stage, step = steps_.split("/")
139             processing_stages.append(stage)
140             processing_steps.append(step)
141         else:
142             # User specified "sensor", "preprocessing" or similar, but without
143             # any further grouping.
144             processing_stages.append(steps_)
145             processing_steps.append(None)
146 
147     config_path = pathlib.Path(config).expanduser().resolve(strict=True)
148     overrides = SimpleNamespace()
149     if root_dir:
150         overrides.bids_root = pathlib.Path(root_dir).expanduser().resolve(strict=True)
151     if subject:
152         overrides.subjects = [subject]
153     if session:
154         overrides.sessions = [session]
155     if task:
156         overrides.task = task
157     if run:
158         overrides.runs = run
159     if interactive:
160         overrides.interactive = interactive
161     if n_jobs:
162         overrides.n_jobs = int(n_jobs)
163     if on_error:
164         overrides.on_error = on_error
165     if not cache:
166         overrides.memory_location = False
167 
168     step_modules: List[ModuleType] = []
169     STEP_MODULES = _get_step_modules()
170     for stage, step in zip(processing_stages, processing_steps):
171         if stage not in STEP_MODULES.keys():
172             raise ValueError(
173                 f"Invalid step requested: '{stage}'. "
174                 f"It should be one of {list(STEP_MODULES.keys())}."
175             )
176 
177         if step is None:
178             # User specified `sensors`, `source`, or similar
179             step_modules.extend(STEP_MODULES[stage])
180         else:
181             # User specified 'stage/step'
182             for step_module in STEP_MODULES[stage]:
183                 step_name = pathlib.Path(step_module.__file__).name
184                 if step in step_name:
185                     step_modules.append(step_module)
186                     break
187             else:
188                 # We've iterated over all steps, but none matched!
189                 raise ValueError(f"Invalid steps requested: {stage}/{step}")
190 
191     if processing_stages[0] != "all":
192         # Always run the directory initialization steps, but skip for 'all',
193         # because it already includes them – and we want to avoid running
194         # them twice.
195         step_modules = [*STEP_MODULES["init"], *step_modules]
196 
197     logger.title("Welcome aboard MNE-BIDS-Pipeline! 👋")
198     msg = f"Using configuration: {config}"
199     __mne_bids_pipeline_step__ = pathlib.Path(__file__)  # used for logging
200     logger.info(**gen_log_kwargs(message=msg, emoji="📝"))
201     config_imported = _import_config(
202         config_path=config_path,
203         overrides=overrides,
204     )
205     # Initialize dask now
206     with get_parallel_backend(config_imported.exec_params):
207         pass
208     del __mne_bids_pipeline_step__
209     logger.end()
210 
211     for step_module in step_modules:
212         start = time.time()
213         step = _short_step_path(pathlib.Path(step_module.__file__))
214         logger.title(title=f"{step}")
215         step_module.main(config=config_imported)
216         elapsed = time.time() - start
217         hours, remainder = divmod(elapsed, 3600)
218         hours = int(hours)
219         minutes, seconds = divmod(remainder, 60)
220         minutes = int(minutes)
221         seconds = int(np.ceil(seconds))  # always take full seconds
222         elapsed = f"{seconds}s"
223         if minutes:
224             elapsed = f"{minutes}m {elapsed}"
225         if hours:
226             elapsed = f"{hours}h {elapsed}"
227         logger.end(f"done ({elapsed})")
228
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mne_bids_pipeline/_main.py b/mne_bids_pipeline/_main.py
--- a/mne_bids_pipeline/_main.py
+++ b/mne_bids_pipeline/_main.py
@@ -59,6 +59,18 @@
         default=None,
         help="BIDS root directory of the data to process.",
     )
+    parser.add_argument(
+        "--deriv_root",
+        dest="deriv_root",
+        default=None,
+        help=dedent(
+            """\
+        The root of the derivatives directory
+        in which the pipeline will store the processing results.
+        If unspecified, this will be derivatives/mne-bids-pipeline
+        inside the BIDS root."""
+        ),
+    ),
     parser.add_argument(
         "--subject", dest="subject", default=None, help="The subject to process."
     )
@@ -115,6 +127,7 @@
         )
     steps = options.steps
     root_dir = options.root_dir
+    deriv_root = options.deriv_root
     subject, session = options.subject, options.session
     task, run = options.task, options.run
     n_jobs = options.n_jobs
@@ -148,6 +161,10 @@
     overrides = SimpleNamespace()
     if root_dir:
         overrides.bids_root = pathlib.Path(root_dir).expanduser().resolve(strict=True)
+    if deriv_root:
+        overrides.deriv_root = (
+            pathlib.Path(deriv_root).expanduser().resolve(strict=False)
+        )
     if subject:
         overrides.subjects = [subject]
     if session:

{"golden_diff": "diff --git a/mne_bids_pipeline/_main.py b/mne_bids_pipeline/_main.py\n--- a/mne_bids_pipeline/_main.py\n+++ b/mne_bids_pipeline/_main.py\n@@ -59,6 +59,18 @@\n         default=None,\n         help=\"BIDS root directory of the data to process.\",\n     )\n+    parser.add_argument(\n+        \"--deriv_root\",\n+        dest=\"deriv_root\",\n+        default=None,\n+        help=dedent(\n+            \"\"\"\\\n+        The root of the derivatives directory\n+        in which the pipeline will store the processing results.\n+        If unspecified, this will be derivatives/mne-bids-pipeline\n+        inside the BIDS root.\"\"\"\n+        ),\n+    ),\n     parser.add_argument(\n         \"--subject\", dest=\"subject\", default=None, help=\"The subject to process.\"\n     )\n@@ -115,6 +127,7 @@\n         )\n     steps = options.steps\n     root_dir = options.root_dir\n+    deriv_root = options.deriv_root\n     subject, session = options.subject, options.session\n     task, run = options.task, options.run\n     n_jobs = options.n_jobs\n@@ -148,6 +161,10 @@\n     overrides = SimpleNamespace()\n     if root_dir:\n         overrides.bids_root = pathlib.Path(root_dir).expanduser().resolve(strict=True)\n+    if deriv_root:\n+        overrides.deriv_root = (\n+            pathlib.Path(deriv_root).expanduser().resolve(strict=False)\n+        )\n     if subject:\n         overrides.subjects = [subject]\n     if session:\n", "issue": "Add command line option for deriv_root\nAs I develop a Docker App using mne-bids-pipeline, I want a straightforward way to overwrite the bids_root and deriv_root values defined in the configuration file from the command line. This enhancement aims to simplify Docker volume mapping.\r\n\r\nCurrently, the option to override `bids_root `is already available ([source](https://github.com/mne-tools/mne-bids-pipeline/blob/ea95979fdb0ef807b3cd262da409cf010ada3da3/mne_bids_pipeline/_main.py#L56)), but there is no similar option for `deriv_root`.\r\n\r\nI suggest adding a command-line option to the mne-bids-pipeline tool to allow users to specify the deriv_root directory. This behavior is similar to other BidsApps such as `FMRIprep `and `MRIQC`, where command line arguments overwrite configuration files.\r\n\r\nIf you are interested, I would be happy to contribute by taking care of the pull request.\n", "before_files": [{"content": "import argparse\nimport pathlib\nfrom textwrap import dedent\nimport time\nfrom typing import List\nfrom types import ModuleType, SimpleNamespace\n\nimport numpy as np\n\nfrom ._config_utils import _get_step_modules\nfrom ._config_import import _import_config\nfrom ._config_template import create_template_config\nfrom ._logging import logger, gen_log_kwargs\nfrom ._parallel import get_parallel_backend\nfrom ._run import _short_step_path\n\n\ndef main():\n    from . import __version__\n\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"--version\", action=\"version\", version=f\"%(prog)s {__version__}\"\n    )\n    parser.add_argument(\"config\", nargs=\"?\", default=None)\n    parser.add_argument(\n        \"--config\",\n        dest=\"config_switch\",\n        default=None,\n        metavar=\"FILE\",\n        help=\"The path of the pipeline configuration file to use.\",\n    )\n    parser.add_argument(\n        \"--create-config\",\n        dest=\"create_config\",\n        default=None,\n        metavar=\"FILE\",\n        help=\"Create a template configuration file with the specified name. \"\n        \"If specified, all other parameters will be ignored.\",\n    ),\n    parser.add_argument(\n        \"--steps\",\n        dest=\"steps\",\n        default=\"all\",\n        help=dedent(\n            \"\"\"\\\n        The processing steps to run.\n        Can either be one of the processing groups 'preprocessing', sensor',\n        'source', 'report',  or 'all',  or the name of a processing group plus\n        the desired step sans the step number and\n        filename extension, separated by a '/'. For example, to run ICA, you\n        would pass 'sensor/run_ica`. If unspecified, will run all processing\n        steps. Can also be a tuple of steps.\"\"\"\n        ),\n    )\n    parser.add_argument(\n        \"--root-dir\",\n        dest=\"root_dir\",\n        default=None,\n        help=\"BIDS root directory of the data to process.\",\n    )\n    parser.add_argument(\n        \"--subject\", dest=\"subject\", default=None, help=\"The subject to process.\"\n    )\n    parser.add_argument(\n        \"--session\", dest=\"session\", default=None, help=\"The session to process.\"\n    )\n    parser.add_argument(\n        \"--task\", dest=\"task\", default=None, help=\"The task to process.\"\n    )\n    parser.add_argument(\"--run\", dest=\"run\", default=None, help=\"The run to process.\")\n    parser.add_argument(\n        \"--n_jobs\",\n        dest=\"n_jobs\",\n        type=int,\n        default=None,\n        help=\"The number of parallel processes to execute.\",\n    )\n    parser.add_argument(\n        \"--interactive\",\n        dest=\"interactive\",\n        action=\"store_true\",\n        help=\"Enable interactive mode.\",\n    )\n    parser.add_argument(\n        \"--debug\", dest=\"debug\", action=\"store_true\", help=\"Enable debugging on error.\"\n    )\n    parser.add_argument(\n        \"--no-cache\",\n        dest=\"no_cache\",\n        action=\"store_true\",\n        help=\"Disable caching of intermediate results.\",\n    )\n    options = parser.parse_args()\n\n    if options.create_config is not None:\n        target_path = pathlib.Path(options.create_config)\n        create_template_config(target_path=target_path, overwrite=False)\n        return\n\n    config = options.config\n    config_switch = options.config_switch\n    bad = False\n    if config is None:\n        if config_switch is None:\n            bad = \"neither was provided\"\n        else:\n            config = config_switch\n    elif config_switch is not None:\n        bad = \"both were provided\"\n    if bad:\n        parser.error(\n            \"\u274c You must specify a configuration file either as a single \"\n            f\"argument or with --config, but {bad}.\"\n        )\n    steps = options.steps\n    root_dir = options.root_dir\n    subject, session = options.subject, options.session\n    task, run = options.task, options.run\n    n_jobs = options.n_jobs\n    interactive, debug = options.interactive, options.debug\n    cache = not options.no_cache\n\n    if isinstance(steps, str) and \",\" in steps:\n        # Work around limitation in Fire: --steps=foo,bar/baz won't produce a\n        # tuple ('foo', 'bar/baz'), but a string 'foo,bar/baz'.\n        steps = tuple(steps.split(\",\"))\n    elif isinstance(steps, str):\n        steps = (steps,)\n\n    on_error = \"debug\" if debug else None\n    cache = \"1\" if cache else \"0\"\n\n    processing_stages = []\n    processing_steps = []\n    for steps_ in steps:\n        if \"/\" in steps_:\n            stage, step = steps_.split(\"/\")\n            processing_stages.append(stage)\n            processing_steps.append(step)\n        else:\n            # User specified \"sensor\", \"preprocessing\" or similar, but without\n            # any further grouping.\n            processing_stages.append(steps_)\n            processing_steps.append(None)\n\n    config_path = pathlib.Path(config).expanduser().resolve(strict=True)\n    overrides = SimpleNamespace()\n    if root_dir:\n        overrides.bids_root = pathlib.Path(root_dir).expanduser().resolve(strict=True)\n    if subject:\n        overrides.subjects = [subject]\n    if session:\n        overrides.sessions = [session]\n    if task:\n        overrides.task = task\n    if run:\n        overrides.runs = run\n    if interactive:\n        overrides.interactive = interactive\n    if n_jobs:\n        overrides.n_jobs = int(n_jobs)\n    if on_error:\n        overrides.on_error = on_error\n    if not cache:\n        overrides.memory_location = False\n\n    step_modules: List[ModuleType] = []\n    STEP_MODULES = _get_step_modules()\n    for stage, step in zip(processing_stages, processing_steps):\n        if stage not in STEP_MODULES.keys():\n            raise ValueError(\n                f\"Invalid step requested: '{stage}'. \"\n                f\"It should be one of {list(STEP_MODULES.keys())}.\"\n            )\n\n        if step is None:\n            # User specified `sensors`, `source`, or similar\n            step_modules.extend(STEP_MODULES[stage])\n        else:\n            # User specified 'stage/step'\n            for step_module in STEP_MODULES[stage]:\n                step_name = pathlib.Path(step_module.__file__).name\n                if step in step_name:\n                    step_modules.append(step_module)\n                    break\n            else:\n                # We've iterated over all steps, but none matched!\n                raise ValueError(f\"Invalid steps requested: {stage}/{step}\")\n\n    if processing_stages[0] != \"all\":\n        # Always run the directory initialization steps, but skip for 'all',\n        # because it already includes them \u2013 and we want to avoid running\n        # them twice.\n        step_modules = [*STEP_MODULES[\"init\"], *step_modules]\n\n    logger.title(\"Welcome aboard MNE-BIDS-Pipeline! \ud83d\udc4b\")\n    msg = f\"Using configuration: {config}\"\n    __mne_bids_pipeline_step__ = pathlib.Path(__file__)  # used for logging\n    logger.info(**gen_log_kwargs(message=msg, emoji=\"\ud83d\udcdd\"))\n    config_imported = _import_config(\n        config_path=config_path,\n        overrides=overrides,\n    )\n    # Initialize dask now\n    with get_parallel_backend(config_imported.exec_params):\n        pass\n    del __mne_bids_pipeline_step__\n    logger.end()\n\n    for step_module in step_modules:\n        start = time.time()\n        step = _short_step_path(pathlib.Path(step_module.__file__))\n        logger.title(title=f\"{step}\")\n        step_module.main(config=config_imported)\n        elapsed = time.time() - start\n        hours, remainder = divmod(elapsed, 3600)\n        hours = int(hours)\n        minutes, seconds = divmod(remainder, 60)\n        minutes = int(minutes)\n        seconds = int(np.ceil(seconds))  # always take full seconds\n        elapsed = f\"{seconds}s\"\n        if minutes:\n            elapsed = f\"{minutes}m {elapsed}\"\n        if hours:\n            elapsed = f\"{hours}h {elapsed}\"\n        logger.end(f\"done ({elapsed})\")\n", "path": "mne_bids_pipeline/_main.py"}], "after_files": [{"content": "import argparse\nimport pathlib\nfrom textwrap import dedent\nimport time\nfrom typing import List\nfrom types import ModuleType, SimpleNamespace\n\nimport numpy as np\n\nfrom ._config_utils import _get_step_modules\nfrom ._config_import import _import_config\nfrom ._config_template import create_template_config\nfrom ._logging import logger, gen_log_kwargs\nfrom ._parallel import get_parallel_backend\nfrom ._run import _short_step_path\n\n\ndef main():\n    from . import __version__\n\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"--version\", action=\"version\", version=f\"%(prog)s {__version__}\"\n    )\n    parser.add_argument(\"config\", nargs=\"?\", default=None)\n    parser.add_argument(\n        \"--config\",\n        dest=\"config_switch\",\n        default=None,\n        metavar=\"FILE\",\n        help=\"The path of the pipeline configuration file to use.\",\n    )\n    parser.add_argument(\n        \"--create-config\",\n        dest=\"create_config\",\n        default=None,\n        metavar=\"FILE\",\n        help=\"Create a template configuration file with the specified name. \"\n        \"If specified, all other parameters will be ignored.\",\n    ),\n    parser.add_argument(\n        \"--steps\",\n        dest=\"steps\",\n        default=\"all\",\n        help=dedent(\n            \"\"\"\\\n        The processing steps to run.\n        Can either be one of the processing groups 'preprocessing', sensor',\n        'source', 'report',  or 'all',  or the name of a processing group plus\n        the desired step sans the step number and\n        filename extension, separated by a '/'. For example, to run ICA, you\n        would pass 'sensor/run_ica`. If unspecified, will run all processing\n        steps. Can also be a tuple of steps.\"\"\"\n        ),\n    )\n    parser.add_argument(\n        \"--root-dir\",\n        dest=\"root_dir\",\n        default=None,\n        help=\"BIDS root directory of the data to process.\",\n    )\n    parser.add_argument(\n        \"--deriv_root\",\n        dest=\"deriv_root\",\n        default=None,\n        help=dedent(\n            \"\"\"\\\n        The root of the derivatives directory\n        in which the pipeline will store the processing results.\n        If unspecified, this will be derivatives/mne-bids-pipeline\n        inside the BIDS root.\"\"\"\n        ),\n    ),\n    parser.add_argument(\n        \"--subject\", dest=\"subject\", default=None, help=\"The subject to process.\"\n    )\n    parser.add_argument(\n        \"--session\", dest=\"session\", default=None, help=\"The session to process.\"\n    )\n    parser.add_argument(\n        \"--task\", dest=\"task\", default=None, help=\"The task to process.\"\n    )\n    parser.add_argument(\"--run\", dest=\"run\", default=None, help=\"The run to process.\")\n    parser.add_argument(\n        \"--n_jobs\",\n        dest=\"n_jobs\",\n        type=int,\n        default=None,\n        help=\"The number of parallel processes to execute.\",\n    )\n    parser.add_argument(\n        \"--interactive\",\n        dest=\"interactive\",\n        action=\"store_true\",\n        help=\"Enable interactive mode.\",\n    )\n    parser.add_argument(\n        \"--debug\", dest=\"debug\", action=\"store_true\", help=\"Enable debugging on error.\"\n    )\n    parser.add_argument(\n        \"--no-cache\",\n        dest=\"no_cache\",\n        action=\"store_true\",\n        help=\"Disable caching of intermediate results.\",\n    )\n    options = parser.parse_args()\n\n    if options.create_config is not None:\n        target_path = pathlib.Path(options.create_config)\n        create_template_config(target_path=target_path, overwrite=False)\n        return\n\n    config = options.config\n    config_switch = options.config_switch\n    bad = False\n    if config is None:\n        if config_switch is None:\n            bad = \"neither was provided\"\n        else:\n            config = config_switch\n    elif config_switch is not None:\n        bad = \"both were provided\"\n    if bad:\n        parser.error(\n            \"\u274c You must specify a configuration file either as a single \"\n            f\"argument or with --config, but {bad}.\"\n        )\n    steps = options.steps\n    root_dir = options.root_dir\n    deriv_root = options.deriv_root\n    subject, session = options.subject, options.session\n    task, run = options.task, options.run\n    n_jobs = options.n_jobs\n    interactive, debug = options.interactive, options.debug\n    cache = not options.no_cache\n\n    if isinstance(steps, str) and \",\" in steps:\n        # Work around limitation in Fire: --steps=foo,bar/baz won't produce a\n        # tuple ('foo', 'bar/baz'), but a string 'foo,bar/baz'.\n        steps = tuple(steps.split(\",\"))\n    elif isinstance(steps, str):\n        steps = (steps,)\n\n    on_error = \"debug\" if debug else None\n    cache = \"1\" if cache else \"0\"\n\n    processing_stages = []\n    processing_steps = []\n    for steps_ in steps:\n        if \"/\" in steps_:\n            stage, step = steps_.split(\"/\")\n            processing_stages.append(stage)\n            processing_steps.append(step)\n        else:\n            # User specified \"sensor\", \"preprocessing\" or similar, but without\n            # any further grouping.\n            processing_stages.append(steps_)\n            processing_steps.append(None)\n\n    config_path = pathlib.Path(config).expanduser().resolve(strict=True)\n    overrides = SimpleNamespace()\n    if root_dir:\n        overrides.bids_root = pathlib.Path(root_dir).expanduser().resolve(strict=True)\n    if deriv_root:\n        overrides.deriv_root = (\n            pathlib.Path(deriv_root).expanduser().resolve(strict=False)\n        )\n    if subject:\n        overrides.subjects = [subject]\n    if session:\n        overrides.sessions = [session]\n    if task:\n        overrides.task = task\n    if run:\n        overrides.runs = run\n    if interactive:\n        overrides.interactive = interactive\n    if n_jobs:\n        overrides.n_jobs = int(n_jobs)\n    if on_error:\n        overrides.on_error = on_error\n    if not cache:\n        overrides.memory_location = False\n\n    step_modules: List[ModuleType] = []\n    STEP_MODULES = _get_step_modules()\n    for stage, step in zip(processing_stages, processing_steps):\n        if stage not in STEP_MODULES.keys():\n            raise ValueError(\n                f\"Invalid step requested: '{stage}'. \"\n                f\"It should be one of {list(STEP_MODULES.keys())}.\"\n            )\n\n        if step is None:\n            # User specified `sensors`, `source`, or similar\n            step_modules.extend(STEP_MODULES[stage])\n        else:\n            # User specified 'stage/step'\n            for step_module in STEP_MODULES[stage]:\n                step_name = pathlib.Path(step_module.__file__).name\n                if step in step_name:\n                    step_modules.append(step_module)\n                    break\n            else:\n                # We've iterated over all steps, but none matched!\n                raise ValueError(f\"Invalid steps requested: {stage}/{step}\")\n\n    if processing_stages[0] != \"all\":\n        # Always run the directory initialization steps, but skip for 'all',\n        # because it already includes them \u2013 and we want to avoid running\n        # them twice.\n        step_modules = [*STEP_MODULES[\"init\"], *step_modules]\n\n    logger.title(\"Welcome aboard MNE-BIDS-Pipeline! \ud83d\udc4b\")\n    msg = f\"Using configuration: {config}\"\n    __mne_bids_pipeline_step__ = pathlib.Path(__file__)  # used for logging\n    logger.info(**gen_log_kwargs(message=msg, emoji=\"\ud83d\udcdd\"))\n    config_imported = _import_config(\n        config_path=config_path,\n        overrides=overrides,\n    )\n    # Initialize dask now\n    with get_parallel_backend(config_imported.exec_params):\n        pass\n    del __mne_bids_pipeline_step__\n    logger.end()\n\n    for step_module in step_modules:\n        start = time.time()\n        step = _short_step_path(pathlib.Path(step_module.__file__))\n        logger.title(title=f\"{step}\")\n        step_module.main(config=config_imported)\n        elapsed = time.time() - start\n        hours, remainder = divmod(elapsed, 3600)\n        hours = int(hours)\n        minutes, seconds = divmod(remainder, 60)\n        minutes = int(minutes)\n        seconds = int(np.ceil(seconds))  # always take full seconds\n        elapsed = f\"{seconds}s\"\n        if minutes:\n            elapsed = f\"{minutes}m {elapsed}\"\n        if hours:\n            elapsed = f\"{hours}h {elapsed}\"\n        logger.end(f\"done ({elapsed})\")\n", "path": "mne_bids_pipeline/_main.py"}]}