From aee3749d68aaefcaa1685646cba8833f5862f197 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 13 Jun 2024 19:19:39 -0400 Subject: [PATCH 01/40] update entities and auto entities validation --- dcm2bids/utils/utils.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/dcm2bids/utils/utils.py b/dcm2bids/utils/utils.py index fd9426c1..a177799a 100644 --- a/dcm2bids/utils/utils.py +++ b/dcm2bids/utils/utils.py @@ -53,12 +53,27 @@ class DEFAULT(object): extractors = {} - auto_entities = {"anat_MEGRE": ["echo"], + auto_entities = {"anat_IRT1": ["inv"], + "anat_MEGRE": ["echo"], "anat_MESE": ["echo"], + "anat_MP2RAGE": ["inv"], + "anat_MPM": ["flip", "mt"], + "anat_MTS": ["flip", "mt"], + "anat_MTR": ["mt"], + "anat_VFA": ["flip"], "func_cbv": ["task"], "func_bold": ["task"], "func_sbref": ["task"], - "fmap_epi": ["dir"]} + "func_event": ["task"], + "func_stim": ["task"], + "func_phase": ["task"], + "fmap_epi": ["dir"], + "fmap_m0scan": ["dir"], + "fmap_TB1DAM": ["flip"], + "fmap_TB1EPI": ["echo", "flip"], + "fmap_TB1SRGE": ["echo", "inv"], + "perf_physio": ["task"], + "perf_stim": ["task"]} compKeys = ["AcquisitionTime", "SeriesNumber", "SidecarFilename"] search_methodChoices = ["fnmatch", "re"] @@ -70,10 +85,12 @@ class DEFAULT(object): case_sensitive = True # Entity table: - # https://bids-specification.readthedocs.io/en/v1.7.0/99-appendices/04-entity-table.html - entityTableKeys = ["sub", "ses", "task", "acq", "ce", "rec", "dir", - "run", "mod", "echo", "flip", "inv", "mt", "part", - "recording"] + # https://bids-specification.readthedocs.io/en/v1.9.0/99-appendices/04-entity-table.html + entityTableKeys = ["sub", "ses", "sample", "task", "tracksys", + "acq", "ce", "trc", "stain", "rec", "dir", + "run", "mod", "echo", "flip", "inv", "mt", + "part", "proc", "hemi", "space", "split", "recording", + "chunk", "seg", "res", "den", "label", "desc"] keyWithPathsidecar_changes = ['IntendedFor', 'Sources'] From c8339333c0ffae0d082dfaf4fcfa884b83379f8f Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Mon, 17 Jun 2024 16:59:19 -0400 Subject: [PATCH 02/40] Add docker, fix subprocess and update to bids 1.9.0 --- Dockerfile | 57 +++++++++++++++++++++++++++++++++++++++ dcm2bids/acquisition.py | 8 +++--- dcm2bids/dcm2bids_gen.py | 12 +++++---- dcm2bids/sidecar.py | 16 ++++++----- dcm2bids/utils/utils.py | 9 ++++--- docs/tutorial/parallel.md | 2 +- environment.yml | 9 +++++++ 7 files changed, 94 insertions(+), 19 deletions(-) create mode 100644 Dockerfile create mode 100644 environment.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5febda1f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,57 @@ +# Conda image for installing FSL tools +FROM continuumio/miniconda3 AS build + +# Install FSL tools with conda +COPY environment.yml /tmp/environment.yml +RUN conda env create -f /tmp/environment.yml + +# Install and use conda-pack +RUN conda install -c conda-forge conda-pack +RUN conda-pack -n fsl -o /tmp/env.tar && \ + mkdir /venv && cd /venv && tar xf /tmp/env.tar && \ + rm /tmp/env.tar +RUN /venv/bin/conda-unpack + +# Runtime image for executing FSL tools +FROM debian:stable AS runtime + +# Copy the conda env from previous stage +COPY --from=build /venv /venv + +# Point to conda executables +ENV PATH /venv/bin:$PATH + +# Set FSL variables +ENV FSLDIR="/venv" +ENV FSLCONFDIR="${FSLDIR}/config" +ENV FSLOUTPUTTYPE="NIFTI" +ENV FSLMULTIFILEQUIT="TRUE" +ENV FSLTCLSH="${FSLDIR}/bin/fsltclsh" +ENV FSLWISH="${FSLDIR}/bin/fslwish" +ENV FSLGECUDAQ="cuda.q" + +# Install dc fro FSL bet and wget for fetching data +RUN apt-get -y update && apt-get -y install dc wget npm unzip + +# Fetch data +RUN wget -P ${FSLDIR}/data https://git.fmrib.ox.ac.uk/fsl/data_standard/-/raw/master/MNI152_T1_1mm_brain.nii.gz + +# Install bids-validator +RUN npm install -g bids-validator + +# Install dcm2niix +WORKDIR / +RUN wget https://github.com/rordenlab/dcm2niix/releases/download/v1.0.20240202/dcm2niix_lnx.zip +RUN unzip dcm2niix_lnx.zip +RUN mv dcm2niix /usr/bin/ + +# Install dcm2bids + +WORKDIR / +ADD . /dcm2bids +WORKDIR /dcm2bids +RUN pip install -e . + +RUN pip install pydeface + +ENTRYPOINT [""] \ No newline at end of file diff --git a/dcm2bids/acquisition.py b/dcm2bids/acquisition.py index cba30c76..e4f6e50c 100644 --- a/dcm2bids/acquisition.py +++ b/dcm2bids/acquisition.py @@ -156,8 +156,8 @@ def setExtraDstFile(self, new_entities): """ Return: The destination filename formatted following - the v1.8.0 BIDS entity key table - https://bids-specification.readthedocs.io/en/v1.8.0/99-appendices/04-entity-table.html + the v1.9.0 BIDS entity key table + https://bids-specification.readthedocs.io/en/v1.9.0/99-appendices/04-entity-table.html """ if self.custom_entities.strip() == "": @@ -210,8 +210,8 @@ def setDstFile(self): """ Return: The destination filename formatted following - the v1.8.0 BIDS entity key table - https://bids-specification.readthedocs.io/en/v1.8.0/99-appendices/04-entity-table.html + the v1.9.0 BIDS entity key table + https://bids-specification.readthedocs.io/en/v1.9.0/99-appendices/04-entity-table.html """ current_name = self.participant.prefix + self.build_suffix new_name = '' diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index ae5e4065..7886999c 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -123,10 +123,11 @@ def run(self): if self.bids_validate: try: - self.logger.info(f"Validate if {self.output_dir} is BIDS valid.") - self.logger.info("Use bids-validator version: ") - run_shell_command(['bids-validator', '-v']) - run_shell_command(['bids-validator', self.bids_dir]) + self.logger.info(f"Validate if {self.bids_dir} is BIDS valid.") + bids_version = run_shell_command(['bids-validator', '-v']) + self.logger.info(f"Use bids-validator version: {bids_version.decode()}") + bids_report = run_shell_command(['bids-validator', self.bids_dir]) + self.logger.info(bids_report.decode()) except Exception: self.logger.error("The bids-validator does not seem to work properly. " "The bids-validator may not be installed on your " @@ -186,7 +187,8 @@ def move(self, acq, idList, post_op): else: cmd = cmd.replace('dst_file', str(dstFile)) - run_shell_command(cmd.split()) + std_out = run_shell_command(cmd.split()) + self.logger.debug(std_out.decode()) continue if ".json" in ext: diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index b0c344c0..da070933 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -427,6 +427,7 @@ def searchDcmTagEntity(self, sidecar, desc): """ descWithTask = desc.copy() concatenated_matches = {} + keys_custom_entities = [] entities = [] if "custom_entities" in desc.keys() or self.auto_extract_entities: if 'custom_entities' in desc.keys(): @@ -435,10 +436,12 @@ def searchDcmTagEntity(self, sidecar, desc): else: descWithTask["custom_entities"] = [] + keys_custom_entities = [curr_entity.split('-')[0] for curr_entity in descWithTask["custom_entities"]] + if self.auto_extract_entities: self.extractors = combine_dict_extractors(self.extractors, DEFAULT.auto_extractors) - + # Loop to check if we find self.extractor for dcmTag in self.extractors: if dcmTag in sidecar.data.keys(): dcmInfo = sidecar.data.get(dcmTag) @@ -447,29 +450,31 @@ def searchDcmTagEntity(self, sidecar, desc): if not isinstance(dcmInfo, list): if compile_regex.search(str(dcmInfo)) is not None: concatenated_matches.update( - compile_regex.search(str(dcmInfo)).groupdict()) + compile_regex.search(str(dcmInfo)).groupdict()) else: for curr_dcmInfo in dcmInfo: if compile_regex.search(curr_dcmInfo) is not None: concatenated_matches.update( - compile_regex.search(curr_dcmInfo).groupdict()) + compile_regex.search(curr_dcmInfo).groupdict()) break # Keep entities asked in custom_entities # If dir found in custom_entities and concatenated_matches.keys we keep it if "custom_entities" in desc.keys(): entities = set(concatenated_matches.keys()).intersection(set(descWithTask["custom_entities"])) - + # custom_entities not a key for extractor or auto_extract_entities complete_entities = [ent for ent in descWithTask["custom_entities"] if '-' in ent] entities = entities.union(set(complete_entities)) - if self.auto_extract_entities: auto_acq = '_'.join([descWithTask['datatype'], descWithTask["suffix"]]) if auto_acq in DEFAULT.auto_entities: # Check if these auto entities have been found before merging auto_entities = set(concatenated_matches.keys()).intersection(set(DEFAULT.auto_entities[auto_acq])) + left_auto_entities = auto_entities.symmetric_difference(set(DEFAULT.auto_entities[auto_acq])) + left_auto_entities = left_auto_entities.difference(keys_custom_entities) + if left_auto_entities: self.logger.warning(f"{left_auto_entities} have not been found for datatype '{descWithTask['datatype']}' " f"and suffix '{descWithTask['suffix']}'.") @@ -478,7 +483,6 @@ def searchDcmTagEntity(self, sidecar, desc): entities = list(set(entities)) descWithTask["custom_entities"] = entities - for curr_entity in entities: if curr_entity in concatenated_matches.keys(): if curr_entity == 'dir': diff --git a/dcm2bids/utils/utils.py b/dcm2bids/utils/utils.py index a177799a..b09bd2ea 100644 --- a/dcm2bids/utils/utils.py +++ b/dcm2bids/utils/utils.py @@ -5,7 +5,7 @@ import logging import os from pathlib import Path -from subprocess import check_output +from subprocess import check_output, Popen, PIPE class DEFAULT(object): @@ -99,7 +99,7 @@ class DEFAULT(object): helper_dir = "helper" # BIDS version - bids_version = "v1.8.0" + bids_version = "v1.9.0" def write_participants(filename, participants): @@ -145,8 +145,11 @@ def run_shell_command(commandLine, log=True): if log: logger = logging.getLogger(__name__) logger.info("Running: %s", " ".join(str(item) for item in commandLine)) - return check_output(commandLine) + pipes = Popen(commandLine, stdout=PIPE, stderr=PIPE) + std_out, std_err = pipes.communicate() + + return std_out def convert_dir(dir): """ Convert Direction diff --git a/docs/tutorial/parallel.md b/docs/tutorial/parallel.md index e8f68c58..f69d9b59 100644 --- a/docs/tutorial/parallel.md +++ b/docs/tutorial/parallel.md @@ -58,7 +58,7 @@ First thing first, let's make sure our software are usable. ```sh (dcm2bids) sam:~$ dcm2bids -v dcm2bids version: 3.1.0 - Based on BIDS version: v1.8.0 + Based on BIDS version: v1.9.0 (dcm2bids) sam:~$ parallel --version GNU parallel 20230722 Copyright (C) 2007-2023 Ole Tange, http://ole.tange.dk and Free Software diff --git a/environment.yml b/environment.yml new file mode 100644 index 00000000..82151bc5 --- /dev/null +++ b/environment.yml @@ -0,0 +1,9 @@ +name: fsl +channels: + - https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/ + - conda-forge + - HCC +dependencies: + - fsl-bet2 + - fsl-flirt + - pydeface \ No newline at end of file From 4532d4440f80ad2171b89f0857260d5c0e637a5f Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Mon, 17 Jun 2024 17:06:22 -0400 Subject: [PATCH 03/40] fix typos and pep8 --- Dockerfile | 2 +- dcm2bids/sidecar.py | 4 ++-- dcm2bids/utils/utils.py | 13 +++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5febda1f..0f067048 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,7 @@ ENV FSLTCLSH="${FSLDIR}/bin/fsltclsh" ENV FSLWISH="${FSLDIR}/bin/fslwish" ENV FSLGECUDAQ="cuda.q" -# Install dc fro FSL bet and wget for fetching data +# Update and install some utils RUN apt-get -y update && apt-get -y install dc wget npm unzip # Fetch data diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index da070933..c9077f79 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -462,7 +462,7 @@ def searchDcmTagEntity(self, sidecar, desc): # If dir found in custom_entities and concatenated_matches.keys we keep it if "custom_entities" in desc.keys(): entities = set(concatenated_matches.keys()).intersection(set(descWithTask["custom_entities"])) - + # custom_entities not a key for extractor or auto_extract_entities complete_entities = [ent for ent in descWithTask["custom_entities"] if '-' in ent] entities = entities.union(set(complete_entities)) @@ -478,7 +478,7 @@ def searchDcmTagEntity(self, sidecar, desc): if left_auto_entities: self.logger.warning(f"{left_auto_entities} have not been found for datatype '{descWithTask['datatype']}' " f"and suffix '{descWithTask['suffix']}'.") - + entities = list(entities) + list(auto_entities) entities = list(set(entities)) descWithTask["custom_entities"] = entities diff --git a/dcm2bids/utils/utils.py b/dcm2bids/utils/utils.py index b09bd2ea..6aa2b881 100644 --- a/dcm2bids/utils/utils.py +++ b/dcm2bids/utils/utils.py @@ -5,7 +5,7 @@ import logging import os from pathlib import Path -from subprocess import check_output, Popen, PIPE +from subprocess import Popen, PIPE class DEFAULT(object): @@ -74,7 +74,7 @@ class DEFAULT(object): "fmap_TB1SRGE": ["echo", "inv"], "perf_physio": ["task"], "perf_stim": ["task"]} - + compKeys = ["AcquisitionTime", "SeriesNumber", "SidecarFilename"] search_methodChoices = ["fnmatch", "re"] search_method = "fnmatch" @@ -148,9 +148,10 @@ def run_shell_command(commandLine, log=True): pipes = Popen(commandLine, stdout=PIPE, stderr=PIPE) std_out, std_err = pipes.communicate() - + return std_out + def convert_dir(dir): """ Convert Direction Args: @@ -163,15 +164,15 @@ def convert_dir(dir): def combine_dict_extractors(d1, d2): - """ combine dict + """ combine dict Args: d1 (dic): dictionary d2 (dic): dictionary - + Returns: dict: dictionary with combined information if d1 d2 use the same keys, return dict will return a list of items. - """ + """ return { k: [d[k][0] for d in (d1, d2) if k in d] for k in set(d1.keys()) | set(d2.keys()) From 9ae71ffaf6a7228edb1d2c70982d785031f10ee2 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Mon, 17 Jun 2024 20:56:03 -0400 Subject: [PATCH 04/40] add a way to show error or warning during dcm2niix execution --- dcm2bids/dcm2niix_gen.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dcm2bids/dcm2niix_gen.py b/dcm2bids/dcm2niix_gen.py index 320af2b7..e49f97c1 100644 --- a/dcm2bids/dcm2niix_gen.py +++ b/dcm2bids/dcm2niix_gen.py @@ -142,7 +142,11 @@ def execute(self): shutil.rmtree(self.rm_tmp_dir) self.logger.info("Temporary dicom directory removed.") - self.logger.debug(f"\n{output}") + if "Warning" in output or "Error" in output: + self.logger.info(f"\n{output}") + else: + self.logger.debug(f"\n{output}") + self.logger.info("Check log file for dcm2niix output\n") else: From 83ede5a58e3fa0470dd67bd6ba41151aaac4b480 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Mon, 17 Jun 2024 21:43:18 -0400 Subject: [PATCH 05/40] fix error message and remove pydeface from default conda env --- dcm2bids/dcm2bids_gen.py | 29 +++++++++++++++++++++-------- dcm2bids/dcm2niix_gen.py | 7 ++++--- environment.yml | 3 +-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index 7886999c..5b6e72bc 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -123,16 +123,19 @@ def run(self): if self.bids_validate: try: - self.logger.info(f"Validate if {self.bids_dir} is BIDS valid.") - bids_version = run_shell_command(['bids-validator', '-v']) - self.logger.info(f"Use bids-validator version: {bids_version.decode()}") + self.logger.info(f"BIDS VALIDATION") + bids_version = run_shell_command(['bids-validator', '-v'], False) + self.logger.info(f"Use bids-validator version: {bids_version.decode()[:-1]}") bids_report = run_shell_command(['bids-validator', self.bids_dir]) + self.logger.info("Report from bids-validator") self.logger.info(bids_report.decode()) except Exception: - self.logger.error("The bids-validator does not seem to work properly. " + self.logger.error("\033[91m" + "The bids-validator does not seem to work properly. " "The bids-validator may not be installed on your " "computer. Please check: " - "https://github.com/bids-standard/bids-validator.") + "https://github.com/bids-standard/bids-validator." + "\033[0m") def move(self, acq, idList, post_op): """Move an acquisition to BIDS format""" @@ -187,9 +190,19 @@ def move(self, acq, idList, post_op): else: cmd = cmd.replace('dst_file', str(dstFile)) - std_out = run_shell_command(cmd.split()) - self.logger.debug(std_out.decode()) - continue + try: + std_out = run_shell_command(cmd.split()) + self.logger.debug(f"Log from: {cmd}") + self.logger.debug(std_out.decode()) + self.logger.info("") + continue + except Exception: + self.logger.error( + "\033[91m" + f"The command post_op: \"{cmd}\" " + "does not seem to work properly. " + "Check if it is installed on your " + "computer.\033[0m\n") if ".json" in ext: data = acq.dstSidecarData(idList) diff --git a/dcm2bids/dcm2niix_gen.py b/dcm2bids/dcm2niix_gen.py index e49f97c1..7e9b6bc5 100644 --- a/dcm2bids/dcm2niix_gen.py +++ b/dcm2bids/dcm2niix_gen.py @@ -143,11 +143,12 @@ def execute(self): self.logger.info("Temporary dicom directory removed.") if "Warning" in output or "Error" in output: - self.logger.info(f"\n{output}") + self.logger.info("Log from dcm2niix execution") + self.logger.info(f"\033[93m{output}\033[0m") else: self.logger.debug(f"\n{output}") - - self.logger.info("Check log file for dcm2niix output\n") + self.logger.info("Check log file for dcm2niix output\n") + else: for dicomDir in self.dicom_dirs: diff --git a/environment.yml b/environment.yml index 82151bc5..1ce5a83a 100644 --- a/environment.yml +++ b/environment.yml @@ -5,5 +5,4 @@ channels: - HCC dependencies: - fsl-bet2 - - fsl-flirt - - pydeface \ No newline at end of file + - fsl-flirt \ No newline at end of file From d103f6864efa250ef96db764ea5b499e5386100f Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 27 Jun 2024 09:31:29 -0400 Subject: [PATCH 06/40] answer Sam comments --- Dockerfile | 4 ++-- dcm2bids/dcm2bids_gen.py | 11 ++++------- dcm2bids/dcm2niix_gen.py | 5 ++++- dcm2bids/utils/logger.py | 29 ++++++++++++++++++++++++++++- environment.yml | 1 - 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0f067048..fec52d41 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ FROM debian:stable AS runtime COPY --from=build /venv /venv # Point to conda executables -ENV PATH /venv/bin:$PATH +ENV PATH="/venv/bin:$PATH" # Set FSL variables ENV FSLDIR="/venv" @@ -54,4 +54,4 @@ RUN pip install -e . RUN pip install pydeface -ENTRYPOINT [""] \ No newline at end of file +ENTRYPOINT ["dcm2bids"] \ No newline at end of file diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index 5b6e72bc..414d083e 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -123,19 +123,17 @@ def run(self): if self.bids_validate: try: - self.logger.info(f"BIDS VALIDATION") + self.logger.info("BIDS VALIDATION") bids_version = run_shell_command(['bids-validator', '-v'], False) self.logger.info(f"Use bids-validator version: {bids_version.decode()[:-1]}") bids_report = run_shell_command(['bids-validator', self.bids_dir]) self.logger.info("Report from bids-validator") self.logger.info(bids_report.decode()) except Exception: - self.logger.error("\033[91m" - "The bids-validator does not seem to work properly. " + self.logger.error("The bids-validator does not seem to work properly. " "The bids-validator may not be installed on your " "computer. Please check: " - "https://github.com/bids-standard/bids-validator." - "\033[0m") + "https://github.com/bids-standard/bids-validator.") def move(self, acq, idList, post_op): """Move an acquisition to BIDS format""" @@ -198,11 +196,10 @@ def move(self, acq, idList, post_op): continue except Exception: self.logger.error( - "\033[91m" f"The command post_op: \"{cmd}\" " "does not seem to work properly. " "Check if it is installed on your " - "computer.\033[0m\n") + "computer.\n") if ".json" in ext: data = acq.dstSidecarData(idList) diff --git a/dcm2bids/dcm2niix_gen.py b/dcm2bids/dcm2niix_gen.py index 7e9b6bc5..47698b6a 100644 --- a/dcm2bids/dcm2niix_gen.py +++ b/dcm2bids/dcm2niix_gen.py @@ -144,7 +144,10 @@ def execute(self): if "Warning" in output or "Error" in output: self.logger.info("Log from dcm2niix execution") - self.logger.info(f"\033[93m{output}\033[0m") + if "Warning" in output: + self.logger.warning(f"{output}") + else: + self.logger.error(f"{output}") else: self.logger.debug(f"\n{output}") self.logger.info("Check log file for dcm2niix output\n") diff --git a/dcm2bids/utils/logger.py b/dcm2bids/utils/logger.py index eb5af2e3..9529ce15 100644 --- a/dcm2bids/utils/logger.py +++ b/dcm2bids/utils/logger.py @@ -19,7 +19,7 @@ def setup_logging(log_level, log_file=None): sh = logging.StreamHandler(sys.stdout) sh.setLevel(log_level) - sh_fmt = logging.Formatter(fmt="%(levelname)-8s| %(message)s") + sh_fmt = CustomFormatter(fmt="%(levelname)-8s| %(message)s") sh.setFormatter(sh_fmt) # default formatting is kept for the log file" @@ -30,3 +30,30 @@ def setup_logging(log_level, log_file=None): datefmt="%Y-%m-%d %H:%M:%S", handlers=[fh, sh] ) + + +class CustomFormatter(logging.Formatter): + """Logging colored formatter, adapted from https://stackoverflow.com/a/56944256/3638629""" + + grey = '\x1b[38;21m' + blue = '\x1b[38;5;39m' + yellow = '\x1b[38;5;226m' + red = '\x1b[38;5;196m' + bold_red = '\x1b[31;1m' + reset = '\x1b[0m' + + def __init__(self, fmt): + super().__init__() + self.fmt = fmt + self.FORMATS = { + logging.DEBUG: self.grey + self.fmt + self.reset, + logging.INFO: self.blue + self.fmt + self.reset, + logging.WARNING: self.yellow + self.fmt + self.reset, + logging.ERROR: self.red + self.fmt + self.reset, + logging.CRITICAL: self.bold_red + self.fmt + self.reset + } + + def format(self, record): + log_fmt = self.FORMATS.get(record.levelno) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) \ No newline at end of file diff --git a/environment.yml b/environment.yml index 1ce5a83a..75447a4f 100644 --- a/environment.yml +++ b/environment.yml @@ -2,7 +2,6 @@ name: fsl channels: - https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/ - conda-forge - - HCC dependencies: - fsl-bet2 - fsl-flirt \ No newline at end of file From 53f39f5787c0baf71a151f4ccf0da64b16ac059b Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 27 Jun 2024 11:49:48 -0400 Subject: [PATCH 07/40] first_working_version --- dcm2bids/acquisition.py | 29 ++++++++++++++++++----------- dcm2bids/cli/dcm2bids.py | 7 +++++++ dcm2bids/dcm2bids_gen.py | 5 ++++- dcm2bids/sidecar.py | 5 ++++- dcm2bids/utils/utils.py | 1 + 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/dcm2bids/acquisition.py b/dcm2bids/acquisition.py index cba30c76..e4008bf6 100644 --- a/dcm2bids/acquisition.py +++ b/dcm2bids/acquisition.py @@ -30,6 +30,7 @@ def __init__( id=None, src_sidecar=None, sidecar_changes=None, + do_not_reorder_entities=None, **kwargs ): self.logger = logging.getLogger(__name__) @@ -43,6 +44,7 @@ def __init__( self.suffix = suffix self.custom_entities = custom_entities self.src_sidecar = src_sidecar + self.do_not_reorder_entities = do_not_reorder_entities if sidecar_changes is None: self.sidecar_changes = {} @@ -196,11 +198,14 @@ def setExtraDstFile(self, new_entities): "compliant. Make sure you know what " "you are doing.") - if current_name != new_name: - self.logger.warning( - f"""✅ Filename was reordered according to BIDS entity table order: - from: {current_name} - to: {new_name}""") + if not self.do_not_reorder_entities: + if current_name != new_name: + self.logger.warning( + f"""✅ Filename was reordered according to BIDS entity table order: + from: {current_name} + to: {new_name}""") + else: + new_name = current_name self.extraDstFile = opj(self.participant.directory, self.datatype, @@ -241,13 +246,15 @@ def setDstFile(self): "compliant. Make sure you know what " "you are doing.") - if current_name != new_name: - self.logger.warning( - f"""✅ Filename was reordered according to BIDS entity table order: - from: {current_name} - to: {new_name}""") + self.dstFile = current_name + if not self.do_not_reorder_entities: + if current_name != new_name: + self.logger.warning( + f"""✅ Filename was reordered according to BIDS entity table order: + from: {current_name} + to: {new_name}""") + self.dstFile = new_name - self.dstFile = new_name def dstSidecarData(self, idList): """ diff --git a/dcm2bids/cli/dcm2bids.py b/dcm2bids/cli/dcm2bids.py index 131ee01f..4d0957af 100644 --- a/dcm2bids/cli/dcm2bids.py +++ b/dcm2bids/cli/dcm2bids.py @@ -53,6 +53,12 @@ def _build_arg_parser(): "information [task, dir, echo] based on the suffix and datatype." " [%(default)s]") + p.add_argument("--do_not_reorder_entities", + action='store_true', + help="If set, it will not reorder entities accordingly to the BIDS " + "and uses the order defined in custom_entities." + " [%(default)s]") + p.add_argument("--bids_validate", action='store_true', help="If set, once your conversion is done it " @@ -120,6 +126,7 @@ def main(): logger.info(f"config: {os.path.realpath(args.config)}") logger.info(f"BIDS directory: {os.path.realpath(args.output_dir)}") logger.info(f"Auto extract entities: {args.auto_extract_entities}") + logger.info(f"Reorder entities: {not args.do_not_reorder_entities}") logger.info(f"Validate BIDS: {args.bids_validate}\n") app = Dcm2BidsGen(**vars(args)).run() diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index ae5e4065..350e3401 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -39,7 +39,8 @@ def __init__( config, output_dir=DEFAULT.output_dir, bids_validate=DEFAULT.bids_validate, - auto_extract_entities=False, + auto_extract_entities=DEFAULT.auto_extract_entities, + do_not_reorder_entities = DEFAULT.do_not_reorder_entities, session=DEFAULT.session, clobber=DEFAULT.clobber, force_dcm2bids=DEFAULT.force_dcm2bids, @@ -55,6 +56,7 @@ def __init__( self.clobber = clobber self.bids_validate = bids_validate self.auto_extract_entities = auto_extract_entities + self.do_not_reorder_entities = do_not_reorder_entities self.force_dcm2bids = force_dcm2bids self.skip_dcm2niix = skip_dcm2niix self.logLevel = log_level @@ -99,6 +101,7 @@ def run(self): self.config["descriptions"], self.config.get("extractors", {}), self.auto_extract_entities, + self.do_not_reorder_entities, self.config.get("search_method", DEFAULT.search_method), self.config.get("case_sensitive", DEFAULT.case_sensitive), self.config.get("dup_method", DEFAULT.dup_method), diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index b0c344c0..ca2e943a 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -96,6 +96,7 @@ def __init__(self, descriptions, extractors=DEFAULT.extractors, auto_extractor=DEFAULT.auto_extract_entities, + do_not_reorder_entities=DEFAULT.do_not_reorder_entities, search_method=DEFAULT.search_method, case_sensitive=DEFAULT.case_sensitive, dup_method=DEFAULT.dup_method, @@ -108,6 +109,7 @@ def __init__(self, self.acquisitions = [] self.extractors = extractors self.auto_extract_entities = auto_extractor + self.do_not_reorder_entities = do_not_reorder_entities self.sidecars = sidecars self.descriptions = descriptions self.search_method = search_method @@ -393,8 +395,8 @@ def build_acquisitions(self, participant): if len(valid_descriptions) == 1: desc = valid_descriptions[0] desc, sidecar = self.searchDcmTagEntity(sidecar, desc) - acq = Acquisition(participant, + do_not_reorder_entities=self.do_not_reorder_entities, src_sidecar=sidecar, **desc) acq.setDstFile() @@ -414,6 +416,7 @@ def build_acquisitions(self, participant): self.logger.warning(f"Several Pairing <- {sidecarName}") for desc in valid_descriptions: acq = Acquisition(participant, + reorder_entities=self.reorder_entities, **desc) self.logger.warning(f" -> {acq.suffix}") diff --git a/dcm2bids/utils/utils.py b/dcm2bids/utils/utils.py index fd9426c1..6eb638ec 100644 --- a/dcm2bids/utils/utils.py +++ b/dcm2bids/utils/utils.py @@ -28,6 +28,7 @@ class DEFAULT(object): session = "" # also Participant object bids_validate = False auto_extract_entities = False + do_not_reorder_entities = False clobber = False force_dcm2bids = False post_op = [] From cfbd3a4097c4441bf2349e42ff30245724bd8919 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 27 Jun 2024 11:52:31 -0400 Subject: [PATCH 08/40] fix typo --- dcm2bids/sidecar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index ca2e943a..6f6a8af3 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -416,7 +416,7 @@ def build_acquisitions(self, participant): self.logger.warning(f"Several Pairing <- {sidecarName}") for desc in valid_descriptions: acq = Acquisition(participant, - reorder_entities=self.reorder_entities, + do_not_reorder_entities=self.do_not_reorder_entities, **desc) self.logger.warning(f" -> {acq.suffix}") From b66bf98259b2d2547e5e68f6f1e6c4801d157d31 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 27 Jun 2024 15:35:52 -0400 Subject: [PATCH 09/40] working version --- dcm2bids/acquisition.py | 15 ++++++++++++--- dcm2bids/dcm2bids_gen.py | 3 ++- dcm2bids/sidecar.py | 37 ++++++++++++++++++++++++++++++------- dcm2bids/utils/utils.py | 10 ++++++---- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/dcm2bids/acquisition.py b/dcm2bids/acquisition.py index cba30c76..c20841b6 100644 --- a/dcm2bids/acquisition.py +++ b/dcm2bids/acquisition.py @@ -4,6 +4,7 @@ import logging from os.path import join as opj +from os import sep from dcm2bids.utils.utils import DEFAULT from dcm2bids.version import __version__ @@ -30,6 +31,7 @@ def __init__( id=None, src_sidecar=None, sidecar_changes=None, + bids_uri=None, **kwargs ): self.logger = logging.getLogger(__name__) @@ -43,6 +45,7 @@ def __init__( self.suffix = suffix self.custom_entities = custom_entities self.src_sidecar = src_sidecar + self.bids_uri = bids_uri if sidecar_changes is None: self.sidecar_changes = {} @@ -277,10 +280,16 @@ def dstSidecarData(self, idList): else: values.append(idList.get(val, val)) if values[-1] != val: - if isinstance(values[-1], list): - values[-1] = ["bids::" + img_dest for img_dest in values[-1]] + if self.bids_uri == DEFAULT.bids_uri: + if isinstance(values[-1], list): + values[-1] = ["bids::" + img_dest for img_dest in values[-1]] + else: + values[-1] = "bids::" + values[-1] else: - values[-1] = "bids::" + values[-1] + if isinstance(values[-1], list): + values[-1] = [img_dest.replace(self.participant.name + sep, "") for img_dest in values[-1]] + else: + values[-1] = values[-1].replace(self.participant.name + sep, "") # handle if nested list vs str flat_value_list = [] diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index ae5e4065..b6c57ec1 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -102,7 +102,8 @@ def run(self): self.config.get("search_method", DEFAULT.search_method), self.config.get("case_sensitive", DEFAULT.case_sensitive), self.config.get("dup_method", DEFAULT.dup_method), - self.config.get("post_op", DEFAULT.post_op) + self.config.get("post_op", DEFAULT.post_op), + self.config.get("bids_uri", DEFAULT.bids_uri) ) parser.build_graph() parser.build_acquisitions(self.participant) diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index b0c344c0..592eae52 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -11,7 +11,8 @@ from dcm2bids.acquisition import Acquisition from dcm2bids.utils.io import load_json -from dcm2bids.utils.utils import DEFAULT, convert_dir, combine_dict_extractors, splitext_ +from dcm2bids.utils.utils import (DEFAULT, convert_dir, combine_dict_extractors, + splitext_) compare_float_keys = ["lt", "gt", "le", "ge", "btw", "btwe"] @@ -99,11 +100,13 @@ def __init__(self, search_method=DEFAULT.search_method, case_sensitive=DEFAULT.case_sensitive, dup_method=DEFAULT.dup_method, - post_op=DEFAULT.post_op): + post_op=DEFAULT.post_op, + bids_uri=DEFAULT.bids_uri): self.logger = logging.getLogger(__name__) self._search_method = "" self._dup_method = "" self._post_op = "" + self._bids_uri = "" self.graph = OrderedDict() self.acquisitions = [] self.extractors = extractors @@ -114,6 +117,7 @@ def __init__(self, self.case_sensitive = case_sensitive self.dup_method = dup_method self.post_op = post_op + self.bids_uri = bids_uri @property def search_method(self): @@ -218,6 +222,25 @@ def post_op(self, value): raise ValueError("post_op is not defined correctly. " "Please check the documentation.") + @property + def bids_uri(self): + return self._bids_uri + + @bids_uri.setter + def bids_uri(self, value): + """ + Checks if the method bids_uri is using is implemented + Warns the user if not and fall back to default + """ + if value in DEFAULT.bids_uri_choices: + self._bids_uri = value + else: + self.bids_uri = DEFAULT.bids_uri + self.logger.warning( + "BIDS URI methods implemented: %s", DEFAULT.bids_uri_choices) + self.logger.warning(f"{value} is not a bids URI method implemented.") + self.logger.warning(f"Falling back to default: {DEFAULT.bids_uri}.") + @property def case_sensitive(self): return self._case_sensitive @@ -393,9 +416,10 @@ def build_acquisitions(self, participant): if len(valid_descriptions) == 1: desc = valid_descriptions[0] desc, sidecar = self.searchDcmTagEntity(sidecar, desc) - acq = Acquisition(participant, - src_sidecar=sidecar, **desc) + src_sidecar=sidecar, + bids_uri=self.bids_uri, + **desc) acq.setDstFile() if acq.id: @@ -414,6 +438,7 @@ def build_acquisitions(self, participant): self.logger.warning(f"Several Pairing <- {sidecarName}") for desc in valid_descriptions: acq = Acquisition(participant, + bids_uri=self.bids_uri, **desc) self.logger.warning(f" -> {acq.suffix}") @@ -438,7 +463,6 @@ def searchDcmTagEntity(self, sidecar, desc): if self.auto_extract_entities: self.extractors = combine_dict_extractors(self.extractors, DEFAULT.auto_extractors) - for dcmTag in self.extractors: if dcmTag in sidecar.data.keys(): dcmInfo = sidecar.data.get(dcmTag) @@ -473,12 +497,11 @@ def searchDcmTagEntity(self, sidecar, desc): if left_auto_entities: self.logger.warning(f"{left_auto_entities} have not been found for datatype '{descWithTask['datatype']}' " f"and suffix '{descWithTask['suffix']}'.") - + entities = list(entities) + list(auto_entities) entities = list(set(entities)) descWithTask["custom_entities"] = entities - for curr_entity in entities: if curr_entity in concatenated_matches.keys(): if curr_entity == 'dir': diff --git a/dcm2bids/utils/utils.py b/dcm2bids/utils/utils.py index fd9426c1..45bf61aa 100644 --- a/dcm2bids/utils/utils.py +++ b/dcm2bids/utils/utils.py @@ -59,7 +59,7 @@ class DEFAULT(object): "func_bold": ["task"], "func_sbref": ["task"], "fmap_epi": ["dir"]} - + compKeys = ["AcquisitionTime", "SeriesNumber", "SidecarFilename"] search_methodChoices = ["fnmatch", "re"] search_method = "fnmatch" @@ -67,6 +67,8 @@ class DEFAULT(object): dup_method = "run" runTpl = "_run-{:02d}" dupTpl = "_dup-{:02d}" + bids_uri_choices = ["URI", "relative"] + bids_uri = "URI" case_sensitive = True # Entity table: @@ -143,15 +145,15 @@ def convert_dir(dir): def combine_dict_extractors(d1, d2): - """ combine dict + """ combine dict Args: d1 (dic): dictionary d2 (dic): dictionary - + Returns: dict: dictionary with combined information if d1 d2 use the same keys, return dict will return a list of items. - """ + """ return { k: [d[k][0] for d in (d1, d2) if k in d] for k in set(d1.keys()) | set(d2.keys()) From dfb87fc573524649a9cff514ebe77e193720ca59 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Tue, 2 Jul 2024 15:51:34 -0400 Subject: [PATCH 10/40] Add a more useful message when entities have not been found --- dcm2bids/sidecar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index c9077f79..1ed89b76 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -476,7 +476,8 @@ def searchDcmTagEntity(self, sidecar, desc): left_auto_entities = left_auto_entities.difference(keys_custom_entities) if left_auto_entities: - self.logger.warning(f"{left_auto_entities} have not been found for datatype '{descWithTask['datatype']}' " + self.logger.warning(f"Entities {left_auto_entities} have not been found" + f" for datatype '{descWithTask['datatype']}' " f"and suffix '{descWithTask['suffix']}'.") entities = list(entities) + list(auto_entities) From d7e2edb0cfff83072eec782d60dacd3d12a68250 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Tue, 2 Jul 2024 15:51:52 -0400 Subject: [PATCH 11/40] typo --- dcm2bids/sidecar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index 1ed89b76..23d426d0 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -476,8 +476,8 @@ def searchDcmTagEntity(self, sidecar, desc): left_auto_entities = left_auto_entities.difference(keys_custom_entities) if left_auto_entities: - self.logger.warning(f"Entities {left_auto_entities} have not been found" - f" for datatype '{descWithTask['datatype']}' " + self.logger.warning(f"Entities {left_auto_entities} have not been found " + f"for datatype '{descWithTask['datatype']}' " f"and suffix '{descWithTask['suffix']}'.") entities = list(entities) + list(auto_entities) From fa01aba6a863d2b0baebdf79a8eb3891859a00a8 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Thu, 4 Jul 2024 14:43:34 -0400 Subject: [PATCH 12/40] Update dcm2bids/cli/dcm2bids.py Co-authored-by: Samuel Guay --- dcm2bids/cli/dcm2bids.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dcm2bids/cli/dcm2bids.py b/dcm2bids/cli/dcm2bids.py index 4d0957af..494a5253 100644 --- a/dcm2bids/cli/dcm2bids.py +++ b/dcm2bids/cli/dcm2bids.py @@ -55,8 +55,9 @@ def _build_arg_parser(): p.add_argument("--do_not_reorder_entities", action='store_true', - help="If set, it will not reorder entities accordingly to the BIDS " - "and uses the order defined in custom_entities." + help="If set, it will not reorder entities according to the relative " + "ordering indicated in the BIDS specification and use the " + "order defined in custom_entities by the user." " [%(default)s]") p.add_argument("--bids_validate", From 3902f89b44168543948d236e759e3c7007ed1dbf Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 4 Jul 2024 15:01:33 -0400 Subject: [PATCH 13/40] add tests for no reorder entities --- tests/data/config_test_no_reorder.json | 16 ++++++++++++++++ tests/test_dcm2bids.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/data/config_test_no_reorder.json diff --git a/tests/data/config_test_no_reorder.json b/tests/data/config_test_no_reorder.json new file mode 100644 index 00000000..fdd7de1c --- /dev/null +++ b/tests/data/config_test_no_reorder.json @@ -0,0 +1,16 @@ +{ + "search_method": "fnmatch", + "extractors": {"SeriesDescription": ["task-(?P[a-zA-Z0-9]+)"]}, + "descriptions": [ + { + "id": "func_task-rest", + "datatype": "func", + "suffix": "bold", + "custom_entities": ["acq-highres", "task"], + "criteria": { + "SeriesDescription": "*bold*", + "ImageType": ["ORIG?NAL", "PRIMARY", "M", "ND", "MOSAIC"] + } + } + ] +} diff --git a/tests/test_dcm2bids.py b/tests/test_dcm2bids.py index 17adb36b..b2a9810c 100644 --- a/tests/test_dcm2bids.py +++ b/tests/test_dcm2bids.py @@ -571,3 +571,24 @@ def test_dcm2bids_multiple_intendedFor(): "bids::" + os.path.join("sub-01", "anat", "sub-01_T1w.nii")] + + +def test_dcm2bids_no_reorder_entities(): + bids_dir = TemporaryDirectory() + + tmp_sub_dir = os.path.join(bids_dir.name, DEFAULT.tmp_dir_name, "sub-01") + shutil.copytree(os.path.join(TEST_DATA_DIR, "sidecars"), tmp_sub_dir) + + app = Dcm2BidsGen(TEST_DATA_DIR, "01", + os.path.join(TEST_DATA_DIR, "config_test_no_reorder.json"), + bids_dir.name, + do_not_reorder_entities=True, + auto_extract_entities=True) + + app.run() + + # existing field + func_json = os.path.join(bids_dir.name, "sub-01", + "func", + "sub-01_acq-highres_task-rest_bold.json") + assert os.path.exists(func_json) \ No newline at end of file From 66c62cdd0fd91924167f9bdc28976587ef910ae4 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Wed, 17 Jul 2024 09:46:01 -0400 Subject: [PATCH 14/40] fix reorder and do not accept it with auto_extract_entities --- dcm2bids/cli/dcm2bids.py | 8 +++++--- dcm2bids/dcm2bids_gen.py | 5 +++++ dcm2bids/sidecar.py | 4 +++- tests/test_dcm2bids.py | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/dcm2bids/cli/dcm2bids.py b/dcm2bids/cli/dcm2bids.py index 494a5253..3342c30d 100644 --- a/dcm2bids/cli/dcm2bids.py +++ b/dcm2bids/cli/dcm2bids.py @@ -47,17 +47,19 @@ def _build_arg_parser(): default=DEFAULT.output_dir, help="Output BIDS directory. [%(default)s]") - p.add_argument("--auto_extract_entities", + g = p.add_mutually_exclusive_group() + g.add_argument("--auto_extract_entities", action='store_true', help="If set, it will automatically try to extract entity" "information [task, dir, echo] based on the suffix and datatype." " [%(default)s]") - p.add_argument("--do_not_reorder_entities", + g.add_argument("--do_not_reorder_entities", action='store_true', help="If set, it will not reorder entities according to the relative " "ordering indicated in the BIDS specification and use the " - "order defined in custom_entities by the user." + "order defined in custom_entities by the user.\n" + "Cannot be used with --auto_extract_entities. " " [%(default)s]") p.add_argument("--bids_validate", diff --git a/dcm2bids/dcm2bids_gen.py b/dcm2bids/dcm2bids_gen.py index 350e3401..317949b4 100644 --- a/dcm2bids/dcm2bids_gen.py +++ b/dcm2bids/dcm2bids_gen.py @@ -62,6 +62,11 @@ def __init__( self.logLevel = log_level self.logger = logging.getLogger(__name__) + if self.auto_extract_entities and self.do_not_reorder_entities: + raise ValueError("Auto extract entities is set to True and " + "do not reorder entities is set to True. " + "Please choose only one option.") + @property def dicom_dirs(self): """List of DICOMs directories""" diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index 6f6a8af3..11e4d8a0 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -460,7 +460,9 @@ def searchDcmTagEntity(self, sidecar, desc): # Keep entities asked in custom_entities # If dir found in custom_entities and concatenated_matches.keys we keep it - if "custom_entities" in desc.keys(): + if "custom_entities" in desc.keys() and not self.auto_extract_entities: + entities = desc["custom_entities"] + elif "custom_entities" in desc.keys(): entities = set(concatenated_matches.keys()).intersection(set(descWithTask["custom_entities"])) # custom_entities not a key for extractor or auto_extract_entities diff --git a/tests/test_dcm2bids.py b/tests/test_dcm2bids.py index b2a9810c..f5befcbe 100644 --- a/tests/test_dcm2bids.py +++ b/tests/test_dcm2bids.py @@ -583,7 +583,7 @@ def test_dcm2bids_no_reorder_entities(): os.path.join(TEST_DATA_DIR, "config_test_no_reorder.json"), bids_dir.name, do_not_reorder_entities=True, - auto_extract_entities=True) + auto_extract_entities=False) app.run() From 5a00d3f3356a6f6ddea2aba340e483de8e01c38a Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Wed, 17 Jul 2024 11:01:47 -0400 Subject: [PATCH 15/40] add data test --- ...est_multiple_intendedfor_uri_relative.json | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/data/config_test_multiple_intendedfor_uri_relative.json diff --git a/tests/data/config_test_multiple_intendedfor_uri_relative.json b/tests/data/config_test_multiple_intendedfor_uri_relative.json new file mode 100644 index 00000000..2c3e9053 --- /dev/null +++ b/tests/data/config_test_multiple_intendedfor_uri_relative.json @@ -0,0 +1,34 @@ +{ + "search_method": "fnmatch", + "extractors": {"SeriesDescription": ["task-(?P[a-zA-Z0-9]+)"]}, + "bids_uri": "relative", + "descriptions": [ + { + "id": "localizer", + "datatype": "localizer", + "suffix": "localizer", + "criteria": { + "SeriesDescription": "locali*" + } + }, + { + "id": "T1", + "datatype": "anat", + "suffix": "T1w", + "criteria": { + "SidecarFilename": "*MPRAGE*" + } + }, + { + "datatype": "fmap", + "suffix": "fmap", + "criteria": { + "EchoNumber": 1, + "EchoTime": 0.00492 + }, + "sidecar_changes": { + "IntendedFor": ["localizer", "T1"] + } + } + ] +} From 1d74109db927dbd10fdde016e770912256eba55b Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Thu, 18 Jul 2024 10:09:19 -0400 Subject: [PATCH 16/40] Update GHA to use setup-python@v5 instead of v1 (#309) * Update tests.yml with setup-python@v5 * Update publish.yml with setup-python@v5 * Update make_binaries.yml with setup-python@v5 * Update publish_doc.yaml with setup-python@v5 * Include dev branch for push and PR * Update coverage.yml with setup-python@v5 --- .github/workflows/codespell.yml | 4 ++-- .github/workflows/coverage.yml | 2 +- .github/workflows/make_binaries.yml | 4 ++-- .github/workflows/publish.yml | 2 +- .github/workflows/publish_doc.yaml | 2 +- .github/workflows/tests.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 7373affc..4498fcb5 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -3,9 +3,9 @@ name: Codespell on: push: - branches: [master] + branches: [master, dev] pull_request: - branches: [master] + branches: [master, dev] permissions: contents: read diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 22753d33..16b966b9 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Set up Python 3.11 - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies diff --git a/.github/workflows/make_binaries.yml b/.github/workflows/make_binaries.yml index ee17670e..3e3b96d3 100644 --- a/.github/workflows/make_binaries.yml +++ b/.github/workflows/make_binaries.yml @@ -19,7 +19,7 @@ jobs: # Check-out repository - uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified @@ -95,4 +95,4 @@ jobs: files: | download/artifact/* env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f89a4f26..41bb83fe 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index e2a2319a..3a4676d5 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -22,7 +22,7 @@ jobs: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: "3.11" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bfffcc7c..d37348ef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From cd163b32bea4a05793525e5ece8e5c556df797e4 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 09:17:21 -0400 Subject: [PATCH 17/40] add --do_not_reorder_entities doc --- docs/how-to/create-config-file.md | 11 ++++++++--- docs/how-to/use-advanced-commands.md | 3 +++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/how-to/create-config-file.md b/docs/how-to/create-config-file.md index 1681eb71..65993736 100644 --- a/docs/how-to/create-config-file.md +++ b/docs/how-to/create-config-file.md @@ -128,9 +128,8 @@ specifications][bids-spec]. For a longer example of a Dcm2Bids config json, see [here](https://github.com/unfmontreal/Dcm2Bids/blob/master/example/config.json). -Note that the different bids labels must come in a very specific order to be -bids valid filenames. If the custom_entities fields that are entered that are in -the wrong order, then dcm2bids will reorder them for you. + +Note that the different BIDS entities have a specific order to be considered valid filenames, as specified in the [Entity table of the BIDS Specification](https://bids-specification.readthedocs.io/en/stable/appendices/entity-table.html). If the custom_entities fields are entered in a different order, dcm2bids will automatically reorder them for you. For example if you entered: @@ -149,6 +148,12 @@ WARNING:dcm2bids.structure:✅ Filename was reordered according to BIDS entity t custom_entities could also be combined with extractors. See [custom_entities combined with extractors](./use-advanced-commands.md#custom_entities-combined-with-extractors) +### Manuel ordering + +!!! tip "`--do_not_reorder_entities`" + + If you prefer to have manual control over the order of `custom_entities`, you can use the `--do_not_reorder_entities` flag. This flag allows you to keep the order defined by you, the user, in the `custom_entities` field. However, please note that this flag cannot be used in conjunction with the `--auto_extract_entities` flag. + ## sidecar_changes, id and IntendedFor Optional field to change or add information in a sidecar. diff --git a/docs/how-to/use-advanced-commands.md b/docs/how-to/use-advanced-commands.md index 5684a3da..397a7c22 100644 --- a/docs/how-to/use-advanced-commands.md +++ b/docs/how-to/use-advanced-commands.md @@ -290,6 +290,9 @@ like this. :radioactive: You can find more detailed information by looking at the file [`dcm2bids/utils/utils.py`](../dcm2bids/utils/utils/) and more specifically *`auto_extractors`* and *`auto_entities`* variables. +!!! danger "You cannot use `--auto_extract_entities` in conjunction with `--do_not_reorder_entities`" + Refer to the [Manuel ordering](../create-config-file/#custom_entities) section for more information. + ### `--bids_validate` By default, dcm2bids will not validate your final BIDS structure. If needed, you From 3a3bf7f76bdc639dc19c2166eab8b6e4b60ac035 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 09:44:07 -0400 Subject: [PATCH 18/40] add bids_uri doc --- docs/how-to/use-advanced-commands.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/how-to/use-advanced-commands.md b/docs/how-to/use-advanced-commands.md index 397a7c22..d6e09fab 100644 --- a/docs/how-to/use-advanced-commands.md +++ b/docs/how-to/use-advanced-commands.md @@ -58,7 +58,7 @@ field. By using the same keys in custom_entities and if found, it will add this new entities directly into the final filename. custom_entities can be a list that combined extractor keys and regular entities. If key is `task` it will -automatically add the field "TaskName" inside the sidecase file. +automatically add the field "TaskName" inside the sidecar file. ### `search_method` @@ -72,11 +72,11 @@ to match criteria. default: `"dup_method": "run"` -run is the default behavior and will add '\_run-' to the customEntities of the +run is the default behavior and will add `_run-` to the custom_entities of the acquisition if it finds duplicate destination roots. dup will keep the last duplicate description and put `_dup-`to the -customEntities of the other acquisitions. This behavior is a +custom_entities of the other acquisitions. This behavior is a [heudiconv](https://heudiconv.readthedocs.io/en/latest/changes.html) inspired feature. @@ -87,6 +87,13 @@ default: `"case_sensitive": "true"` If false, comparisons between strings/lists will be not case sensitive. It's only disabled when used with `"search_method": "fnmatch"`. +### `bids_uri` + +default: `"bids_uri": "URI"` +option: `"bids_uri": "relative"` + +Using `"bids_uri": "relative"` triggers the old behavior of dcm2bids (v2.1.9) that provides the path relative to within the subject directory without the BIDS URI (e.g., `bids::sub-01/`). This option has been brought back for compatibility reasons, especially for [fMRIprep users (pre v24.0.0)](https://fmriprep.org/en/latest/changes.html#june-17-2024). + ### `post_op` default: `"post_op": []` From e9da2c551d59a01409f77479074d7ec1fc209817 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 10:43:46 -0400 Subject: [PATCH 19/40] fix gha + order main commands --- .github/workflows/publish_doc.yaml | 3 +- docs/how-to/use-main-commands.md | 49 ++++++++++++++++-------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index 3a4676d5..036127e4 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -6,6 +6,7 @@ on: push: branches: - master + - dev tags: - '[0-9]+.[0-9]+.[0-9]+' release: @@ -76,7 +77,7 @@ jobs: mike deploy -p ${{ github.ref_name }} - name: Deploy dev version - if: ${{ github.ref == 'refs/heads/master' }} + if: ${{ github.ref == 'refs/heads/dev' }} run: | VERSION=$(dcm2bids -v | awk '/dcm2bids/ {print $3}') echo "Version: $VERSION" diff --git a/docs/how-to/use-main-commands.md b/docs/how-to/use-main-commands.md index 75570e8b..dbef4b6b 100644 --- a/docs/how-to/use-main-commands.md +++ b/docs/how-to/use-main-commands.md @@ -1,9 +1,14 @@ # How to use main commands -## Command Line Interface (CLI) +## Command Line Interface (CLI) usage -How to launch dcm2bids when you have build your configuration file ? First `cd` -in your BIDS directory. +See `dcm2bids -h` or `dcm2bids --help` to show the complete list of options and arguments. + +```bash +--8<-- "docs_helper/help.txt" +``` + +### Main command: `dcm2bids` ```bash dcm2bids -d DICOM_DIR -p PARTICIPANT_ID -c CONFIG_FILE @@ -15,11 +20,6 @@ If your participant have a session ID: dcm2bids -d DICOM_DIR -p PARTICIPANT_ID -s SESSION_ID -c CONFIG_FILE ``` -dcm2bids creates log files inside `tmp_dcm2bids/log` - -See `dcm2bids -h` or `dcm2bids --help` to show the help message that contains -more information. - !!! important If your directory or file names have space in them, we recommend that you @@ -29,14 +29,12 @@ more information. `dcm2bids -d "DICOM DIR" -p PARTICIPANT_ID -c "path/with spaces to/CONFIG FILE.json"` - - ## Output dcm2bids creates a `sub-` directory in the output directory (by default the folder where the script is launched). -Sidecars with one matching description will be convert to BIDS. If a file +Sidecars with one matching description will be converted to BIDS. If a file already exists, dcm2bids won't overwrite it. You should use the `--clobber` option to overwrite files. @@ -47,28 +45,35 @@ Sidecars with no or more than one matching descriptions are kept in `tmp_dcm2bids` directory. Users can review these mismatches to change the configuration file accordingly. +dcm2bids creates log files inside `tmp_dcm2bids/log` directory. + ## Tools -- Helper +### Scaffold + +the `dcm2bids_scaffold` command creates basic BIDS files and directories based on the [bids-starter-kit](https://github.com/bids-standard/bids-starter-kit). The output directory is set to the location where the script is launched by default. ```bash -dcm2bids_helper -d DICOM_DIR [-o OUTPUT_DIR] +dcm2bids_scaffold [-o OUTPUT_DIR] ``` -To build the configuration file, you need to have a example of the sidecars. You -can use `dcm2bids_helper` with the DICOMs of one participant. It will launch -dcm2niix and save the result inside the `tmp_dcm2bids/helper` of the output -directory. +```bash +--8<-- "docs_helper/help_scaffold.txt" +``` + +### Helper -- Scaffold +To build the configuration file, you need to have examples of sidecar files. You +can use `dcm2bids_helper` with the DICOMs of one participant. It will launch +dcm2niix and save the result inside the `tmp_dcm2bids/helper` directory by default. ```bash -dcm2bids_scaffold [-o OUTPUT_DIR] +dcm2bids_helper -d DICOM_DIR [-o OUTPUT_DIR] ``` -Create basic BIDS files and directories in the output directory (by default -folder where the script is launched). - +```bash +--8<-- "docs_helper/helper.txt" +``` [json-editor]: http://jsoneditoronline.org/ [^1]: From e723e1bb144c983702f407e3f8f6205e28c4e570 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 10:54:36 -0400 Subject: [PATCH 20/40] add readme me doc --- docs_helper/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs_helper/README.md diff --git a/docs_helper/README.md b/docs_helper/README.md new file mode 100644 index 00000000..2e2145d8 --- /dev/null +++ b/docs_helper/README.md @@ -0,0 +1,12 @@ +# How to build the doc locally + +The GHA workflow is set to build the documentation and has more steps than +the usual `mkdocs serve`. So if you want to see the documentation locally, +you can use the following steps: + +1. Create a virtual environment and install the dependencies in `requirements-docs.txt` with python 3.11. +2. Install dcm2bids within the virtual environment: `pip install -e .`. +3. Run `dcm2bids -h > docs_helper/help.txt && dcm2bids_helper -h > docs_helper/helper.txt && dcm2bids_scaffold -h > docs_helper/help_scaffold.txt` +4. Run `mkdocs serve` to see the documentation locally. + +Note that this will only run the latest local version of the documentation. `mike` takes care of the versioning through the GHA workflow. \ No newline at end of file From eeb7d6101ad708f8ce17476bb9f2516c5fe49c4e Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 11:18:53 -0400 Subject: [PATCH 21/40] add do_not_reorder to advance comm --- docs/how-to/use-advanced-commands.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/how-to/use-advanced-commands.md b/docs/how-to/use-advanced-commands.md index d6e09fab..5fccff5d 100644 --- a/docs/how-to/use-advanced-commands.md +++ b/docs/how-to/use-advanced-commands.md @@ -300,6 +300,10 @@ more specifically *`auto_extractors`* and *`auto_entities`* variables. !!! danger "You cannot use `--auto_extract_entities` in conjunction with `--do_not_reorder_entities`" Refer to the [Manuel ordering](../create-config-file/#custom_entities) section for more information. +### `--do_not_reorder_entities` + +This option will keep the order of the entities as they are entered in the config file by the user in the `custom_entities` field. However, please note that this flag cannot be used in conjunction with the `--auto_extract_entities` flag. + ### `--bids_validate` By default, dcm2bids will not validate your final BIDS structure. If needed, you From 9cf58f922ea7820719184fc1770a96b1b3ddac48 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 11:39:53 -0400 Subject: [PATCH 22/40] up py3.7 to 3.8 --- docs/get-started/install.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 8f7952e1..f3d05540 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -104,7 +104,7 @@ dcm2bids. ### Python As dcm2bids is a Python package, the first prerequisite is that Python must be -installed on the machine you will use dcm2bids. You will need **Python 3.7 or +installed on the machine you will use dcm2bids. You will need **Python 3.8 or above** to run dcm2bids properly. If you are unsure what version(s) of Python is available on your machine, you @@ -129,7 +129,7 @@ line. >>> exit() ``` -If your system-wide version of Python is lower 3.7, it is okay. We will make +If your system-wide version of Python is lower 3.8, it is okay. We will make sure to use a higher version in the isolated environment that will be created for dcm2bids. The important part is to verify that Python is installed. @@ -163,7 +163,7 @@ the next section. We recommend to install all the dependencies at once when installing dcm2bids on a machine or server. As mentioned above the minimal installation requires only -dcm2bids, dcm2niix and Python >= 3.7. For ease of use and to make sure we have a +dcm2bids, dcm2niix and Python >= 3.8. For ease of use and to make sure we have a reproducible environment, we recommend to use a dedicated environment through [conda][conda] or, for those who have it installed, [Anaconda][anaconda]. Note that you **don't need** to use specifically them to use dcm2bids, but it will @@ -260,7 +260,7 @@ name: dcm2bids channels: - conda-forge dependencies: - - python>=3.7 + - python>=3.8 - dcm2niix - dcm2bids ``` @@ -277,7 +277,7 @@ In short, here's what the fields mean: environment. If you are creating an environment for your analysis project, this is where you would list other dependencies such as `nilearn`, `pandas`, and especially as `pip` since you don't want to use the pip outside of your - environment Note that we specify `python>=3.7` to make sure the requirement is + environment Note that we specify `python>=3.8` to make sure the requirement is satisfied for dcm2bids as the newer version of dcm2bids may face issue with Python 3.6 and below. @@ -384,7 +384,7 @@ containers: channels: - conda-forge dependencies: - - python>=3.7 + - python>=3.8 - dcm2niix - dcm2bids From 41fdaab9f9990ea79181575d49e16052745e6243 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 12:21:55 -0400 Subject: [PATCH 23/40] long due update for changelog --- CHANGELOG.md | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3acfb1c..91ff3ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,205 @@ # CHANGELOG +## [3.1.1](https://github.com/UNFmontreal/Dcm2Bids/releases/tag/3.1.1) - 2023-10-12 + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.1.1) + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.1.1) + +Here is the newest release of dcm2bids ! 🎉 🥳 + +No new feature but two useful fixes ! +Hope you like this new feature less buggy ⛔ 🐛 + +Arnaud and Sam + +### What's Changed + +- Bump gitpython from 3.1.35 to 3.1.37 by [@dependabot](https://github.com/dependabot) in [#277](https://github.com/UNFmontreal/Dcm2Bids/pull/277) +- [BF] Auto extractors and merge regex expressions by [@arnaudbore](https://github.com/arnaudbore) in [#275](https://github.com/UNFmontreal/Dcm2Bids/pull/275) +- [ENH] fix binary by [@arnaudbore](https://github.com/arnaudbore) in [#278](https://github.com/UNFmontreal/Dcm2Bids/pull/278) + +**Full Changelog**: [3.1.0...3.1.1](https://github.com/UNFmontreal/Dcm2Bids/compare/3.1.0...3.1.1) + +## [3.1.0](https://github.com/UNFmontreal/Dcm2Bids/releases/tag/3.1.0) - 2023-09-13 + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.1.0) + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.1.0) + +We are excited to announce the newest release of dcm2bids ! 🎉 🥳 + +This update introduces some new features, improvements, and bug fixes to enhance your DICOM to BIDS conversion experience. +Everything embedded into this version comes from the community ❤️. Here are few examples. + +- During OHBM we've been asked to support archives as a dicom input, it's part of Dcm2bids 3.1.0. Check `dcm2bids --help` output. [link](https://unfmontreal.github.io/Dcm2Bids/3.1.0/tutorial/first-steps/#running-dcm2bids) +- While helping people on Neurostars, [@smeisler](https://github.com/smeisler) indicates that he needed to run pydeface after dcm2bids conversion since he needed both versions before and after defacing, it's now part of Dcm2bids 3.1.0. Check custom_entities in post-op section. [link](https://unfmontreal.github.io/Dcm2Bids/3.1.0/how-to/use-advanced-commands/#post_op) +- If you want to speed up dcm2bids conversion [@SamGuay](https://github.com/SamGuay) wrote a really nice [tutorial](https://unfmontreal.github.io/Dcm2Bids/3.1.0/tutorial/parallel/) to convert your data faster than ever. + +Your questions and concerns remain our top priority and continue to shape the future of Dcm2bids! + +Thank you +Arnaud and Sam + +We would like to thank [@smeisler](https://github.com/smeisler), [@Remi-Gau](https://github.com/Remi-Gau), [@raniaezzo](https://github.com/raniaezzo), [@arokem](https://github.com/arokem) and the users from [neurostars](https://neurostars.org/tag/dcm2bids) for their feedbacks. + +### What's Changed + +- [MAINT] validate citation.cff by [@Remi-Gau](https://github.com/Remi-Gau) in [#257](https://github.com/UNFmontreal/Dcm2Bids/pull/257) +- Bump gitpython from 3.1.32 to 3.1.34 by [@dependabot](https://github.com/dependabot) in [#259](https://github.com/UNFmontreal/Dcm2Bids/pull/259) +- Bump gitpython from 3.1.34 to 3.1.35 by [@dependabot](https://github.com/dependabot) in [#261](https://github.com/UNFmontreal/Dcm2Bids/pull/261) +- Fix typos in scaffold files by [@SamGuay](https://github.com/SamGuay) in [#263](https://github.com/UNFmontreal/Dcm2Bids/pull/263) +- [ENH] Add possibility to input dicom tar or zip archives by [@arnaudbore](https://github.com/arnaudbore) in [#262](https://github.com/UNFmontreal/Dcm2Bids/pull/262) +- Fix post op - pydeface by [@arnaudbore](https://github.com/arnaudbore) in [#260](https://github.com/UNFmontreal/Dcm2Bids/pull/260) +- Fix release tags in GHA by [@SamGuay](https://github.com/SamGuay) in [#266](https://github.com/UNFmontreal/Dcm2Bids/pull/266) +- Release 3.0.3 by [@arnaudbore](https://github.com/arnaudbore) in [#265](https://github.com/UNFmontreal/Dcm2Bids/pull/265) +- [ENH] - Automate help message in doc by [@SamGuay](https://github.com/SamGuay) in [#267](https://github.com/UNFmontreal/Dcm2Bids/pull/267) +- [DOC] - Tutorial on parallel x dcm2bids by [@SamGuay](https://github.com/SamGuay) in [#268](https://github.com/UNFmontreal/Dcm2Bids/pull/268) + +**Full Changelog**: [3.0.2...3.1.0](https://github.com/UNFmontreal/Dcm2Bids/compare/3.0.2...3.1.0) + +## [3.0.2](https://github.com/UNFmontreal/Dcm2Bids/releases/tag/3.0.2) - 2023-31-23 + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.2) + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.2) + +First of all thank you to everybody who came see our poster during OHBM 2023 in Montreal ! + +We listened to you and we added an option to reorganize your NIFTIs into a BIDS structure. Check this [link](https://unfmontreal.github.io/Dcm2Bids/3.0.1/how-to/use-advanced-commands/#-skip_dcm2niix). +We also extended the possibilities provided by the item sidecar_changes. + +Congrats 🥳 + +### What's Changed + +- codespell: add config and action to codespell the code to avoid known typos by [@yarikoptic](https://github.com/yarikoptic) in [#245](https://github.com/UNFmontreal/Dcm2Bids/pull/245) +- Bump certifi from 2023.5.7 to 2023.7.22 by [@dependabot](https://github.com/dependabot) in [#247](https://github.com/UNFmontreal/Dcm2Bids/pull/247) +- Bring all 3 Arnauds into 1 by [@yarikoptic](https://github.com/yarikoptic) in [#246](https://github.com/UNFmontreal/Dcm2Bids/pull/246) +- Add option to skip_dcm2niix and reorganize NIFTI and JSON files by [@arnaudbore](https://github.com/arnaudbore) in [#248](https://github.com/UNFmontreal/Dcm2Bids/pull/248) +- Allowing Numericals in JSON custom fields by [@smeisler](https://github.com/smeisler) in [#250](https://github.com/UNFmontreal/Dcm2Bids/pull/250) +- Bump gitpython from 3.1.31 to 3.1.32 by [@dependabot](https://github.com/dependabot) in [#251](https://github.com/UNFmontreal/Dcm2Bids/pull/251) + +### New Contributors + +- [@yarikoptic](https://github.com/yarikoptic) made their first contribution in [#245](https://github.com/UNFmontreal/Dcm2Bids/pull/245) +- [@dependabot](https://github.com/dependabot) made their first contribution in [#247](https://github.com/UNFmontreal/Dcm2Bids/pull/247) + +**Full Changelog**: [3.0.1...3.0.2](https://github.com/UNFmontreal/Dcm2Bids/compare/3.0.1...3.0.2) + +## [3.0.1](https://github.com/UNFmontreal/Dcm2Bids/releases/tag/3.0.1) - 2023-07-23 + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.1) + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.1) + +We could not be more proud of the 3.0.1 dcm2bids release 😊 . We put everything we've learned from our past experiences and listen to all our users' ideas into this version. + +Advanced searching criterias such as extractors combined with custom entities, the ability to compare floats or the auto_extract_entities option directly accessible from dcm2bids command will make the conversion to BIDS smoother than ever and significantly reduce the complexity and the length of your configuration file especially for multi-site acquisitions. + +We highly encourage you to dive into the [documentation](https://unfmontreal.github.io/Dcm2Bids/3.0.1) since we added quite a lot of new features. + +Please don't hesitate to give us your feedback using this [#240](https://github.com/UNFmontreal/Dcm2Bids/discussions/240). + +Thank you again for all our users who contributed in some ways to this release. Thank you [@SamGuay](https://github.com/SamGuay) for the long discussions and late debug sessions. 🎉 + +Arnaud + +### What's Changed + +- [DOC] fix typo and add detail about entity reordering by [@Remi-Gau](https://github.com/Remi-Gau) in [#183](https://github.com/UNFmontreal/Dcm2Bids/pull/183) +- update version to match release by [@SamGuay](https://github.com/SamGuay) in [#185](https://github.com/UNFmontreal/Dcm2Bids/pull/185) +- [ENH] Refactorisation - Major API upgrade by [@arnaudbore](https://github.com/arnaudbore) in [#200](https://github.com/UNFmontreal/Dcm2Bids/pull/200) +- Get README from bids toolkit by [@arnaudbore](https://github.com/arnaudbore) in [#201](https://github.com/UNFmontreal/Dcm2Bids/pull/201) +- Add bids-validator option by [@arnaudbore](https://github.com/arnaudbore) in [#206](https://github.com/UNFmontreal/Dcm2Bids/pull/206) +- Upgrade feature Intended for by [@arnaudbore](https://github.com/arnaudbore) in [#207](https://github.com/UNFmontreal/Dcm2Bids/pull/207) +- [ENH] Upgrade custom entities by [@arnaudbore](https://github.com/arnaudbore) in [#208](https://github.com/UNFmontreal/Dcm2Bids/pull/208) +- [FIX] Broken scaffold no more by [@SamGuay](https://github.com/SamGuay) in [#209](https://github.com/UNFmontreal/Dcm2Bids/pull/209) +- [FIX,ENH] - Improve dcm2bids_helper mod by [@SamGuay](https://github.com/SamGuay) in [#210](https://github.com/UNFmontreal/Dcm2Bids/pull/210) +- Generalization of sidecarchanges using ids by [@arnaudbore](https://github.com/arnaudbore) in [#213](https://github.com/UNFmontreal/Dcm2Bids/pull/213) +- [ENH] dataType -> datatype and modalityLabel -> suffix by [@arnaudbore](https://github.com/arnaudbore) in [#214](https://github.com/UNFmontreal/Dcm2Bids/pull/214) +- Fix log n version by [@SamGuay](https://github.com/SamGuay) in [#219](https://github.com/UNFmontreal/Dcm2Bids/pull/219) +- [BF] valid participant by [@arnaudbore](https://github.com/arnaudbore) in [#215](https://github.com/UNFmontreal/Dcm2Bids/pull/215) +- Allow a criteria item to be a dict with a key - any (or) or all (and) by [@arnaudbore](https://github.com/arnaudbore) in [#217](https://github.com/UNFmontreal/Dcm2Bids/pull/217) +- Add an option to use duplicates instead of runs as suggested in heudiconv project. by [@arnaudbore](https://github.com/arnaudbore) in [#218](https://github.com/UNFmontreal/Dcm2Bids/pull/218) +- [BF] Valid session by [@arnaudbore](https://github.com/arnaudbore) in [#222](https://github.com/UNFmontreal/Dcm2Bids/pull/222) +- add test helper by [@arnaudbore](https://github.com/arnaudbore) in [#220](https://github.com/UNFmontreal/Dcm2Bids/pull/220) +- [BF] dcm2bids_scaffold by [@arnaudbore](https://github.com/arnaudbore) in [#224](https://github.com/UNFmontreal/Dcm2Bids/pull/224) +- prevent doc deployment by pushing to master by [@SamGuay](https://github.com/SamGuay) in [#226](https://github.com/UNFmontreal/Dcm2Bids/pull/226) +- [ENH] Add major OS executables on new release by [@SamGuay](https://github.com/SamGuay) in [#221](https://github.com/UNFmontreal/Dcm2Bids/pull/221) +- [ENH] Generalization of defaceTpl to post_op by [@arnaudbore](https://github.com/arnaudbore) in [#225](https://github.com/UNFmontreal/Dcm2Bids/pull/225) +- [ENH] Rename all cap var by [@arnaudbore](https://github.com/arnaudbore) in [#227](https://github.com/UNFmontreal/Dcm2Bids/pull/227) +- Revert doc to 2.1.9 by [@arnaudbore](https://github.com/arnaudbore) in [#228](https://github.com/UNFmontreal/Dcm2Bids/pull/228) +- Automated version-control documentation for 2.1.9 and up by [@SamGuay](https://github.com/SamGuay) in [#231](https://github.com/UNFmontreal/Dcm2Bids/pull/231) +- Fix GHA for docs + layouts by [@SamGuay](https://github.com/SamGuay) in [#234](https://github.com/UNFmontreal/Dcm2Bids/pull/234) +- [ENH] Add float comparison by [@arnaudbore](https://github.com/arnaudbore) in [#229](https://github.com/UNFmontreal/Dcm2Bids/pull/229) +- [Quick Fix] Add specific message when no acquisition was found by [@arnaudbore](https://github.com/arnaudbore) in [#235](https://github.com/UNFmontreal/Dcm2Bids/pull/235) +- Fix typo src_file dst_file by [@arnaudbore](https://github.com/arnaudbore) in [#236](https://github.com/UNFmontreal/Dcm2Bids/pull/236) +- Improve doc for v3.0.0 by [@arnaudbore](https://github.com/arnaudbore) in [#223](https://github.com/UNFmontreal/Dcm2Bids/pull/223) +- [FIX] - update the alias for dev and latest by [@SamGuay](https://github.com/SamGuay) in [#237](https://github.com/UNFmontreal/Dcm2Bids/pull/237) +- Quick fix version by [@arnaudbore](https://github.com/arnaudbore) in [#238](https://github.com/UNFmontreal/Dcm2Bids/pull/238) +- Update docs by [@smeisler](https://github.com/smeisler) in [#239](https://github.com/UNFmontreal/Dcm2Bids/pull/239) +- [BF] fix sidecars suggested by Sam by [@arnaudbore](https://github.com/arnaudbore) in [#243](https://github.com/UNFmontreal/Dcm2Bids/pull/243) + +### New Contributors + +- [@Remi-Gau](https://github.com/Remi-Gau) made their first contribution in [#183](https://github.com/UNFmontreal/Dcm2Bids/pull/183) +- [@smeisler](https://github.com/smeisler) made their first contribution in [#239](https://github.com/UNFmontreal/Dcm2Bids/pull/239) + +**Full Changelog**: [2.1.9...3.0.1](https://github.com/UNFmontreal/Dcm2Bids/compare/2.1.9...3.0.1) + +## [3.0.0rc1](https://github.com/UNFmontreal/Dcm2Bids/releases/tag/3.0.0rc1) - 2023-07-17 + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.0rc1) + +[](https://github.com/UNFmontreal/Dcm2Bids/releases/edit/3.0.0rc1) + +Ok let's be clear after working very hard on this we are definitively biased so we decided to ask ChatGPT to write for us a short fun description for our brand new version. + +Introducing the latest version of dcm2bids: the superhero of medical imaging data conversion! With simplified configuration, enhanced DICOM handling, comprehensive data validation, advanced options, and amazing new features, dcm2bids will transform your data into BIDS format like magic. Join the fun and unleash your scientific superpowers today! + +Please check the documentation 🎉 + +⚠️This is a release candidate. + +### What's Changed + +- [DOC] fix typo and add detail about entity reordering by [@Remi-Gau](https://github.com/Remi-Gau) in [#183](https://github.com/UNFmontreal/Dcm2Bids/pull/183) +- update version to match release by [@SamGuay](https://github.com/SamGuay) in [#185](https://github.com/UNFmontreal/Dcm2Bids/pull/185) +- [ENH] Refactorisation - Major API upgrade by [@arnaudbore](https://github.com/arnaudbore) in [#200](https://github.com/UNFmontreal/Dcm2Bids/pull/200) +- Get README from bids toolkit by [@arnaudbore](https://github.com/arnaudbore) in [#201](https://github.com/UNFmontreal/Dcm2Bids/pull/201) +- Add bids-validator option by [@arnaudbore](https://github.com/arnaudbore) in [#206](https://github.com/UNFmontreal/Dcm2Bids/pull/206) +- Upgrade feature Intended for by [@arnaudbore](https://github.com/arnaudbore) in [#207](https://github.com/UNFmontreal/Dcm2Bids/pull/207) +- [ENH] Upgrade custom entities by [@arnaudbore](https://github.com/arnaudbore) in [#208](https://github.com/UNFmontreal/Dcm2Bids/pull/208) +- [FIX] Broken scaffold no more by [@SamGuay](https://github.com/SamGuay) in [#209](https://github.com/UNFmontreal/Dcm2Bids/pull/209) +- [FIX,ENH] - Improve dcm2bids_helper mod by [@SamGuay](https://github.com/SamGuay) in [#210](https://github.com/UNFmontreal/Dcm2Bids/pull/210) +- Generalization of sidecarchanges using ids by [@arnaudbore](https://github.com/arnaudbore) in [#213](https://github.com/UNFmontreal/Dcm2Bids/pull/213) +- [ENH] dataType -> datatype and modalityLabel -> suffix by [@arnaudbore](https://github.com/arnaudbore) in [#214](https://github.com/UNFmontreal/Dcm2Bids/pull/214) +- Fix log n version by [@SamGuay](https://github.com/SamGuay) in [#219](https://github.com/UNFmontreal/Dcm2Bids/pull/219) +- [BF] valid participant by [@arnaudbore](https://github.com/arnaudbore) in [#215](https://github.com/UNFmontreal/Dcm2Bids/pull/215) +- Allow a criteria item to be a dict with a key - any (or) or all (and) by [@arnaudbore](https://github.com/arnaudbore) in [#217](https://github.com/UNFmontreal/Dcm2Bids/pull/217) +- Add an option to use duplicates instead of runs as suggested in heudiconv project. by [@arnaudbore](https://github.com/arnaudbore) in [#218](https://github.com/UNFmontreal/Dcm2Bids/pull/218) +- [BF] Valid session by [@arnaudbore](https://github.com/arnaudbore) in [#222](https://github.com/UNFmontreal/Dcm2Bids/pull/222) +- add test helper by [@arnaudbore](https://github.com/arnaudbore) in [#220](https://github.com/UNFmontreal/Dcm2Bids/pull/220) +- [BF] dcm2bids_scaffold by [@arnaudbore](https://github.com/arnaudbore) in [#224](https://github.com/UNFmontreal/Dcm2Bids/pull/224) +- prevent doc deployment by pushing to master by [@SamGuay](https://github.com/SamGuay) in [#226](https://github.com/UNFmontreal/Dcm2Bids/pull/226) +- [ENH] Add major OS executables on new release by [@SamGuay](https://github.com/SamGuay) in [#221](https://github.com/UNFmontreal/Dcm2Bids/pull/221) +- [ENH] Generalization of defaceTpl to post_op by [@arnaudbore](https://github.com/arnaudbore) in [#225](https://github.com/UNFmontreal/Dcm2Bids/pull/225) +- [ENH] Rename all cap var by [@arnaudbore](https://github.com/arnaudbore) in [#227](https://github.com/UNFmontreal/Dcm2Bids/pull/227) +- Revert doc to 2.1.9 by [@arnaudbore](https://github.com/arnaudbore) in [#228](https://github.com/UNFmontreal/Dcm2Bids/pull/228) +- Automated version-control documentation for 2.1.9 and up by [@SamGuay](https://github.com/SamGuay) in [#231](https://github.com/UNFmontreal/Dcm2Bids/pull/231) +- Fix GHA for docs + layouts by [@SamGuay](https://github.com/SamGuay) in [#234](https://github.com/UNFmontreal/Dcm2Bids/pull/234) +- [ENH] Add float comparison by [@arnaudbore](https://github.com/arnaudbore) in [#229](https://github.com/UNFmontreal/Dcm2Bids/pull/229) +- [Quick Fix] Add specific message when no acquisition was found by [@arnaudbore](https://github.com/arnaudbore) in [#235](https://github.com/UNFmontreal/Dcm2Bids/pull/235) +- Fix typo src_file dst_file by [@arnaudbore](https://github.com/arnaudbore) in [#236](https://github.com/UNFmontreal/Dcm2Bids/pull/236) +- Improve doc for v3.0.0 by [@arnaudbore](https://github.com/arnaudbore) in [#223](https://github.com/UNFmontreal/Dcm2Bids/pull/223) + +### New Contributors + +- [@Remi-Gau](https://github.com/Remi-Gau) made their first contribution in [#183](https://github.com/UNFmontreal/Dcm2Bids/pull/183) + +**Full Changelog**: [2.1.8...3.0.0rc1](https://github.com/UNFmontreal/Dcm2Bids/compare/2.1.8...3.0.0rc1) + ## **2.1.9 - 2022-06-17** Some issues with pypi. Sorry for this. From 3ab67f034bb2bc456099d13ac8a63c1f9d084504 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Wed, 24 Jul 2024 16:34:53 -0400 Subject: [PATCH 24/40] fix log and output folder for dcm2bids_helper (#312) --- dcm2bids/cli/dcm2bids_helper.py | 23 +++++++++++++++-------- dcm2bids/dcm2niix_gen.py | 2 -- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/dcm2bids/cli/dcm2bids_helper.py b/dcm2bids/cli/dcm2bids_helper.py index 6e2599f7..8a8548aa 100644 --- a/dcm2bids/cli/dcm2bids_helper.py +++ b/dcm2bids/cli/dcm2bids_helper.py @@ -15,7 +15,6 @@ from dcm2bids.utils.utils import DEFAULT from dcm2bids.utils.tools import dcm2niix_version, check_latest from dcm2bids.utils.logger import setup_logging -from dcm2bids.utils.args import assert_dirs_empty from dcm2bids.version import __version__ @@ -59,12 +58,22 @@ def main(): """Let's go""" parser = _build_arg_parser() args = parser.parse_args() - out_dir = Path(args.output_dir) - log_file = (Path(DEFAULT.output_dir) - / DEFAULT.tmp_dir_name - / "log" - / f"helper_{datetime.now().strftime('%Y%m%d-%H%M%S')}.log") + out_dir = Path(args.output_dir) + if args.output_dir != parser.get_default('output_dir'): + out_dir = (Path(args.output_dir) + / DEFAULT.tmp_dir_name + / DEFAULT.helper_dir) + + log_file = (Path(args.output_dir) + / DEFAULT.tmp_dir_name + / "log" + / f"helper_{datetime.now().strftime('%Y%m%d-%H%M%S')}.log") + else: + log_file = (Path(DEFAULT.output_dir) + / DEFAULT.tmp_dir_name + / "log" + / f"helper_{datetime.now().strftime('%Y%m%d-%H%M%S')}.log") if args.nest: if isinstance(args.nest, str): log_file = Path( @@ -94,8 +103,6 @@ def main(): check_latest("dcm2bids") check_latest("dcm2niix") - assert_dirs_empty(parser, args, out_dir) - app = Dcm2niixGen(dicom_dirs=args.dicom_dir, bids_dir=out_dir, helper=True) rsl = app.run(force=args.overwrite) diff --git a/dcm2bids/dcm2niix_gen.py b/dcm2bids/dcm2niix_gen.py index 47698b6a..d43e81fe 100644 --- a/dcm2bids/dcm2niix_gen.py +++ b/dcm2bids/dcm2niix_gen.py @@ -151,8 +151,6 @@ def execute(self): else: self.logger.debug(f"\n{output}") self.logger.info("Check log file for dcm2niix output\n") - - else: for dicomDir in self.dicom_dirs: shutil.copytree(dicomDir, self.output_dir, dirs_exist_ok=True) From 027d5fb33e119e33db7dacd001ec74a540cd9ef1 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 17:45:02 -0400 Subject: [PATCH 25/40] add container doc --- CHANGELOG.md | 2 +- README.md | 4 +- containers/Dockerfile | 26 -------- containers/singularity.def | 2 - docs/get-started/install.md | 25 ++++---- docs/how-to/container.md | 115 ++++++++++++++++++++++++++++++++++++ docs/how-to/index.md | 2 + mkdocs.yml | 4 +- 8 files changed, 137 insertions(+), 43 deletions(-) delete mode 100644 containers/Dockerfile delete mode 100644 containers/singularity.def create mode 100644 docs/how-to/container.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ff3ae3..21ab9c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,7 +95,7 @@ Congrats 🥳 We could not be more proud of the 3.0.1 dcm2bids release 😊 . We put everything we've learned from our past experiences and listen to all our users' ideas into this version. -Advanced searching criterias such as extractors combined with custom entities, the ability to compare floats or the auto_extract_entities option directly accessible from dcm2bids command will make the conversion to BIDS smoother than ever and significantly reduce the complexity and the length of your configuration file especially for multi-site acquisitions. +Advanced searching criteria such as extractors combined with custom entities, the ability to compare floats or the auto_extract_entities option directly accessible from dcm2bids command will make the conversion to BIDS smoother than ever and significantly reduce the complexity and the length of your configuration file especially for multi-site acquisitions. We highly encourage you to dive into the [documentation](https://unfmontreal.github.io/Dcm2Bids/3.0.1) since we added quite a lot of new features. diff --git a/README.md b/README.md index d249d0bb..67359872 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ Please take a look at the [documentation][dcm2bids-doc] to: * [Learn about bids][bids-spec] with some dataset [examples][bids-examples] * [Install dcm2bids][dcm2bids-install] -* [Follow the tutorial][dcm2bids-tutorial] +* [Use docker and Apptainer/Singularity][dcm2bids-container] +* [Follow the tutorials][dcm2bids-tutorial] * [Seek for more advanced usage][dcm2bids-advanced] ## Issues and Questions @@ -68,6 +69,7 @@ Before posting your question, you may want to first browse through questions tha [dcm2bids-install]: https://unfmontreal.github.io/Dcm2Bids/latest/get-started/install/ [dcm2bids-tutorial]: https://unfmontreal.github.io/Dcm2Bids/latest/tutorial/first-steps/#tutorial-first-steps [dcm2bids-advanced]: https://unfmontreal.github.io/Dcm2Bids/latest/advanced/ +[dcm2bids-container]: https://unfmontreal.github.io/Dcm2Bids/latest/how-to/container/ [dcm2bids-upgrade]: https://unfmontreal.github.io/Dcm2Bids/dev/upgrade/ [dcm2bids-issues]: https://github.com/UNFmontreal/Dcm2Bids/issues [dcm2niix-install]: https://github.com/rordenlab/dcm2niix#install diff --git a/containers/Dockerfile b/containers/Dockerfile deleted file mode 100644 index c23b365f..00000000 --- a/containers/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -From ubuntu:latest -ENV DEBIAN_FRONTEND=noninteractive - -MAINTAINER Arnaud Boré - -RUN apt-get update -RUN apt-get -y upgrade - -RUN apt-get -y install wget build-essential cmake git pigz \ - nodejs python3 python3-pip unzip - -RUN pip3 install dcm2bids - -# Install dcm2niix from github -ENV DCM2NIIX_VERSION="v1.0.20230411" - -WORKDIR /usr/local/src -RUN git clone https://github.com/rordenlab/dcm2niix.git -WORKDIR /usr/local/src/dcm2niix -RUN git checkout tags/${DCM2NIIX_VERSION} -b install -RUN mkdir build -WORKDIR /usr/local/src/dcm2niix/build -RUN cmake .. -RUN make install - -WORKDIR / diff --git a/containers/singularity.def b/containers/singularity.def deleted file mode 100644 index 101dde23..00000000 --- a/containers/singularity.def +++ /dev/null @@ -1,2 +0,0 @@ -BootStrap: docker -From: unfmontreal/dcm2bids:latest diff --git a/docs/get-started/install.md b/docs/get-started/install.md index f3d05540..b3da9988 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -9,6 +9,19 @@ date: 2022-04-17 There are several ways to install dcm2bids. +## Containers + +We provide a container image that includes both dcm2niix and dcm2bids as well as pydeface and the BIDS validator. +You can install it using [Docker][docker] or [Apptainer/Singularity][apptainer]. + +=== "Docker" + + `docker pull unfmontreal/dcm2bids:latest` + +=== "Apptainer/Singularity" + + `singularity pull dcm2bids_latest.sif docker://unfmontreal/dcm2bids:latest` + ## Installing binary executables From dcm2bids>=3.0.0, we provide binaries for macOS, Windows and Linux @@ -353,18 +366,6 @@ Voilà, you are ready to use dcm2bids or at least [Go to the How-to section](../../how-to/){ .md-button } -## Containers - -We also provide a container image that includes both dcm2niix and dcm2bids which -you can install using [Docker][docker] or [Apptainer/Singularity][apptainer]. - -=== "Docker" - - `docker pull unfmontreal/dcm2bids:latest` - -=== "Apptainer/Singularity" - - `singularity pull dcm2bids_latest.sif docker://unfmontreal/dcm2bids:latest ` ## Summary of the steps diff --git a/docs/how-to/container.md b/docs/how-to/container.md new file mode 100644 index 00000000..d33550ac --- /dev/null +++ b/docs/how-to/container.md @@ -0,0 +1,115 @@ +# dcm2bids with Docker and Apptainer / Singularity + +We provide a container image that includes both dcm2niix and dcm2bids as well as pydeface and the BIDS validator. You can find it on [Docker Hub/r/unfmontreal/dcm2bids](https://hub.docker.com/r/unfmontreal/dcm2bids). + +You can install it using [Docker](https://www.docker.com/get-started) or [Apptainer/Singularity](https://www.apptainer.org). + +## Prerequisites + +Before you begin, make sure you have at least one of the following installed: + +- Docker: [Download and install Docker](https://www.docker.com/get-started) +- Apptainer, formerly known as Singularity : [Download and install Apptainer](https://apptainer.org/docs/admin/main/installation.html) + +!!! note + If you are using a HPC cluster, Apptainer is the recommended choice and is probably installed on your system. Simply load the module (e.g., + `module load apptainer`) and use the `apptainer` command, + +## Step 1: Pull the dcm2bids container + +To start, you can either pull the dcm2bids image from the Docker Hub repository or [build it from the Dockerfile in the repository](https://github.com/UNFmontreal/Dcm2Bids/blob/dev/Dockerfile).: + +=== "Docker" + + ``` + docker pull unfmontreal/dcm2bids:latest + ``` + +=== "Apptainer/Singularity" + + ``` + apptainer pull dcm2bids.sif docker://unfmontreal/dcm2bids:latest + ``` + +## Step 2: Test dcm2bids + +The default command, or the point of entry, for the container is `dcm2bids`. So every time you run the container, you can pass the `dcm2bids` arguments and options directly. To test the container, run the following command to display the help message for the `dcm2bids` command. + +=== "Docker" + + ``` + docker run --rm -it unfmontreal/dcm2bids:latest --help + ``` + +=== "Apptainer/Singularity" + + ``` + apptainer run dcm2bids.sif --help + ``` + +## Step 3: Run `dcm2bids_scaffold` + +To run `dcm2bids_scaffold`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). You need to bind the respective volumes. + +=== "Docker" + + ``` + docker run + ``` + +=== "Apptainer/Singularity" + + ``` + singularity exec \ + -B /path/to/output-dir:/output \ + dcm2bids.sif dcm2bids_scaffold -o /output/new_bids_dataset + ``` + + +## Step 4: Run `dcm2bids_helper` + +To run `dcm2bids_helper`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). To bind the respective volumes, you have two options: + +1. Put the input data in the same parent directory as the output directory. +2. Specify the input data directory as a separate volume. + +If you bind the newly scaffolded directory on its own, you can simply use the `-o /output` instead of having to specify the full path to the scaffolded directory. Same goes for the input data directory, if the input data directory is one subject, you can bind it directly to `/input`. If it is the parent directory of multiple subjects, you can bind it to `/input` and specify the specific subject directory (e.g, `-d /input/subject-01`). + +=== "Docker" + + ``` + docker run + ``` + +=== "Apptainer/Singularity" + + ``` + singularity exec \ + -B /path/to/input-data:/input \ + -B /path/to/output-dir/new_bids_dataset:/output \ + dcm2bids.sif dcm2bids_helper -o /output -d /input + ``` + +## Step 5: Run `dcm2bids` + +You can use `run` as in Step 2 or use `exec dcm2bids` to run `dcm2bids` with the appropriate arguments and options. You need to bind the respective volumes. + +You can put input data in the same parent directory as the output directory, or you can specify the input data directory as a separate volume. You must also specify the path to the configuration file. If you use the scaffolded dataset, the config file is usually in the `code/` directory. + +You can also deface your data and validate your BIDS data using the `--bids_validate` flag. + +=== "Docker" + + ``` + docker run --rm -v + ``` + +=== "Apptainer/Singularity" + + ``` + singularity run \ + -B /path/to/input-data:/input \ + -B /path/to/output-dir/new_bids_dataset:/output \ + dcm2bids.sif --auto_extract_entities --bids_validate \ + -o /output -d /input -c /output/code/config.json -p 001 + ``` diff --git a/docs/how-to/index.md b/docs/how-to/index.md index 1c8e215a..77ca0ce6 100644 --- a/docs/how-to/index.md +++ b/docs/how-to/index.md @@ -16,6 +16,8 @@ title: How-to guides - [Use advanced commands](./use-advanced-commands.md) +- [Use dcm2bids with Docker or Apptainer/Singularity](./container.md) + ## Development and Community - [Contribute to dcm2bids](./contributing.md) diff --git a/mkdocs.yml b/mkdocs.yml index f41d4b26..cfe0631c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,10 +29,11 @@ nav: - Use main commands: how-to/use-main-commands.md - Create a config file: how-to/create-config-file.md - Use advanced commands: how-to/use-advanced-commands.md + - Use container images: how-to/container.md + - Upgrade dcm2bids: upgrade.md - Contribute to dcm2bids: how-to/contributing.md - Changelog: - changelog/index.md - - How to upgrade: upgrade.md - API Reference: dcm2bids - Code of conduct: code_of_conduct.md @@ -76,6 +77,7 @@ theme: - content.action.view - content.code.annotate - content.code.copy + # - content.tabs.link - content.tooltips - navigation.footer - navigation.indexes From 5f7aee6ec1920025d4433e0fb2eee8ad0636463d Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Wed, 24 Jul 2024 17:45:09 -0400 Subject: [PATCH 26/40] bump version --- dcm2bids/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcm2bids/version.py b/dcm2bids/version.py index f9b3b65c..530c5ab3 100644 --- a/dcm2bids/version.py +++ b/dcm2bids/version.py @@ -2,8 +2,8 @@ # Format expected by setup.py and doc/source/conf.py: string of form "X.Y.Z" _version_major = 3 -_version_minor = 1 -_version_micro = 1 +_version_minor = 2 +_version_micro = 0 _version_extra = '' # Construct full version string from these. From 89445ca6115db5cc43afe36a7b0b5b4dd02933c5 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 25 Jul 2024 13:38:51 -0400 Subject: [PATCH 27/40] update container with links --- docs/how-to/container.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index d33550ac..6c5af36e 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -49,12 +49,15 @@ The default command, or the point of entry, for the container is `dcm2bids`. So ## Step 3: Run `dcm2bids_scaffold` -To run `dcm2bids_scaffold`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). You need to bind the respective volumes. +To run `dcm2bids_scaffold`, `with singularity`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). You need to bind the respective volumes. === "Docker" ``` - docker run + docker run --rm -it \ + --entrypoint /venv/bin/dcm2bids_scaffold \ + -v /path/to/output-dir:/output \ + unfmontreal/dcm2bids:latest -o /output/new_bids_dataset ``` === "Apptainer/Singularity" @@ -68,7 +71,7 @@ To run `dcm2bids_scaffold`, you need to *execute* a command instead of *running* ## Step 4: Run `dcm2bids_helper` -To run `dcm2bids_helper`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). To bind the respective volumes, you have two options: +To run `dcm2bids_helper`, `with singularity`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). To bind the respective volumes, you have two options: 1. Put the input data in the same parent directory as the output directory. 2. Specify the input data directory as a separate volume. @@ -78,7 +81,10 @@ If you bind the newly scaffolded directory on its own, you can simply use the `- === "Docker" ``` - docker run + docker run --rm -it --entrypoint /venv/bin/dcm2bids_helper \ + -v /path/to/input-data:/input \ + -v /path/to/output-dir/new_bids_dataset:/output \ + unfmontreal/dcm2bids:latest -o /output -d /input ``` === "Apptainer/Singularity" @@ -96,12 +102,16 @@ You can use `run` as in Step 2 or use `exec dcm2bids` to run `dcm2bids` with the You can put input data in the same parent directory as the output directory, or you can specify the input data directory as a separate volume. You must also specify the path to the configuration file. If you use the scaffolded dataset, the config file is usually in the `code/` directory. -You can also deface your data and validate your BIDS data using the `--bids_validate` flag. +You can also [deface your data](use-advanced-commands.md#post_op) and [validate your BIDS data](use-advanced-commands.md#-bids_validate) using the `--bids_validate` flag. === "Docker" ``` - docker run --rm -v + docker run --rm -it \ + -B /path/to/input-data:/input \ + -B /path/to/output-dir/new_bids_dataset:/output \ + unfmontreal/dcm2bids:latest --auto_extract_entities --bids_validate \ + -o /output -d /input -c /output/code/config.json -p 001 ``` === "Apptainer/Singularity" From d8f3482d4989aefefcc5f7e85de151efc681246c Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Thu, 25 Jul 2024 14:03:43 -0400 Subject: [PATCH 28/40] fix typo --- docs/how-to/container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index 6c5af36e..dd4589ea 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -1,6 +1,6 @@ # dcm2bids with Docker and Apptainer / Singularity -We provide a container image that includes both dcm2niix and dcm2bids as well as pydeface and the BIDS validator. You can find it on [Docker Hub/r/unfmontreal/dcm2bids](https://hub.docker.com/r/unfmontreal/dcm2bids). +We provide a container image that includes both dcm2niix and dcm2bids as well as pydeface and the BIDS validator. You can find it on [Docker Hub](https://hub.docker.com/r/unfmontreal/dcm2bids). You can install it using [Docker](https://www.docker.com/get-started) or [Apptainer/Singularity](https://www.apptainer.org). From 8f6d1bf86128746df0354d2d965936e9a6656569 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Thu, 25 Jul 2024 14:42:42 -0400 Subject: [PATCH 29/40] Update docs/how-to/container.md Co-authored-by: Samuel Guay --- docs/how-to/container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index dd4589ea..1eaa29fe 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -71,7 +71,7 @@ To run `dcm2bids_scaffold`, `with singularity`, you need to *execute* a command ## Step 4: Run `dcm2bids_helper` -To run `dcm2bids_helper`, `with singularity`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). To bind the respective volumes, you have two options: +To run `dcm2bids_helper` with Apptainer/Singularity, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). To bind the respective volumes, you have two options: 1. Put the input data in the same parent directory as the output directory. 2. Specify the input data directory as a separate volume. From d656c1726c88adab0f3b347a6aa7e780c5f52359 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Thu, 25 Jul 2024 14:42:48 -0400 Subject: [PATCH 30/40] Update docs/how-to/container.md Co-authored-by: Samuel Guay --- docs/how-to/container.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index 1eaa29fe..39212642 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -49,7 +49,7 @@ The default command, or the point of entry, for the container is `dcm2bids`. So ## Step 3: Run `dcm2bids_scaffold` -To run `dcm2bids_scaffold`, `with singularity`, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). You need to bind the respective volumes. +To run `dcm2bids_scaffold` with Apptainer/Singularity, you need to *execute* a command instead of *running* the pre-specified command (`dcm2bids`). You need to bind the respective volumes. === "Docker" From 88383c2d668e21433021f4b8663887393de49301 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Thu, 25 Jul 2024 15:55:19 -0400 Subject: [PATCH 31/40] fix check folder (#313) --- dcm2bids/utils/args.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dcm2bids/utils/args.py b/dcm2bids/utils/args.py index 1266e4aa..cbe8164e 100644 --- a/dcm2bids/utils/args.py +++ b/dcm2bids/utils/args.py @@ -28,12 +28,12 @@ def check(path: Path): "could be overwritten or deleted.\nRerun the command " "with --force option to overwrite " "existing output files.") - else: - for child in path.iterdir(): - if child.is_file(): - os.remove(child) - elif child.is_dir(): - shutil.rmtree(child) + else: + for child in path.iterdir(): + if child.is_file(): + os.remove(child) + elif child.is_dir(): + shutil.rmtree(child) if isinstance(required, str): required = Path(required) From 27dd27eb2e86a20f145b651420b14e171f189cdf Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Thu, 25 Jul 2024 19:54:19 -0400 Subject: [PATCH 32/40] Update docs/how-to/create-config-file.md Co-authored-by: Steven Meisler --- docs/how-to/create-config-file.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to/create-config-file.md b/docs/how-to/create-config-file.md index 65993736..e89e5a8b 100644 --- a/docs/how-to/create-config-file.md +++ b/docs/how-to/create-config-file.md @@ -152,7 +152,7 @@ custom_entities could also be combined with extractors. See !!! tip "`--do_not_reorder_entities`" - If you prefer to have manual control over the order of `custom_entities`, you can use the `--do_not_reorder_entities` flag. This flag allows you to keep the order defined by you, the user, in the `custom_entities` field. However, please note that this flag cannot be used in conjunction with the `--auto_extract_entities` flag. + If you prefer to have manual control over the order of `custom_entities`, you can use the `--do_not_reorder_entities` flag. This flag allows you to keep the order defined by you, the user, in the `custom_entities` field. However, please note that this flag cannot be used in conjunction with the `--auto_extract_entities` flag. Also please keep in mind that a custom non-BIDS compliant entity order may preclude downstream usage of BIDS apps such as fMRIPrep. ## sidecar_changes, id and IntendedFor From 5e645fdf8ef9ff60e023a000084a537d6596ee6c Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 26 Jul 2024 08:37:41 -0400 Subject: [PATCH 33/40] Apply suggestions from code review Edited a bit to make sure dcm2bids_scaffold creates it in a newly created dir. Co-authored-by: Steven Meisler --- docs/how-to/container.md | 49 +++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index 39212642..e5c892ef 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -28,7 +28,7 @@ To start, you can either pull the dcm2bids image from the Docker Hub repository === "Apptainer/Singularity" ``` - apptainer pull dcm2bids.sif docker://unfmontreal/dcm2bids:latest + apptainer pull dcm2bids_${VERSION}.sif docker://unfmontreal/dcm2bids:${VERSION} ``` ## Step 2: Test dcm2bids @@ -44,7 +44,7 @@ The default command, or the point of entry, for the container is `dcm2bids`. So === "Apptainer/Singularity" ``` - apptainer run dcm2bids.sif --help + apptainer run -e --containall dcm2bids.sif --help ``` ## Step 3: Run `dcm2bids_scaffold` @@ -56,16 +56,17 @@ To run `dcm2bids_scaffold` with Apptainer/Singularity, you need to *execute* a c ``` docker run --rm -it \ --entrypoint /venv/bin/dcm2bids_scaffold \ - -v /path/to/output-dir:/output \ - unfmontreal/dcm2bids:latest -o /output/new_bids_dataset + -v /path/to/bids:/bids \ + unfmontreal/dcm2bids:${VERSION} -o /bids/new_scaffold ``` === "Apptainer/Singularity" ``` - singularity exec \ - -B /path/to/output-dir:/output \ - dcm2bids.sif dcm2bids_scaffold -o /output/new_bids_dataset + apptainer exec \ + -e --containall \ + -B /path/to/bids:/bids \ + dcm2bids.sif dcm2bids_scaffold -o /bids/new_scaffold ``` @@ -76,24 +77,24 @@ To run `dcm2bids_helper` with Apptainer/Singularity, you need to *execute* a com 1. Put the input data in the same parent directory as the output directory. 2. Specify the input data directory as a separate volume. -If you bind the newly scaffolded directory on its own, you can simply use the `-o /output` instead of having to specify the full path to the scaffolded directory. Same goes for the input data directory, if the input data directory is one subject, you can bind it directly to `/input`. If it is the parent directory of multiple subjects, you can bind it to `/input` and specify the specific subject directory (e.g, `-d /input/subject-01`). +If you bind the newly scaffolded directory on its own, you can simply use the `-o /bids` instead of having to specify the full path to the scaffolded directory. Same goes for the input data directory, if the input data directory is one subject, you can bind it directly to `/dicoms`. If it is the parent directory of multiple subjects, you can bind it to `/dicoms` and specify the specific subject directory (e.g, `-d /dicoms/subject-01`). === "Docker" ``` docker run --rm -it --entrypoint /venv/bin/dcm2bids_helper \ - -v /path/to/input-data:/input \ - -v /path/to/output-dir/new_bids_dataset:/output \ - unfmontreal/dcm2bids:latest -o /output -d /input + -v /path/to/dicoms:/dicoms:ro \ + -v /path/to/bids/new_scaffold:/bids \ + unfmontreal/dcm2bids:${VERSION} -o /bids -d /dicoms ``` === "Apptainer/Singularity" ``` - singularity exec \ - -B /path/to/input-data:/input \ - -B /path/to/output-dir/new_bids_dataset:/output \ - dcm2bids.sif dcm2bids_helper -o /output -d /input + apptainer exec \ + -B /path/to/dicoms:/dicoms:ro \ + -B /path/to/bids/new_scaffold:/bids \ + dcm2bids.sif dcm2bids_helper -o /bids -d /dicoms ``` ## Step 5: Run `dcm2bids` @@ -108,18 +109,20 @@ You can also [deface your data](use-advanced-commands.md#post_op) and [validate ``` docker run --rm -it \ - -B /path/to/input-data:/input \ - -B /path/to/output-dir/new_bids_dataset:/output \ - unfmontreal/dcm2bids:latest --auto_extract_entities --bids_validate \ - -o /output -d /input -c /output/code/config.json -p 001 + -v /path/to/dicoms:/dicoms:ro \ + -v /path/to/config.json:/config.json:ro \ + -v /path/to/bids/new_scaffold:/bids \ + unfmontreal/dcm2bids:${VERSION} --auto_extract_entities --bids_validate \ + -o /bids -d /dicoms -c /config.json -p 001 ``` === "Apptainer/Singularity" ``` - singularity run \ - -B /path/to/input-data:/input \ - -B /path/to/output-dir/new_bids_dataset:/output \ + apptainer run \ + -B /path/to/dicoms:/dicoms:ro \ + -B /path/to/config.json:/config.json:ro \ + -B /path/to/bids/new_scaffold:/bids \ dcm2bids.sif --auto_extract_entities --bids_validate \ - -o /output -d /input -c /output/code/config.json -p 001 + -o /bids -d /dicoms -c /config.json -p 001 ``` From 0a30af6291d65b82c934a58b08dcf89a6a687741 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 26 Jul 2024 08:39:36 -0400 Subject: [PATCH 34/40] Update docs/get-started/install.md Co-authored-by: Steven Meisler --- docs/get-started/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index b3da9988..07f944b9 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -20,7 +20,7 @@ You can install it using [Docker][docker] or [Apptainer/Singularity][apptainer]. === "Apptainer/Singularity" - `singularity pull dcm2bids_latest.sif docker://unfmontreal/dcm2bids:latest` + `apptainer pull dcm2bids_${VERSION}.sif docker://unfmontreal/dcm2bids:${VERSION}` ## Installing binary executables From 17e82051f36904024d28647d5eaeba4f4597f189 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 26 Jul 2024 08:42:20 -0400 Subject: [PATCH 35/40] Apply ${VERSION} everywhere for consistency --- docs/get-started/install.md | 2 +- docs/how-to/container.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 07f944b9..22102614 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -16,7 +16,7 @@ You can install it using [Docker][docker] or [Apptainer/Singularity][apptainer]. === "Docker" - `docker pull unfmontreal/dcm2bids:latest` + `docker pull unfmontreal/dcm2bids:${VERSION}` === "Apptainer/Singularity" diff --git a/docs/how-to/container.md b/docs/how-to/container.md index e5c892ef..fd490d5b 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -22,7 +22,7 @@ To start, you can either pull the dcm2bids image from the Docker Hub repository === "Docker" ``` - docker pull unfmontreal/dcm2bids:latest + docker pull unfmontreal/dcm2bids:${VERSION} ``` === "Apptainer/Singularity" From 74f749be1d92151c9118b69f35ca5f46a5c80c64 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 26 Jul 2024 08:55:16 -0400 Subject: [PATCH 36/40] add missing -e --containall --- docs/how-to/container.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/how-to/container.md b/docs/how-to/container.md index fd490d5b..96f73c0f 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -92,6 +92,7 @@ If you bind the newly scaffolded directory on its own, you can simply use the `- ``` apptainer exec \ + -e --containall \ -B /path/to/dicoms:/dicoms:ro \ -B /path/to/bids/new_scaffold:/bids \ dcm2bids.sif dcm2bids_helper -o /bids -d /dicoms @@ -120,6 +121,7 @@ You can also [deface your data](use-advanced-commands.md#post_op) and [validate ``` apptainer run \ + -e --containall \ -B /path/to/dicoms:/dicoms:ro \ -B /path/to/config.json:/config.json:ro \ -B /path/to/bids/new_scaffold:/bids \ From e4b7123cac573178f65f035f39060a273c527757 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 26 Jul 2024 09:22:51 -0400 Subject: [PATCH 37/40] add export version to containers --- .github/workflows/publish_doc.yaml | 1 + .gitignore | 1 + docs/get-started/install.md | 10 ++++++++-- docs/how-to/container.md | 6 +++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index 036127e4..ba4819cb 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -51,6 +51,7 @@ jobs: dcm2bids -h > docs_helper/help.txt dcm2bids_helper -h > docs_helper/helper.txt dcm2bids_scaffold -h > docs_helper/help_scaffold.txt + echo "export VERSION=$(dcm2bids -v | awk '/dcm2bids/ {print $3}')" > docs_helper/version.txt - name: Set git credentials run: | diff --git a/.gitignore b/.gitignore index ee1d0b5f..104f9265 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,4 @@ tests/data/* docs_helper/help.txt docs_helper/help_scaffold.txt docs_helper/helper.txt +docs_helper/version.txt \ No newline at end of file diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 22102614..cd9d7148 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -16,11 +16,17 @@ You can install it using [Docker][docker] or [Apptainer/Singularity][apptainer]. === "Docker" - `docker pull unfmontreal/dcm2bids:${VERSION}` + ``` + --8<-- "docs_helper/version.txt" + docker pull unfmontreal/dcm2bids:${VERSION} + ``` === "Apptainer/Singularity" - `apptainer pull dcm2bids_${VERSION}.sif docker://unfmontreal/dcm2bids:${VERSION}` + ``` + --8<-- "docs_helper/version.txt" + apptainer pull dcm2bids.sif docker://unfmontreal/dcm2bids:${VERSION} + ``` ## Installing binary executables diff --git a/docs/how-to/container.md b/docs/how-to/container.md index 96f73c0f..9a693577 100644 --- a/docs/how-to/container.md +++ b/docs/how-to/container.md @@ -19,15 +19,19 @@ Before you begin, make sure you have at least one of the following installed: To start, you can either pull the dcm2bids image from the Docker Hub repository or [build it from the Dockerfile in the repository](https://github.com/UNFmontreal/Dcm2Bids/blob/dev/Dockerfile).: + + === "Docker" ``` + --8<-- "docs_helper/version.txt" docker pull unfmontreal/dcm2bids:${VERSION} ``` === "Apptainer/Singularity" ``` + --8<-- "docs_helper/version.txt" apptainer pull dcm2bids_${VERSION}.sif docker://unfmontreal/dcm2bids:${VERSION} ``` @@ -38,7 +42,7 @@ The default command, or the point of entry, for the container is `dcm2bids`. So === "Docker" ``` - docker run --rm -it unfmontreal/dcm2bids:latest --help + docker run --rm -it unfmontreal/dcm2bids:${VERSION} --help ``` === "Apptainer/Singularity" From ce10d473687d0423a846cf97fab9a1baf3774d85 Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Fri, 26 Jul 2024 09:36:04 -0400 Subject: [PATCH 38/40] Update publish_doc.yaml Rename dev doc tag --- .github/workflows/publish_doc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index ba4819cb..cf15ea21 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -82,4 +82,4 @@ jobs: run: | VERSION=$(dcm2bids -v | awk '/dcm2bids/ {print $3}') echo "Version: $VERSION" - mike deploy -p $VERSION dev -u + mike deploy -p dev dev -u From 449bfb1d5879d547b396db2dd7ec5193b2aef20b Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Fri, 26 Jul 2024 09:41:43 -0400 Subject: [PATCH 39/40] Update publish_doc.yaml delete dev before deploying it. --- .github/workflows/publish_doc.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index cf15ea21..d4128bdf 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -81,5 +81,6 @@ jobs: if: ${{ github.ref == 'refs/heads/dev' }} run: | VERSION=$(dcm2bids -v | awk '/dcm2bids/ {print $3}') - echo "Version: $VERSION" + echo "Version: ${VERSION}-dev" + mike delete dev mike deploy -p dev dev -u From 58f3c728a9301bd3ec962ec3afd1939bd1344e3e Mon Sep 17 00:00:00 2001 From: Arnaud Bore Date: Fri, 26 Jul 2024 09:44:26 -0400 Subject: [PATCH 40/40] Update publish_doc.yaml Just deploy dev --- .github/workflows/publish_doc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_doc.yaml b/.github/workflows/publish_doc.yaml index d4128bdf..17c4feea 100644 --- a/.github/workflows/publish_doc.yaml +++ b/.github/workflows/publish_doc.yaml @@ -83,4 +83,4 @@ jobs: VERSION=$(dcm2bids -v | awk '/dcm2bids/ {print $3}') echo "Version: ${VERSION}-dev" mike delete dev - mike deploy -p dev dev -u + mike deploy -p dev