From 2981baac719da97d6ec6c3c444c046389d44baf3 Mon Sep 17 00:00:00 2001 From: Jermiah Joseph <44614774+jjjermiah@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:12:20 -0500 Subject: [PATCH] feat: dicom-finder cli tool, and improve documentation (#142) * docs: add mkdocs-include-markdown plugin for Markdown file inclusion * docs: add tag helpers documentation for DICOM utilities * docs: add documentation for finding DICOM files * Update src/imgtools/cli/dicomfind.py * feat: add regex filtering and improved logging for dicom_finder function * chore: exclude CLI files from coverage reporting --- README.md | 5 +- config/coverage.toml | 1 + config/mypy.ini | 3 +- docs/index.md | 106 +-- docs/reference/dicom-utils/find-dicoms.md | 3 + docs/reference/dicom-utils/tag-helpers.md | 7 + mkdocs.yml | 1 + pixi.lock | 1048 +++------------------ pixi.toml | 1 + src/imgtools/cli/__main__.py | 2 + src/imgtools/cli/dicomfind.py | 152 +++ src/imgtools/dicom/sort/sort_method.py | 3 +- src/imgtools/dicom/utils.py | 109 ++- 13 files changed, 380 insertions(+), 1061 deletions(-) create mode 100644 docs/reference/dicom-utils/find-dicoms.md create mode 100644 docs/reference/dicom-utils/tag-helpers.md create mode 100644 src/imgtools/cli/dicomfind.py diff --git a/README.md b/README.md index 8719d9ca..812d2189 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Med-Imagetools: Transparent and Reproducible Medical Image Processing Pipelines in Python + [![CI/CD Status](https://github.com/bhklab/med-imagetools/actions/workflows/main.yml/badge.svg)](https://github.com/bhklab/med-imagetools/actions/workflows/main.yml) ![GitHub repo size](https://img.shields.io/github/repo-size/bhklab/med-imagetools) @@ -14,7 +15,7 @@ [![PyPI - Format](https://img.shields.io/pypi/format/med-imagetools)](https://pypi.org/project/med-imagetools/) [![Downloads](https://static.pepy.tech/badge/med-imagetools)](https://pepy.tech/project/med-imagetools) -#### Med-ImageTools core features +## Med-ImageTools core features * AutoPipeline CLI * `nnunet` nnU-Net compatibility mode @@ -64,7 +65,7 @@ pip install -e git+https://github.com/bhklab/med-imagetools.git ``` This will install the package in editable mode, so that the installed package will update when the code is changed. - + ## Latest Updates Nov 21st, 2024 ### New CLI entry point `imgtools` diff --git a/config/coverage.toml b/config/coverage.toml index f3c6556c..90e92c52 100644 --- a/config/coverage.toml +++ b/config/coverage.toml @@ -1,6 +1,7 @@ [tool.coverage.run] omit = [ "src/imgtools/logging/**/*.py", + "src/imgtools/cli/**/*.py", ] [tool.coverage.report] \ No newline at end of file diff --git a/config/mypy.ini b/config/mypy.ini index 0393f194..12e2988f 100644 --- a/config/mypy.ini +++ b/config/mypy.ini @@ -1,6 +1,7 @@ [mypy] files = src/imgtools/logging/**/*.py, - src/imgtools/dicom/**/*.py + src/imgtools/dicom/**/*.py, + src/imgtools/cli/**/*.py exclude = tests/ \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index a06b2185..9ef6514b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,107 +1,3 @@ # Med-Imagetools: Transparent and Reproducible Medical Image Processing Pipelines in Python -[![main-ci](https://github.com/bhklab/med-imagetools/actions/workflows/main-ci.yml/badge.svg)](https://github.com/bhklab/med-imagetools/actions/workflows/main-ci.yml) -![GitHub repo size](https://img.shields.io/github/repo-size/bhklab/med-imagetools) -![GitHub contributors](https://img.shields.io/github/contributors/bhklab/med-imagetools) -![GitHub stars](https://img.shields.io/github/stars/bhklab/med-imagetools?style=social) -![GitHub forks](https://img.shields.io/github/forks/bhklab/med-imagetools?style=social) - -## Latest Updates (v0.4.4) - July 27th, 2022 - -New features include: - -* AutoPipeline CLI -* `nnunet` nnU-Net compatibility mode -* Built-in train/test split for both normal/nnU-Net modes -* `random_state` for reproducible seeds -* Region of interest (ROI) yaml dictionary intake for RTSTRUCT processing -* Markdown report output post-processing -* `continue_processing` flag to continue autopipeline -* `dry_run` flag to only crawl the dataset - -Med-Imagetools, a python package offers the perfect tool to transform messy medical dataset folders to deep learning ready format in few lines of code. It not only processes DICOMs consisting of different modalities (like CT, PET, RTDOSE and RTSTRUCTS), it also transforms them into deep learning ready subject based format taking the dependencies of these modalities into consideration. - -## Introduction - -A medical dataset, typically contains multiple different types of scans for a single patient in a single study. As seen in the figure below, the different scans containing DICOM of different modalities are interdependent on each other. For making effective machine learning models, one ought to take different modalities into account. - -
Fig.1 - Different network topology for different studies of different patients
- -Med-Imagetools is a unique tool, which focuses on subject based Machine learning. It crawls the dataset and makes a network by connecting different modalities present in the dataset. Based on the user defined modalities, med-imagetools, queries the graph and process the queried raw DICOMS. The processed DICOMS are saved as nrrds, which med-imagetools converts to torchio subject dataset and eventually torch dataloader for ML pipeline. - -
Fig.2 - Med-Imagetools AutoPipeline diagram
- -## Installing med-imagetools - -```sh -pip install med-imagetools -``` - -### (recommended) Create new conda virtual environment - -``` sh -conda create -n mit -conda activate mit -pip install med-imagetools -``` - -### (optional) Install in development mode - -``` sh -conda create -n mit -conda activate mit -pip install -e git+https://github.com/bhklab/med-imagetools.git -``` - -This will install the package in editable mode, so that the installed package will update when the code is changed. - -## Getting Started - -Med-Imagetools takes two step approch to turn messy medical raw dataset to ML ready dataset. - -1. ***Autopipeline***: Crawls the raw dataset, forms a network and performs graph query, based on the user defined modalities. The relevant DICOMS, get processed and saved as nrrds - - ``` sh - autopipeline\ - [INPUT_DIRECTORY] \ - [OUTPUT_DIRECTORY] \ - --modalities [str: CT,RTSTRUCT,PT] \ - --spacing [Tuple: (int,int,int)]\ - --n_jobs [int]\ - --visualize [flag]\ - --nnunet [flag]\ - --train_size [float]\ - --random_state [int]\ - --roi_yaml_path [str]\ - --continue_processing [flag]\ - --dry_run [flag] - ``` - -2. ***class Dataset***: This class converts processed nrrds to torchio subjects, which can be easily converted to torch dataset - - ```py - from imgtools.io import Dataset - - subjects = Dataset.load_from_nrrd(output_directory, ignore_multi=True) - data_set = tio.SubjectsDataset(subjects) - data_loader = torch.utils.data.DataLoader(data_set, batch_size=4, shuffle=True, num_workers=4) - ``` - - -### Contributors - -Thanks to the following people who have contributed to this project: - -* [@mkazmier](https://github.com/mkazmier) -* [@skim2257](https://github.com/skim2257) -* [@fishingguy456](https://github.com/fishingguy456) -* [@Vishwesh4](https://github.com/Vishwesh4) -* [@mnakano](https://github.com/mnakano) - -## Contact - -If you have any questions/concerns, you can reach the main development team at sejin.kim@uhnresearch.ca or open an issue on our [GitHub repository](https://github.com/bhklab/med-imagetools) - -## License - -This project uses the following license: [Apache License 2.0](http://www.apache.org/licenses/) +{% include-markdown "../README.md" start="" end="" %} diff --git a/docs/reference/dicom-utils/find-dicoms.md b/docs/reference/dicom-utils/find-dicoms.md new file mode 100644 index 00000000..1dcd7523 --- /dev/null +++ b/docs/reference/dicom-utils/find-dicoms.md @@ -0,0 +1,3 @@ +# Find DICOMs + +::: imgtools.dicom.utils.find_dicoms diff --git a/docs/reference/dicom-utils/tag-helpers.md b/docs/reference/dicom-utils/tag-helpers.md new file mode 100644 index 00000000..2ba1c74c --- /dev/null +++ b/docs/reference/dicom-utils/tag-helpers.md @@ -0,0 +1,7 @@ +# Tag Helpers + +::: imgtools.dicom.utils.lookup_tag + +::: imgtools.dicom.utils.tag_exists + +::: imgtools.dicom.utils.similar_tags diff --git a/mkdocs.yml b/mkdocs.yml index afe9bce3..e3819e06 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,6 +51,7 @@ plugins: - awesome-pages # simplifies configuring page titles and their order - search # necessary for search functionality to work - git-authors # adds authors to pages using git history + - include-markdown # allows for including Markdown files into another Markdown file - mkdocstrings: handlers: python: diff --git a/pixi.lock b/pixi.lock index 3b590ad4..b4744637 100644 --- a/pixi.lock +++ b/pixi.lock @@ -144,6 +144,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/bleach-6.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/bracex-2.2.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda @@ -159,7 +160,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.7-py312h178313f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-43.0.3-py312hda17c39_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.8-py312h2ec8cdc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.9-py312h2ec8cdc_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.1.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/defusedxml-0.7.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_0.conda @@ -249,6 +250,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-get-deps-0.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-authors-plugin-0.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-revision-date-localized-plugin-1.2.9-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-include-markdown-plugin-7.1.1-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.5.45-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocstrings-0.27.0-pyhd8ed1ab_0.conda @@ -284,8 +286,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-24.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.9.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.23.4-py312h12e396e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.10.0-pyh10f6f8f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.27.0-py312h12e396e_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pymdown-extensions-10.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda @@ -317,7 +319,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.7.4-py312h2156523_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/send2trash-1.8.3-pyh0d859eb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.5.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.0-pyhd8ed1ab_0.tar.bz2 @@ -345,22 +347,22 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.5.3-h0f3a69f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.5.4-h0f3a69f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/verspec-0.1.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.27.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcmatch-10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.13-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webcolors-24.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.17.2-py312h66e93f0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.18.0-py312h66e93f0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h3b0a872_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312hef9b889_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda - - pypi: https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ba/99/6794142b90b853a9155316c8f470d2e4821fe6f086b03e372aca848227dd/contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl @@ -389,7 +391,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_0.conda @@ -407,6 +408,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/bleach-6.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/bracex-2.2.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312hde4cb15_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda @@ -420,7 +422,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/comm-0.2.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.6.7-py312h998013c_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/debugpy-1.8.8-py312hd8f9ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/debugpy-1.8.9-py312hd8f9ff3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.1.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/defusedxml-0.7.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_0.conda @@ -497,6 +499,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-get-deps-0.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-authors-plugin-0.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-revision-date-localized-plugin-1.2.9-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-include-markdown-plugin-7.1.1-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.5.45-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocstrings-0.27.0-pyhd8ed1ab_0.conda @@ -531,8 +534,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyaml-24.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.9.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.23.4-py312he431725_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.10.0-pyh10f6f8f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.27.0-py312hcd83bfe_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pymdown-extensions-10.12-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyobjc-core-10.3.1-py312hd24fc31_1.conda @@ -565,7 +568,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rpds-py-0.21.0-py312hcd83bfe_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.7.4-py312h5d18b81_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/send2trash-1.8.3-pyh31c8845_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.5.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/smmap-5.0.0-pyhd8ed1ab_0.tar.bz2 @@ -593,22 +596,22 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.5.3-h668ec48_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.5.4-h668ec48_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/verspec-0.1.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.27.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcmatch-10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.13-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webcolors-24.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.17.2-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.18.0-py312hea69d52_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-hc1bb282_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py312h15fbf35_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.6-hb46c0d2_0.conda - - pypi: https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6b/6a/7833cfae2c1e63d1d8875a50fd23371394f540ce809d7383550681a1fa64/contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl @@ -637,7 +640,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl - pypi: . docs: channels: @@ -649,6 +651,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/bracex-2.2.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda @@ -692,6 +695,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-get-deps-0.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-authors-plugin-0.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-revision-date-localized-plugin-1.2.9-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-include-markdown-plugin-7.1.1-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.5.45-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocstrings-0.27.0-pyhd8ed1ab_0.conda @@ -726,13 +730,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/verspec-0.1.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/watchdog-6.0.0-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcmatch-10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312hef9b889_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda - pypi: https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ba/99/6794142b90b853a9155316c8f470d2e4821fe6f086b03e372aca848227dd/contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl @@ -763,10 +767,10 @@ environments: - pypi: https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/bracex-2.2.1-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312hde4cb15_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda @@ -802,6 +806,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-get-deps-0.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-authors-plugin-0.9.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-git-revision-date-localized-plugin-1.2.9-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-include-markdown-plugin-7.1.1-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-9.5.45-pyhff2d567_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocs-material-extensions-1.3.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mkdocstrings-0.27.0-pyhd8ed1ab_0.conda @@ -836,13 +841,13 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/verspec-0.1.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/watchdog-6.0.0-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcmatch-10.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py312h15fbf35_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.6-hb46c0d2_0.conda - pypi: https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6b/6a/7833cfae2c1e63d1d8875a50fd23371394f540ce809d7383550681a1fa64/contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl @@ -873,7 +878,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl - pypi: . py310: channels: @@ -1501,17 +1505,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl - pypi: . packages: -- kind: conda - name: _libgcc_mutex - version: '0.1' - build: conda_forge - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 - md5: d7c89558ba9fa0495403155b64376d81 - license: None - size: 2562 - timestamp: 1578324546067 - kind: conda name: _libgcc_mutex version: '0.1' @@ -1524,24 +1517,6 @@ packages: purls: [] size: 2562 timestamp: 1578324546067 -- kind: conda - name: _openmp_mutex - version: '4.5' - build: 2_gnu - build_number: 16 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 - md5: 73aaf86a425cc6e73fcf236a5a46396d - depends: - - _libgcc_mutex 0.1 conda_forge - - libgomp >=7.5.0 - constrains: - - openmp_impl 9999 - license: BSD-3-Clause - license_family: BSD - size: 23621 - timestamp: 1650670423406 - kind: conda name: _openmp_mutex version: '4.5' @@ -1909,12 +1884,23 @@ packages: - pkg:pypi/bleach?source=hash-mapping size: 132652 timestamp: 1730286301829 -- kind: pypi +- kind: conda name: bracex - version: 2.5.post1 - url: https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl - sha256: 13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6 - requires_python: '>=3.8' + version: 2.2.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/bracex-2.2.1-pyhd8ed1ab_0.tar.bz2 + sha256: e3f867b5be7837366e989df8f6e64f94ec180676fea3494285ee873f24921156 + md5: 586272349d7bef5b1ef527b56dca73cb + depends: + - python >=3.5 + license: MIT + license_family: MIT + purls: + - pkg:pypi/bracex?source=hash-mapping + size: 14045 + timestamp: 1636190617443 - kind: conda name: brotli-python version: 1.1.0 @@ -1961,22 +1947,6 @@ packages: - pkg:pypi/brotli?source=hash-mapping size: 339360 timestamp: 1725268143995 -- kind: conda - name: bzip2 - version: 1.0.8 - build: h4bc722e_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d - md5: 62ee74e96c5ebb0af99386de58cf9553 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - license: bzip2-1.0.6 - license_family: BSD - size: 252783 - timestamp: 1720974456583 - kind: conda name: bzip2 version: 1.0.8 @@ -1994,21 +1964,6 @@ packages: purls: [] size: 252783 timestamp: 1720974456583 -- kind: conda - name: bzip2 - version: 1.0.8 - build: h99b78c6_7 - build_number: 7 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - sha256: adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91 - md5: fc6948412dbbbe9a4c9ddbbcfe0a79ab - depends: - - __osx >=11.0 - license: bzip2-1.0.6 - license_family: BSD - size: 122909 - timestamp: 1720974522888 - kind: conda name: bzip2 version: 1.0.8 @@ -2025,17 +1980,6 @@ packages: purls: [] size: 122909 timestamp: 1720974522888 -- kind: conda - name: ca-certificates - version: 2024.8.30 - build: hbcca054_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda - sha256: afee721baa6d988e27fef1832f68d6f32ac8cc99cdf6015732224c2841a09cea - md5: c27d1c142233b5bc9ca570c6e2e0c244 - license: ISC - size: 159003 - timestamp: 1725018903918 - kind: conda name: ca-certificates version: 2024.8.30 @@ -2048,17 +1992,6 @@ packages: purls: [] size: 159003 timestamp: 1725018903918 -- kind: conda - name: ca-certificates - version: 2024.8.30 - build: hf0a4a13_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda - sha256: 2db1733f4b644575dbbdd7994a8f338e6ef937f5ebdb74acd557e9dda0211709 - md5: 40dec13fd8348dbe303e57be74bd3d35 - license: ISC - size: 158482 - timestamp: 1725019034582 - kind: conda name: ca-certificates version: 2024.8.30 @@ -2226,21 +2159,6 @@ packages: - pkg:pypi/click-option-group?source=hash-mapping size: 16770 timestamp: 1686394351507 -- kind: conda - name: colorama - version: 0.4.6 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 - sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 - md5: 3faab06a954c2a04039983f2c4a50d99 - depends: - - python >=3.7 - license: BSD-3-Clause - license_family: BSD - size: 25170 - timestamp: 1666700778190 - kind: conda name: colorama version: 0.4.6 @@ -2506,24 +2424,6 @@ packages: - pkg:pypi/coverage?source=hash-mapping size: 372952 timestamp: 1731698891980 -- kind: conda - name: coverage - version: 7.6.7 - build: py312h178313f_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.7-py312h178313f_0.conda - sha256: 2d8f9a588f89fc3df7b98ab5ffcf5968c82c34813db7373f40b5a7de71eabf2a - md5: f64f3206bf9e86338b881957fd498870 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - python >=3.12,<3.13.0a0 - - python_abi 3.12.* *_cp312 - - tomli - license: Apache-2.0 - license_family: APACHE - size: 364489 - timestamp: 1731698658681 - kind: conda name: coverage version: 7.6.7 @@ -2544,24 +2444,6 @@ packages: - pkg:pypi/coverage?source=hash-mapping size: 364489 timestamp: 1731698658681 -- kind: conda - name: coverage - version: 7.6.7 - build: py312h998013c_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.6.7-py312h998013c_0.conda - sha256: 2be117611f5c776372b7d12ea8bce2d0452022e612c84e042017eb6c777b9da6 - md5: 0962c6746e00b34ce0584d3ae129d266 - depends: - - __osx >=11.0 - - python >=3.12,<3.13.0a0 - - python >=3.12,<3.13.0a0 *_cpython - - python_abi 3.12.* *_cp312 - - tomli - license: Apache-2.0 - license_family: APACHE - size: 363385 - timestamp: 1731698781484 - kind: conda name: coverage version: 7.6.7 @@ -2639,12 +2521,12 @@ packages: timestamp: 1640112124844 - kind: conda name: debugpy - version: 1.8.8 + version: 1.8.9 build: py312h2ec8cdc_0 subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.8-py312h2ec8cdc_0.conda - sha256: 9ffdc284d4c67ba9ab88d400fc55890aafba6a559268f2dc3ca5a1c58d1a7ab9 - md5: eb182854d81037c9cfd95b06aba22c06 + url: https://conda.anaconda.org/conda-forge/linux-64/debugpy-1.8.9-py312h2ec8cdc_0.conda + sha256: cf79cac70773567382910fcaf7b10bb0f5242d159f8dd93296d8451cd542af9a + md5: c522fd70ca7a0c2fe1a861dd13987a57 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 @@ -2655,16 +2537,16 @@ packages: license_family: MIT purls: - pkg:pypi/debugpy?source=hash-mapping - size: 2661121 - timestamp: 1731045067784 + size: 2605093 + timestamp: 1732236790708 - kind: conda name: debugpy - version: 1.8.8 + version: 1.8.9 build: py312hd8f9ff3_0 subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/debugpy-1.8.8-py312hd8f9ff3_0.conda - sha256: 2a20826d25063bb500a8bda98a02fee024a64da0fa52183a29af026e2d4e81a7 - md5: a47db7a8ec137fa9cc5ba9f20a45394f + url: https://conda.anaconda.org/conda-forge/osx-arm64/debugpy-1.8.9-py312hd8f9ff3_0.conda + sha256: d588943ac0392300f31115d9852a2ff4213ec22856c382ef56f5650576523ec6 + md5: 51085e5bb7f21019186cc88fd9a03164 depends: - __osx >=11.0 - libcxx >=18 @@ -2675,8 +2557,8 @@ packages: license_family: MIT purls: - pkg:pypi/debugpy?source=hash-mapping - size: 2535797 - timestamp: 1731045204699 + size: 2512030 + timestamp: 1732236996277 - kind: conda name: decorator version: 5.1.1 @@ -2788,20 +2670,6 @@ packages: - pkg:pypi/entrypoints?source=hash-mapping size: 9199 timestamp: 1643888357950 -- kind: conda - name: exceptiongroup - version: 1.2.2 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda - sha256: e0edd30c4b7144406bb4da975e6bb97d6bc9c0e999aa4efe66ae108cada5d5b5 - md5: d02ae936e42063ca46af6cdad2dbd1e0 - depends: - - python >=3.7 - license: MIT and PSF-2.0 - size: 20418 - timestamp: 1720869435725 - kind: conda name: exceptiongroup version: 1.2.2 @@ -2818,21 +2686,6 @@ packages: - pkg:pypi/exceptiongroup?source=hash-mapping size: 20418 timestamp: 1720869435725 -- kind: conda - name: execnet - version: 2.1.1 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda - sha256: 564bc012d73ca29964e7acca18d60b2fa8d20eea6d258d98cfc24df5167beaf0 - md5: 15dda3cdbf330abfe9f555d22f66db46 - depends: - - python >=3.8 - license: MIT - license_family: MIT - size: 38883 - timestamp: 1712591929944 - kind: conda name: execnet version: 2.1.1 @@ -3653,21 +3506,6 @@ packages: - pkg:pypi/importlib-resources?source=hash-mapping size: 32725 timestamp: 1725921462405 -- kind: conda - name: iniconfig - version: 2.0.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda - sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 - md5: f800d2da156d08e289b14e87e43c1ae5 - depends: - - python >=3.7 - license: MIT - license_family: MIT - size: 11101 - timestamp: 1673103208955 - kind: conda name: iniconfig version: 2.0.0 @@ -4396,23 +4234,6 @@ packages: - pytest>=7.4 ; extra == 'test' - pytest-cov>=4.1 ; extra == 'test' requires_python: '>=3.7' -- kind: conda - name: ld_impl_linux-64 - version: '2.43' - build: h712a8e2_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda - sha256: 7c91cea91b13f4314d125d1bedb9d03a29ebbd5080ccdea70260363424646dbe - md5: 048b02e3962f066da18efe3a21b77672 - depends: - - __glibc >=2.17,<3.0.a0 - constrains: - - binutils_impl_linux-64 2.43 - license: GPL-3.0-only - license_family: GPL - size: 669211 - timestamp: 1729655358674 - kind: conda name: ld_impl_linux-64 version: '2.43' @@ -4479,22 +4300,6 @@ packages: purls: [] size: 123878 timestamp: 1597616541093 -- kind: conda - name: libexpat - version: 2.6.4 - build: h286801f_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.4-h286801f_0.conda - sha256: e42ab5ace927ee7c84e3f0f7d813671e1cf3529f5f06ee5899606630498c2745 - md5: 38d2656dd914feb0cab8c629370768bf - depends: - - __osx >=11.0 - constrains: - - expat 2.6.4.* - license: MIT - license_family: MIT - size: 64693 - timestamp: 1730967175868 - kind: conda name: libexpat version: 2.6.4 @@ -4512,23 +4317,6 @@ packages: purls: [] size: 64693 timestamp: 1730967175868 -- kind: conda - name: libexpat - version: 2.6.4 - build: h5888daf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda - sha256: 56541b98447b58e52d824bd59d6382d609e11de1f8adf20b23143e353d2b8d26 - md5: db833e03127376d461e1e13e76f09b6c - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - constrains: - - expat 2.6.4.* - license: MIT - license_family: MIT - size: 73304 - timestamp: 1730967041968 - kind: conda name: libexpat version: 2.6.4 @@ -4547,19 +4335,6 @@ packages: purls: [] size: 73304 timestamp: 1730967041968 -- kind: conda - name: libffi - version: 3.4.2 - build: h3422bc3_5 - build_number: 5 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 - sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca - md5: 086914b672be056eb70fd4285b6783b6 - license: MIT - license_family: MIT - size: 39020 - timestamp: 1636488587153 - kind: conda name: libffi version: 3.4.2 @@ -4587,43 +4362,9 @@ packages: - libgcc-ng >=9.4.0 license: MIT license_family: MIT - size: 58292 - timestamp: 1636488182923 -- kind: conda - name: libffi - version: 3.4.2 - build: h7f98852_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 - sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e - md5: d645c6d2ac96843a2bfaccd2d62b3ac3 - depends: - - libgcc-ng >=9.4.0 - license: MIT - license_family: MIT - purls: [] + purls: [] size: 58292 timestamp: 1636488182923 -- kind: conda - name: libgcc - version: 14.2.0 - build: h77fa898_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda - sha256: 53eb8a79365e58849e7b1a068d31f4f9e718dc938d6f2c03e960345739a03569 - md5: 3cb76c3f10d3bc7f1105b2fc9db984df - depends: - - _libgcc_mutex 0.1 conda_forge - - _openmp_mutex >=4.5 - constrains: - - libgomp 14.2.0 h77fa898_1 - - libgcc-ng ==14.2.0=*_1 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 848745 - timestamp: 1729027721139 - kind: conda name: libgcc version: 14.2.0 @@ -4644,21 +4385,6 @@ packages: purls: [] size: 848745 timestamp: 1729027721139 -- kind: conda - name: libgcc-ng - version: 14.2.0 - build: h69a702a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda - sha256: 3a76969c80e9af8b6e7a55090088bc41da4cffcde9e2c71b17f44d37b7cb87f7 - md5: e39480b9ca41323497b05492a63bc35b - depends: - - libgcc 14.2.0 h77fa898_1 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 54142 - timestamp: 1729027726517 - kind: conda name: libgcc-ng version: 14.2.0 @@ -4696,21 +4422,6 @@ packages: purls: [] size: 3931898 timestamp: 1729191404130 -- kind: conda - name: libgomp - version: 14.2.0 - build: h77fa898_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda - sha256: 1911c29975ec99b6b906904040c855772ccb265a1c79d5d75c8ceec4ed89cd63 - md5: cc3573974587f12dda90d96e3e55a702 - depends: - - _libgcc_mutex 0.1 conda_forge - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 460992 - timestamp: 1729027639220 - kind: conda name: libgomp version: 14.2.0 @@ -4742,20 +4453,6 @@ packages: purls: [] size: 705775 timestamp: 1702682170569 -- kind: conda - name: libnsl - version: 2.0.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 - md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 - depends: - - libgcc-ng >=12 - license: LGPL-2.1-only - license_family: GPL - size: 33408 - timestamp: 1697359010159 - kind: conda name: libnsl version: 2.0.1 @@ -4799,22 +4496,6 @@ packages: purls: [] size: 164972 timestamp: 1716828607917 -- kind: conda - name: libsqlite - version: 3.47.0 - build: hadc24fc_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda - sha256: 8a9aadf996a2399f65b679c6e7f29139d5059f699c63e6d7b50e20db10c00508 - md5: b6f02b52a174e612e89548f4663ce56a - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libzlib >=1.3.1,<2.0a0 - license: Unlicense - size: 875349 - timestamp: 1730208050020 - kind: conda name: libsqlite version: 3.47.0 @@ -4832,21 +4513,6 @@ packages: purls: [] size: 875349 timestamp: 1730208050020 -- kind: conda - name: libsqlite - version: 3.47.0 - build: hbaaea75_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.47.0-hbaaea75_1.conda - sha256: 5a96caa566c11e5a5ebdcdb86a0759a7fb27d3c5f42e6a0fd0d6023c1e935d9e - md5: 07a14fbe439eef078cc479deca321161 - depends: - - __osx >=11.0 - - libzlib >=1.3.1,<2.0a0 - license: Unlicense - size: 837683 - timestamp: 1730208293578 - kind: conda name: libsqlite version: 3.47.0 @@ -4895,20 +4561,6 @@ packages: purls: [] size: 54105 timestamp: 1729027780628 -- kind: conda - name: libuuid - version: 2.38.1 - build: h0b41bf4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda - sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 - md5: 40b61aab5c7ba9ff276c41cfffe6b80b - depends: - - libgcc-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 33601 - timestamp: 1680112270483 - kind: conda name: libuuid version: 2.38.1 @@ -4924,20 +4576,6 @@ packages: purls: [] size: 33601 timestamp: 1680112270483 -- kind: conda - name: libxcrypt - version: 4.4.36 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c - md5: 5aa797f8787fe7a17d1b0821485b5adc - depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - size: 100393 - timestamp: 1702724383534 - kind: conda name: libxcrypt version: 4.4.36 @@ -4953,23 +4591,6 @@ packages: purls: [] size: 100393 timestamp: 1702724383534 -- kind: conda - name: libzlib - version: 1.3.1 - build: h8359307_2 - build_number: 2 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b - md5: 369964e85dc26bfe78f41399b366c435 - depends: - - __osx >=11.0 - constrains: - - zlib 1.3.1 *_2 - license: Zlib - license_family: Other - size: 46438 - timestamp: 1727963202283 - kind: conda name: libzlib version: 1.3.1 @@ -4988,24 +4609,6 @@ packages: purls: [] size: 46438 timestamp: 1727963202283 -- kind: conda - name: libzlib - version: 1.3.1 - build: hb9d3cd8_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 - md5: edb0dca6bc32e4f4789199455a1dbeb8 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - constrains: - - zlib 1.3.1 *_2 - license: Zlib - license_family: Other - size: 60963 - timestamp: 1727963148474 - kind: conda name: libzlib version: 1.3.1 @@ -5310,9 +4913,9 @@ packages: timestamp: 1704317789138 - kind: pypi name: med-imagetools - version: 1.7.0 + version: 1.8.2 path: . - sha256: 0472aa2cf13c1db331a8173f210a6ea92ec8d1c269afb6d809ae36a0d7e5b8e3 + sha256: f31f0da0919632b0d41c865825623222b001e3b20dff3ed1d32a3dbdcd5b6f03 requires_dist: - h5py>=3.11.0,<4 - joblib>=1.4.2,<2 @@ -5517,6 +5120,24 @@ packages: - pkg:pypi/mkdocs-git-revision-date-localized-plugin?source=hash-mapping size: 25456 timestamp: 1726153706839 +- kind: conda + name: mkdocs-include-markdown-plugin + version: 7.1.1 + build: pyhff2d567_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/mkdocs-include-markdown-plugin-7.1.1-pyhff2d567_0.conda + sha256: be4d9473ce819eeaadd783cb5cdd48ef63b18dc9f224cff5b6bf254a2e7bbb76 + md5: 7a21b22f88a26f2076c3953ba3b9753c + depends: + - mkdocs >=1.4 + - python >=3.9 + - wcmatch + license: Apache-2.0 + purls: + - pkg:pypi/mkdocs-include-markdown-plugin?source=hash-mapping + size: 27187 + timestamp: 1732180076375 - kind: conda name: mkdocs-material version: 9.5.45 @@ -5816,20 +5437,6 @@ packages: - pkg:pypi/nbformat?source=hash-mapping size: 101232 timestamp: 1712239122969 -- kind: conda - name: ncurses - version: '6.5' - build: h7bae524_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda - sha256: 27d0b9ff78ad46e1f3a6c96c479ab44beda5f96def88e2fe626e0a49429d8afc - md5: cb2b0ea909b97b3d70cd3921d1445e1a - depends: - - __osx >=11.0 - license: X11 AND BSD-3-Clause - size: 802321 - timestamp: 1724658775723 - kind: conda name: ncurses version: '6.5' @@ -5845,21 +5452,6 @@ packages: purls: [] size: 802321 timestamp: 1724658775723 -- kind: conda - name: ncurses - version: '6.5' - build: he02047a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda - sha256: 6a1d5d8634c1a07913f1c525db6455918cbc589d745fac46d9d6e30340c8731a - md5: 70caf8bb6cf39a0b6b7efc885f51c0fe - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - license: X11 AND BSD-3-Clause - size: 889086 - timestamp: 1724658547447 - kind: conda name: ncurses version: '6.5' @@ -5983,21 +5575,6 @@ packages: url: https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl sha256: 03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b requires_python: '>=3.9' -- kind: conda - name: openssl - version: 3.4.0 - build: h39f12f2_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.0-h39f12f2_0.conda - sha256: bd1d58ced46e75efa3b842c61642fd12272c69e9fe4d7261078bc082153a1d53 - md5: df307bbc703324722df0293c9ca2e418 - depends: - - __osx >=11.0 - - ca-certificates - license: Apache-2.0 - license_family: Apache - size: 2935176 - timestamp: 1731377561525 - kind: conda name: openssl version: 3.4.0 @@ -6014,22 +5591,6 @@ packages: purls: [] size: 2935176 timestamp: 1731377561525 -- kind: conda - name: openssl - version: 3.4.0 - build: hb9d3cd8_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-hb9d3cd8_0.conda - sha256: 814b9dff1847b132c676ee6cc1a8cb2d427320779b93e1b6d76552275c128705 - md5: 23cc74f77eb99315c0360ec3533147a9 - depends: - - __glibc >=2.17,<3.0.a0 - - ca-certificates - - libgcc >=13 - license: Apache-2.0 - license_family: Apache - size: 2947466 - timestamp: 1731377666602 - kind: conda name: openssl version: 3.4.0 @@ -6071,22 +5632,6 @@ packages: url: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl sha256: 09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 requires_python: '>=3.8' -- kind: conda - name: packaging - version: '24.2' - build: pyhff2d567_1 - build_number: 1 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhff2d567_1.conda - sha256: 74843f871e5cd8a1baf5ed8c406c571139c287141efe532f8ffbdafa3664d244 - md5: 8508b703977f4c4ada34d657d051972c - depends: - - python >=3.8 - license: Apache-2.0 - license_family: APACHE - size: 60380 - timestamp: 1731802602808 - kind: conda name: packaging version: '24.2' @@ -6975,21 +6520,6 @@ packages: - pkg:pypi/platformdirs?source=hash-mapping size: 20625 timestamp: 1726613611845 -- kind: conda - name: pluggy - version: 1.5.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda - sha256: 33eaa3359948a260ebccf9cdc2fd862cea5a6029783289e13602d8e634cd9a26 - md5: d3483c8fc2dc2cc3f5cf43e26d60cabf - depends: - - python >=3.8 - license: MIT - license_family: MIT - size: 23815 - timestamp: 1713667175451 - kind: conda name: pluggy version: 1.5.0 @@ -7191,32 +6721,33 @@ packages: timestamp: 1711811634025 - kind: conda name: pydantic - version: 2.9.2 - build: pyhd8ed1ab_0 + version: 2.10.0 + build: pyh10f6f8f_0 subdir: noarch noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.9.2-pyhd8ed1ab_0.conda - sha256: 1b7b0dc9f6af4da156bf22b0263be70829364a08145c696d3670facff2f6441a - md5: 1eb533bb8eb2199e3fef3e4aa147319f + url: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.10.0-pyh10f6f8f_0.conda + sha256: fbb18b5d24acad15c452d1d4467999d1a6cbc7b3a89771c0b2424031ddc303b4 + md5: c8d0d99422d56d42185f43e1d4808cb5 depends: - annotated-types >=0.6.0 - - pydantic-core 2.23.4 - - python >=3.7 + - pydantic-core 2.27.0 + - python >=3.9 - typing-extensions >=4.6.1 + - typing_extensions >=4.12.2 license: MIT license_family: MIT purls: - pkg:pypi/pydantic?source=hash-mapping - size: 300649 - timestamp: 1726601202431 + size: 315366 + timestamp: 1732174789708 - kind: conda name: pydantic-core - version: 2.23.4 + version: 2.27.0 build: py312h12e396e_0 subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.23.4-py312h12e396e_0.conda - sha256: 365fde689865087b2a9da636f36678bd59617b324ce7a538b4806e90602b20f1 - md5: 0845ab52d4ea209049129a6a91bc74ba + url: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.27.0-py312h12e396e_0.conda + sha256: 711ce3ed4bfc1d5bdf452f78c14ff36befb3fef629a288c308861042fb8faf92 + md5: 9729cebbd1ad13a592359001bf4408d9 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 @@ -7226,19 +6757,18 @@ packages: constrains: - __glibc >=2.17 license: MIT - license_family: MIT purls: - pkg:pypi/pydantic-core?source=hash-mapping - size: 1611784 - timestamp: 1726525286507 + size: 1631170 + timestamp: 1732137352411 - kind: conda name: pydantic-core - version: 2.23.4 - build: py312he431725_0 + version: 2.27.0 + build: py312hcd83bfe_0 subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.23.4-py312he431725_0.conda - sha256: d6edd3d0f9e701c8299519d412ad3dc900c7d893a134f2582203cf43585decca - md5: 3148052477686acc581b20a34b478eeb + url: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.27.0-py312hcd83bfe_0.conda + sha256: b636b735b955d7ba68544f6e970f6423466a6046ae4626a05117bf7e199b82cb + md5: 0c3f3cfb26ecaf470a41aae1af404265 depends: - __osx >=11.0 - python >=3.12,<3.13.0a0 @@ -7248,11 +6778,10 @@ packages: constrains: - __osx >=11.0 license: MIT - license_family: MIT purls: - pkg:pypi/pydantic-core?source=hash-mapping - size: 1431747 - timestamp: 1726525575527 + size: 1445849 + timestamp: 1732137735725 - kind: pypi name: pydicom version: 2.4.4 @@ -7421,29 +6950,6 @@ packages: - pkg:pypi/pysocks?source=hash-mapping size: 18981 timestamp: 1661604969727 -- kind: conda - name: pytest - version: 8.3.3 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda - sha256: e99376d0068455712109d233f5790458ff861aeceb458bfda74e353338e4d815 - md5: c03d61f31f38fdb9facf70c29958bf7a - depends: - - colorama - - exceptiongroup >=1.0.0rc8 - - iniconfig - - packaging - - pluggy <2,>=1.5 - - python >=3.8 - - tomli >=1 - constrains: - - pytest-faulthandler >=2 - license: MIT - license_family: MIT - size: 258293 - timestamp: 1725977334143 - kind: conda name: pytest version: 8.3.3 @@ -7481,48 +6987,14 @@ packages: depends: - coverage >=7.5 - pytest >=4.6 - - python >=3.9 - - toml - license: MIT - license_family: MIT - size: 26218 - timestamp: 1730284385470 -- kind: conda - name: pytest-cov - version: 6.0.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda - sha256: 915323edaee9f6f3ebd8c2e5450b4865700edf2c85eb2bba61980e66c6f03c5d - md5: cb8a11b6d209e3d85e5094bdbd9ebd9c - depends: - - coverage >=7.5 - - pytest >=4.6 - - python >=3.9 - - toml - license: MIT - license_family: MIT - purls: - - pkg:pypi/pytest-cov?source=hash-mapping - size: 26218 - timestamp: 1730284385470 -- kind: conda - name: pytest-mock - version: 3.14.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pytest-mock-3.14.0-pyhd8ed1ab_0.conda - sha256: f7cd8910ce3690a9189483f4b01dde1970b2b86ea853a03b1225f344f988045d - md5: 4b9b5e086812283c052a9105ab1e254e - depends: - - pytest >=5.0 - - python >=3.8 + - python >=3.9 + - toml license: MIT license_family: MIT - size: 21860 - timestamp: 1711072510934 + purls: + - pkg:pypi/pytest-cov?source=hash-mapping + size: 26218 + timestamp: 1730284385470 - kind: conda name: pytest-mock version: 3.14.0 @@ -7541,25 +7013,6 @@ packages: - pkg:pypi/pytest-mock?source=hash-mapping size: 21860 timestamp: 1711072510934 -- kind: conda - name: pytest-xdist - version: 3.6.1 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda - sha256: c9f27ed55352bee2c9f7cc2fdaf12b322ee280b1989d7e763b4540d4fe7ec995 - md5: b39568655c127a9c4a44d178ac99b6d0 - depends: - - execnet >=2.1 - - pytest >=7.0.0 - - python >=3.8 - constrains: - - psutil >=3.0 - license: MIT - license_family: MIT - size: 38320 - timestamp: 1718138508765 - kind: conda name: pytest-xdist version: 3.6.1 @@ -7701,32 +7154,6 @@ packages: purls: [] size: 30543977 timestamp: 1729043512711 -- kind: conda - name: python - version: 3.12.7 - build: h739c21a_0_cpython - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.7-h739c21a_0_cpython.conda - sha256: 45d7ca2074aa92594bd2f91a9003b338cc1df8a46b9492b7fc8167110783c3ef - md5: e0d82e57ebb456077565e6d82cd4a323 - depends: - - __osx >=11.0 - - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.3,<3.0a0 - - libffi >=3.4,<4.0a0 - - libsqlite >=3.46.1,<4.0a0 - - libzlib >=1.3.1,<2.0a0 - - ncurses >=6.5,<7.0a0 - - openssl >=3.3.2,<4.0a0 - - readline >=8.2,<9.0a0 - - tk >=8.6.13,<8.7.0a0 - - tzdata - - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 - license: Python-2.0 - size: 12975439 - timestamp: 1728057819519 - kind: conda name: python version: 3.12.7 @@ -7754,37 +7181,6 @@ packages: purls: [] size: 12975439 timestamp: 1728057819519 -- kind: conda - name: python - version: 3.12.7 - build: hc5c86c4_0_cpython - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.7-hc5c86c4_0_cpython.conda - sha256: 674be31ff152d9f0e0fe16959a45e3803a730fc4f54d87df6a9ac4e6a698c41d - md5: 0515111a9cdf69f83278f7c197db9807 - depends: - - __glibc >=2.17,<3.0.a0 - - bzip2 >=1.0.8,<2.0a0 - - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.6.3,<3.0a0 - - libffi >=3.4,<4.0a0 - - libgcc >=13 - - libnsl >=2.0.1,<2.1.0a0 - - libsqlite >=3.46.1,<4.0a0 - - libuuid >=2.38.1,<3.0a0 - - libxcrypt >=4.4.36 - - libzlib >=1.3.1,<2.0a0 - - ncurses >=6.5,<7.0a0 - - openssl >=3.3.2,<4.0a0 - - readline >=8.2,<9.0a0 - - tk >=8.6.13,<8.7.0a0 - - tzdata - - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 - license: Python-2.0 - size: 31574780 - timestamp: 1728059777603 - kind: conda name: python version: 3.12.7 @@ -7991,21 +7387,6 @@ packages: purls: [] size: 6308 timestamp: 1723823096865 -- kind: conda - name: python_abi - version: '3.12' - build: 5_cp312 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda - sha256: d10e93d759931ffb6372b45d65ff34d95c6000c61a07e298d162a3bc2accebb0 - md5: 0424ae29b104430108f5218a66db7260 - constrains: - - python 3.12.* *_cpython - license: BSD-3-Clause - license_family: BSD - size: 6238 - timestamp: 1723823388266 - kind: conda name: python_abi version: '3.12' @@ -8022,21 +7403,6 @@ packages: purls: [] size: 6238 timestamp: 1723823388266 -- kind: conda - name: python_abi - version: '3.12' - build: 5_cp312 - build_number: 5 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-5_cp312.conda - sha256: 49d624e4b809c799d2bf257b22c23cf3fc4460f5570d9a58e7ad86350aeaa1f4 - md5: b76f9b1c862128e56ac7aa8cd2333de9 - constrains: - - python 3.12.* *_cpython - license: BSD-3-Clause - license_family: BSD - size: 6278 - timestamp: 1723823099686 - kind: conda name: python_abi version: '3.12' @@ -8217,22 +7583,6 @@ packages: - pkg:pypi/pyzmq?source=hash-mapping size: 361674 timestamp: 1728642457661 -- kind: conda - name: readline - version: '8.2' - build: h8228510_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 - md5: 47d31b792659ce70f470b5c82fdfb7a4 - depends: - - libgcc-ng >=12 - - ncurses >=6.3,<7.0a0 - license: GPL-3.0-only - license_family: GPL - size: 281456 - timestamp: 1679532220005 - kind: conda name: readline version: '8.2' @@ -8250,21 +7600,6 @@ packages: purls: [] size: 281456 timestamp: 1679532220005 -- kind: conda - name: readline - version: '8.2' - build: h92ec313_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 - md5: 8cbb776a2f641b943d413b3e19df71f4 - depends: - - ncurses >=6.3,<7.0a0 - license: GPL-3.0-only - license_family: GPL - size: 250351 - timestamp: 1679532511311 - kind: conda name: readline version: '8.2' @@ -9617,21 +8952,21 @@ packages: timestamp: 1712585504123 - kind: conda name: setuptools - version: 75.5.0 + version: 75.6.0 build: pyhff2d567_0 subdir: noarch noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.5.0-pyhff2d567_0.conda - sha256: 54dcf5f09f74f69641e0063bc695b38340d0349fa8371b1f2ed0c45c5b2fd224 - md5: ade63405adb52eeff89d506cd55908c0 + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_0.conda + sha256: eeec4645f70ce0ed03348397dced9d218a650a42df98592419af61d2689163ed + md5: 68d7d406366926b09a6a023e3d0f71d7 depends: - python >=3.9 license: MIT license_family: MIT purls: - pkg:pypi/setuptools?source=hash-mapping - size: 772480 - timestamp: 1731707561164 + size: 774304 + timestamp: 1732216189406 - kind: conda name: shellingham version: 1.5.4 @@ -9894,21 +9229,6 @@ packages: - pkg:pypi/tinycss2?source=hash-mapping size: 28285 timestamp: 1729802975370 -- kind: conda - name: tk - version: 8.6.13 - build: h5083fa2_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 - md5: b50a57ba89c32b62428b71a875291c9b - depends: - - libzlib >=1.2.13,<2.0.0a0 - license: TCL - license_family: BSD - size: 3145523 - timestamp: 1699202432999 - kind: conda name: tk version: 8.6.13 @@ -9925,22 +9245,6 @@ packages: purls: [] size: 3145523 timestamp: 1699202432999 -- kind: conda - name: tk - version: 8.6.13 - build: noxft_h4845f30_101 - build_number: 101 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e - md5: d453b98d9c83e71da0741bb0ff4d76bc - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<2.0.0a0 - license: TCL - license_family: BSD - size: 3318875 - timestamp: 1699202167581 - kind: conda name: tk version: 8.6.13 @@ -9958,21 +9262,6 @@ packages: purls: [] size: 3318875 timestamp: 1699202167581 -- kind: conda - name: toml - version: 0.10.2 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 - sha256: f0f3d697349d6580e4c2f35ba9ce05c65dc34f9f049e85e45da03800b46139c1 - md5: f832c45a477c78bebd107098db465095 - depends: - - python >=2.7 - license: MIT - license_family: MIT - size: 18433 - timestamp: 1604308660817 - kind: conda name: toml version: 0.10.2 @@ -9990,21 +9279,6 @@ packages: - pkg:pypi/toml?source=hash-mapping size: 18433 timestamp: 1604308660817 -- kind: conda - name: tomli - version: 2.1.0 - build: pyhff2d567_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.1.0-pyhff2d567_0.conda - sha256: 354b8a64d4f3311179d85aefc529ca201a36afc1af090d0010c46be7b79f9a47 - md5: 3fa1089b4722df3a900135925f4519d9 - depends: - - python >=3.9 - license: MIT - license_family: MIT - size: 18741 - timestamp: 1731426862834 - kind: conda name: tomli version: 2.1.0 @@ -10274,18 +9548,6 @@ packages: url: https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl sha256: a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd requires_python: '>=2' -- kind: conda - name: tzdata - version: 2024b - build: hc8b5060_0 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - sha256: 4fde5c3008bf5d2db82f2b50204464314cc3c91c1d953652f7bd01d9e52aefdf - md5: 8ac3367aafb1cc0a068483c580af8015 - license: LicenseRef-Public-Domain - size: 122354 - timestamp: 1728047496079 - kind: conda name: tzdata version: 2024b @@ -10357,12 +9619,12 @@ packages: timestamp: 1632758637093 - kind: conda name: uv - version: 0.5.3 + version: 0.5.4 build: h0f3a69f_0 subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/uv-0.5.3-h0f3a69f_0.conda - sha256: f49110efc4226ab1d7dea746ef96c816f895c4d7011f84214b6230abe30515f5 - md5: 2fd5a028eb55792b119ffa80c1556b67 + url: https://conda.anaconda.org/conda-forge/linux-64/uv-0.5.4-h0f3a69f_0.conda + sha256: 826c427524d1930d66bdbbe9f2a380d46abc02e06b4b9870e4c5eb661a292156 + md5: ecce7c2d83da66eaabf8ba4961a4c828 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 @@ -10371,16 +9633,16 @@ packages: - __glibc >=2.17 license: Apache-2.0 OR MIT purls: [] - size: 10034324 - timestamp: 1732067629668 + size: 10061197 + timestamp: 1732159190433 - kind: conda name: uv - version: 0.5.3 + version: 0.5.4 build: h668ec48_0 subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.5.3-h668ec48_0.conda - sha256: 93e7d6dfbcb09dfcebf31f84a181cc8572ab860fb8d4c4e7631cd8cf1f5007cf - md5: 127225a3e453fa59ce5a715d95e56359 + url: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.5.4-h668ec48_0.conda + sha256: 85b61a53c0f39339c67a4f11b708fa1f59ad5f0a85d907f3c5ff001c88914b31 + md5: baad04fb088c4c66acf74a870bdb4536 depends: - __osx >=11.0 - libcxx >=18 @@ -10388,8 +9650,8 @@ packages: - __osx >=11.0 license: Apache-2.0 OR MIT purls: [] - size: 8858645 - timestamp: 1732068361442 + size: 8942315 + timestamp: 1732160450871 - kind: conda name: verspec version: 0.1.0 @@ -10465,14 +9727,24 @@ packages: - pkg:pypi/watchdog?source=hash-mapping size: 149164 timestamp: 1730493202256 -- kind: pypi +- kind: conda name: wcmatch version: '10.0' - url: https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl - sha256: 0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a - requires_dist: - - bracex>=2.1.1 - requires_python: '>=3.8' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/wcmatch-10.0-pyhd8ed1ab_0.conda + sha256: 9883e1a7c65f91c3480b38137af5b1d88ee38150b1943c356d11f6b0cd374a8b + md5: b262b976f96f01ad6847b20dbea512af + depends: + - bracex >=2.1.1 + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/wcmatch?source=hash-mapping + size: 37788 + timestamp: 1727447886965 - kind: conda name: wcwidth version: 0.2.13 @@ -10542,19 +9814,6 @@ packages: - pkg:pypi/websocket-client?source=hash-mapping size: 47066 timestamp: 1713923494501 -- kind: conda - name: xz - version: 5.2.6 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 - md5: 2161070d867d1b1204ea749c8eec4ef0 - depends: - - libgcc-ng >=12 - license: LGPL-2.1 and GPL-2.0 - size: 418368 - timestamp: 1660346797927 - kind: conda name: xz version: 5.2.6 @@ -10569,17 +9828,6 @@ packages: purls: [] size: 418368 timestamp: 1660346797927 -- kind: conda - name: xz - version: 5.2.6 - build: h57fd34a_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec - md5: 39c6b54e94014701dd157f4f576ed211 - license: LGPL-2.1 and GPL-2.0 - size: 235693 - timestamp: 1660346961024 - kind: conda name: xz version: 5.2.6 @@ -10624,12 +9872,12 @@ packages: timestamp: 1641346969816 - kind: conda name: yarl - version: 1.17.2 + version: 1.18.0 build: py312h66e93f0_0 subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.17.2-py312h66e93f0_0.conda - sha256: 4e870938d29f38cd2aa43247efff6f99f6ecd8973735509122cd3167ccc22add - md5: 99518ade67138dcce4f2751b47ab5b00 + url: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.18.0-py312h66e93f0_0.conda + sha256: 8a1e51303ecac64f10dd0ec548d472c49954c3e2f38023ef28899191580795e1 + md5: 601d2b19a54fd9346ba18c07c2516339 depends: - __glibc >=2.17,<3.0.a0 - idna >=2.0 @@ -10642,16 +9890,16 @@ packages: license_family: Apache purls: - pkg:pypi/yarl?source=hash-mapping - size: 150022 - timestamp: 1731927117182 + size: 151247 + timestamp: 1732220988648 - kind: conda name: yarl - version: 1.17.2 + version: 1.18.0 build: py312hea69d52_0 subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.17.2-py312hea69d52_0.conda - sha256: 43d85ffae29642b81e1ef4191560a7700911f3753078ab23248b8275952abcec - md5: e3d4600d565bac01340b12d3c4cba2b2 + url: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.18.0-py312hea69d52_0.conda + sha256: 4c90de12b1569f85126a12dbbb89f3dc10cee5838335b9c9993ead8bf1594cd3 + md5: f538709098e1642d50f4a01707e7dfdb depends: - __osx >=11.0 - idna >=2.0 @@ -10664,8 +9912,8 @@ packages: license_family: Apache purls: - pkg:pypi/yarl?source=hash-mapping - size: 140245 - timestamp: 1731927409723 + size: 141452 + timestamp: 1732221306526 - kind: conda name: zeromq version: 4.3.5 diff --git a/pixi.toml b/pixi.toml index 0bc945a0..df84c381 100644 --- a/pixi.toml +++ b/pixi.toml @@ -82,6 +82,7 @@ mkdocs-git-authors-plugin = ">=0.9.0,<0.10" mkdocs-git-revision-date-localized-plugin = ">=1.2.9,<2" griffe-inherited-docstrings = ">=1.1.1,<2" mike = ">=2.1.2,<3" +mkdocs-include-markdown-plugin = ">=7.1.1,<8" [feature.docs.pypi-dependencies] mkdocs-awesome-pages-plugin = ">=2.9.3, <3" diff --git a/src/imgtools/cli/__main__.py b/src/imgtools/cli/__main__.py index 920d2297..65adfb15 100644 --- a/src/imgtools/cli/__main__.py +++ b/src/imgtools/cli/__main__.py @@ -5,6 +5,7 @@ from click.decorators import FC from imgtools import __version__ +from imgtools.cli.dicomfind import dicom_finder from imgtools.cli.dicomsort import dicomsort from imgtools.logging import logger @@ -52,6 +53,7 @@ def cli(verbose: int) -> None: cli.add_command(dicomsort) +cli.add_command(dicom_finder, 'find-dicoms') if __name__ == '__main__': cli() diff --git a/src/imgtools/cli/dicomfind.py b/src/imgtools/cli/dicomfind.py new file mode 100644 index 00000000..73cdbc10 --- /dev/null +++ b/src/imgtools/cli/dicomfind.py @@ -0,0 +1,152 @@ +import pathlib +import re + +import click + +from imgtools.dicom import find_dicoms +from imgtools.logging import logger + + +def natural_sort_key(s: str) -> list: + """Sort strings in a natural order.""" + return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', str(s))] + + +@click.command() +@click.argument( + 'path', + type=click.Path( + exists=True, + file_okay=False, + dir_okay=True, + readable=True, + path_type=pathlib.Path, + resolve_path=True, + ), +) +@click.argument( + 'search_input', + nargs=-1, # Allow multiple search inputs + type=str, + required=False, +) +@click.option( + '-e', + '--extension', + default='dcm', + show_default=True, + help='File extension to look for.', +) +@click.option( + '-c', + '--count', + is_flag=True, + default=False, + show_default=True, + help='Whether to just print the count of files found. This is useful for scripts.', +) +@click.option( + '-l', + '--limit', + default=None, + type=int, + show_default=True, + help='The limit of results to return.', +) +@click.option( + '-ch', + '--check-header', + is_flag=True, + default=False, + show_default=True, + help='Whether to check DICOM header for "DICM" signature.', +) +@click.option( + '-s', + '--sorted', + 'sort_results', + is_flag=True, + default=False, + show_default=True, + help='Sort the results alphabetically.', +) +@click.help_option( + '-h', + '--help', +) +def dicom_finder( + search_input: str, + path: pathlib.Path, + extension: str, + check_header: bool, + count: bool, + limit: int, + sort_results: bool, +) -> None: + """A tool to find DICOM files. + + PATH is the directory to search for DICOM files. + + SEARCH_INPUT is an optional list of regex patterns to filter the search results. + + """ + logger.info('Searching for DICOM files.', args=locals()) + + dicom_files = find_dicoms( + directory=path, + check_header=check_header, + recursive=True, + extension=extension, + ) + + if not dicom_files: + warningmsg = f'No DICOM files found in {path}.' + logger.warning( + warningmsg, + directory=path, + check_header=check_header, + recursive=True, + extension=extension, + ) + return + + logger.info('DICOM find successful.', count=len(dicom_files)) + + # Filter by multiple search patterns + for search in search_input: + try: + pattern = re.compile(search) + dicom_files = [f for f in dicom_files if pattern.search(str(f))] + logger.info( + f'Filtered files based on search_input "{search}".', + search_input=search, + filtered_count=len(dicom_files), + ) + except re.error as e: + errmsg = f'Invalid regex pattern "{search}": {str(e)}' + logger.exception(errmsg) + return + + if not dicom_files: + warningmsg = f'Search input "{search_input}" did not match any DICOM files.' + logger.warning(warningmsg) + return + + if count: + click.echo(f'Number of DICOM files found: {len(dicom_files)}') + return + + if sort_results: + dicom_files = sorted(dicom_files, key=lambda p: natural_sort_key(str(p))) + + if limit: + dicom_files = dicom_files[:limit] + + for dicom_file in dicom_files: + click.echo(dicom_file) + + logger.info('Search complete.') + + +if __name__ == '__main__': + dicom_finder() diff --git a/src/imgtools/dicom/sort/sort_method.py b/src/imgtools/dicom/sort/sort_method.py index 5e7fee59..9f46d1eb 100644 --- a/src/imgtools/dicom/sort/sort_method.py +++ b/src/imgtools/dicom/sort/sort_method.py @@ -110,7 +110,8 @@ def choices() -> List[str]: def handle_file( source_path: Path, resolved_path: Path, action: FileAction, overwrite: bool = False ) -> None: - action = FileAction.validate(action) + if not isinstance(action, FileAction): + action = FileAction.validate(action) # Check if the source exists if not source_path.exists(): diff --git a/src/imgtools/dicom/utils.py b/src/imgtools/dicom/utils.py index 57ac2cd4..c93c428b 100644 --- a/src/imgtools/dicom/utils.py +++ b/src/imgtools/dicom/utils.py @@ -6,27 +6,6 @@ - Looking up DICOM tags by keywords with optional hexadecimal formatting. - Checking the existence of DICOM tags. - Finding similar DICOM tags. - -Examples --------- -Find DICOM files in a directory: - >>> from pathlib import Path - >>> from imgtools.dicom.utils import find_dicoms - >>> files = find_dicoms(Path('/data/dicoms'), recursive=True, check_header=True) - >>> len(files) - 10 - -Lookup a DICOM tag: - >>> from imgtools.dicom.utils import lookup_tag - >>> lookup_tag('PatientID') - '1048608' - >>> lookup_tag('PatientID', hex_format=True) - '0x100020' - -Find similar DICOM tags: - >>> from imgtools.dicom.utils import similar_tags - >>> similar_tags('PatinetID') # Misspelled keyword - ['PatientID', 'PatientName', 'PatientBirthDate'] """ import difflib @@ -60,44 +39,63 @@ def find_dicoms( check_header: bool, extension: Optional[str] = None, ) -> List[Path]: - """ - Find DICOM files in a directory. + """Locate DICOM files in a specified directory. - This function searches for files with a specified extension in the provided directory. - It supports recursive search and optional DICOM header validation. + This function scans a directory for files matching the specified extension + and validates them as DICOM files based on the provided options. It supports + recursive search and optional header validation to confirm file validity. Parameters ---------- directory : Path - Directory to search for DICOM files. + The directory in which to search for DICOM files. recursive : bool - If True, search subdirectories recursively. - If False, search only the specified directory. + Whether to include subdirectories in the search. + + - If `True`, recursively search all subdirectories. + - If `False`, search only the specified directory. check_header : bool - If True, validate files by checking for a valid DICOM header. + Whether to validate files by checking for a valid DICOM header. + + - If `True`, perform DICOM header validation (slower but more accurate). + - If `False`, skip header validation and rely on extension. + extension : str, optional - File extension to search for. If None, all files are considered (default is None). + File extension to search for (e.g., "dcm"). If `None`, consider all files + regardless of extension. Returns ------- List[Path] - List of file paths to valid DICOM files. + A list of valid DICOM file paths found in the directory. Notes ----- - - If `check_header` is True, this function may be slower due to header validation. + - If `check_header` is enabled, the function checks each file for a valid + DICOM header, which may slow down the search process. Examples -------- - Find DICOM files with header validation: - >>> from pathlib import Path - >>> find_dicoms(Path('/data'), recursive=True, check_header=True) - [PosixPath('/data/scan1.dcm'), PosixPath('/data/scan2.dcm')] - - Find files without recursive search: - >>> find_dicoms(Path('/data'), recursive=False, check_header=False) - [PosixPath('/data/scan1.dcm')] + Setup + + >>> from pathlib import Path + >>> from imgtools.dicom.utils import find_dicoms + + Find DICOM files recursively without header validation: + + >>> find_dicoms(Path('/data'), recursive=True, check_header=False) + [PosixPath('/data/scan1.dcm'), PosixPath('/data/subdir/scan2.dcm'), PosixPath('/data/subdir/scan3.dcm')] + + Suppose that `scan3.dcm` is not a valid DICOM file. Find DICOM files with header validation: + + >>> find_dicoms(Path('/data'), recursive=True, check_header=True) + [PosixPath('/data/scan1.dcm'), PosixPath('/data/subdir/scan2.dcm')] + + Find DICOM files without recursion: + >>> find_dicoms(Path('/data'), recursive=False, check_header=False) + [PosixPath('/data/scan1.dcm')] """ + pattern = f'*.{extension}' if extension else '*' glob_method = directory.rglob if recursive else directory.glob @@ -139,13 +137,16 @@ def lookup_tag(keyword: str, hex_format: bool = False) -> Optional[str]: Examples -------- + Lookup a DICOM tag in decimal format: - >>> lookup_tag('PatientID') - '1048608' + + >>> lookup_tag('PatientID') + '1048608' Lookup a DICOM tag in hexadecimal format: - >>> lookup_tag('PatientID', hex_format=True) - '0x100020' + + >>> lookup_tag('PatientID', hex_format=True) + '0x100020' """ if (tag := tag_for_keyword(keyword)) is None: return None @@ -154,8 +155,7 @@ def lookup_tag(keyword: str, hex_format: bool = False) -> Optional[str]: @functools.lru_cache(maxsize=1024) def tag_exists(keyword: str) -> bool: - """ - Check if a DICOM tag exists for a given keyword. + """Boolean check if a DICOM tag exists for a given keyword. Parameters ---------- @@ -169,8 +169,10 @@ def tag_exists(keyword: str) -> bool: Examples -------- + >>> tag_exists('PatientID') True + >>> tag_exists('InvalidKeyword') False """ @@ -179,8 +181,9 @@ def tag_exists(keyword: str) -> bool: @functools.lru_cache(maxsize=1024) def similar_tags(keyword: str, n: int = 3, threshold: float = 0.6) -> List[str]: - """ - Find similar DICOM tags for a given keyword. + """Find similar DICOM tags for a given keyword. + + Useful for User Interface to suggest similar tags based on a misspelled keyword. Parameters ---------- @@ -199,11 +202,13 @@ def similar_tags(keyword: str, n: int = 3, threshold: float = 0.6) -> List[str]: Examples -------- Find similar tags for a misspelled keyword: - >>> similar_tags('PatinetID') - ['PatientID', 'PatientName', 'PatientBirthDate']s + + >>> similar_tags('PatinetID') + ['PatientID', 'PatientName', 'PatientBirthDate'] Adjust the number of results and threshold: - >>> similar_tags('PatinetID', n=5, threshold=0.7) - ['PatientID', 'PatientName'] + + >>> similar_tags('PatinetID', n=5, threshold=0.7) + ['PatientID', 'PatientName'] """ return difflib.get_close_matches(keyword, ALL_DICOM_TAGS, n, threshold)