diff --git a/.gitattributes b/.gitattributes index 887a2c1..997504b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # SCM syntax highlighting & preventing 3-way merges -pixi.lock merge=binary linguist-language=YAML linguist-generated=true +pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff diff --git a/README.md b/README.md index 43ad39e..a459092 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ Steps to add a model: -1. Create a contract.py file in the models/ directory. That will get the input data ready to run the model. +1. Create a prepare.py file in the models/ directory. That will get the input data ready to run the model. 2. Create a .def file with the entry point for the model \ No newline at end of file diff --git a/docs/devnotes.md b/docs/devnotes.md index 33b2c19..110cf28 100644 --- a/docs/devnotes.md +++ b/docs/devnotes.md @@ -1,47 +1,25 @@ # Developer Notes -## Purpose of This Section - -This section is for documenting technical decisions, challenges, and solutions encountered during your project. These notes are valuable for: - -- Future you (who will forget why certain decisions were made) -- Collaborators who join the project later -- People coming from your publication who want to reproduce your work -- Anyone who might want to extend your research - -## What to Document - -### Design Decisions - +## Design Decisions Document important decisions about your project's architecture, algorithms, or methodologies: -``` markdown -## Choice of RNA-Seq Analysis Pipeline +### Choice of RECIST longest diameter calculation algorithm +[2026-08-10] Katy S. compared the different algorithms developed by MedSAM2 and BHKLab teams to calculate the longest axial diameter of a 3D segmentation. MedSAM2's method in [`compute_recist_line`](../src/ab_testing/utils/conver_nifti_to_recist_npz.py) under function utilizes OpenCV contours. BHKLab's method (by Kaitlyn K.) in [`get_recist_pts`](../src/ab_testing/utils/annotations.py) measures from the centroid of the slice based on a `transformation of the origin * half of the major axis length`. Based on some testing with the NSCLC-Radiomics dataset, the MedSAM2 method was visually assessed to be more accurate. [Exploration script](../sandbox/recist_comparison.py) -[2025-04-25] We chose the kallisto over STAR pipeline for the following reasons: - 1. The CCLE dataset is very large, and kallisto is faster for quantifying large datasets - 2. GDSC used kallisto, so we can compare our results with theirs -``` +### Multiple lesion handling +[2026-08-10] The nifti to recist npz setup right now expects an nnUnet directory structure for images where the label files can contain multiple lesions with each lesion having a different label number. I (Katy) typically run med-imagetools with the SEPARATE ROI strategy, but could use MERGE so that the data is set up this way. -### Technical Challenges +## Technical Challenges Record significant problems you encountered and how you solved them -``` markdown -## Sample Name Format Issue -[2025-04-25] We encountered a problem with sample name formats between the CCLE and GDSC datasets. - The CCLE dataset uses "BRCA-XX-XXXX" format, while the GDSC dataset uses "BRCA-XX-XXXX-XX". - We had to write a script to remove the last two characters from the sample names in the GDSC dataset. -``` - -### Dependencies and Environment +## Dependencies and Environment Document specific version requirements or compatibility issues: ``` markdown -## Critical Version Dependencies - +### Critical Version Dependencies [2025-04-25] SimpleITK 2.4.1 introduced a bug that flips images, so we froze version 2.4.0 ``` diff --git a/models/medsam2/prepare.py b/models/medsam2/prepare.py deleted file mode 100644 index 2f7d902..0000000 --- a/models/medsam2/prepare.py +++ /dev/null @@ -1,21 +0,0 @@ -import argparse -from pathlib import Path -import pandas as pd - - -def prepare_data(imgtools_path: str | Path, output_path: str | Path): - - imgtools_path = Path(imgtools_path) - - index_csv = pd.read_csv(imgtools_path / f"{imgtools_path.name}_index-simple.csv") - - # DO THE NPZ CONVERSION HERE - - -if __name__ == "__main__": - argparser = argparse.ArgumentParser() - argparser.add_argument("--imgtools_path", type=str, required=True) - argparser.add_argument("--output_path", type=str, required=True) - args = argparser.parse_args() - - prepare_data(args.imgtools_path, args.output_path) \ No newline at end of file diff --git a/pixi.lock b/pixi.lock index fd381a9..b3a7ef9 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1,40 +1,599 @@ -version: 6 +version: 7 +platforms: +- name: linux-64 + virtual-packages: + - __unix=0=0 + - __linux=4.18 + - __glibc=2.28 + - __archspec=0=x86_64 +- name: osx-64 + virtual-packages: + - __unix=0=0 + - __osx=13.0 + - __archspec=0=x86_64 +- name: osx-arm64 + virtual-packages: + - __unix=0=0 + - __osx=13.0 + - __archspec=0=m1 environments: default: channels: - url: https://conda.anaconda.org/conda-forge/ indexes: - https://pypi.org/simple - options: - pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.1.0-ha9f2e26_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.1.0-he0feb66_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.1.0-h934c35e_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-h242f9ac_102_cp314.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - - pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/aa/18aea7d249e824686a935513f07bd845a019197dc49969d9799b92ab5cc1/connected_components_3d-4.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/0d/a17e966e620545c1548125af0b29ac812dd17b197a18a7462ac12fa859ee/matplotlib-3.11.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/73/c3/cec6a3cbaadfdcc02bd6ff02f3abfe09eaa7f4d4e0a525a1e3a3f4bce49c/scikit_image-0.26.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/78/91/3635cdb13318cb0a328abaa69e2b91251caad39d6779aa308098f341f6cb/simplejson-4.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/c4/bc41eb19b0fd0db868f4132920879019318d80cc522ad8f2bca4611af808/scipy-1.18.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/e8/f20557aca240d88e69850ad1ee91756821d094bb1310565c04d25c6682a2/yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/99/461bd36dbdfac6c1c53efa370bd55a83227542d0d118f1677dbf1a3dacd5/numpy-2.5.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c9/54/777e0495acd4fb008791e84889be33d6e7fc8af095b441d939390b7d2491/pywavelets-1.9.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cf/4c/c73f828fdbcd37eaf21d08fa852544a3ca7c2dbb3ea76873d64f2ea413d1/opencv_python-5.0.0.93-cp37-abi3-manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/ec/301532fb2003e6557e6a12106eb1df572ed6f74c08c05c2e7a8913353383/simpleitk-2.5.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h374f1ed_10.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.7.0-h8c408c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-ha1e9b39_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.4-h77d7759_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.3-hc881268_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.6-hb933c43_102_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hb794df6_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-hbc1a06c_7.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/f4/84d160e9fa8cada1e0a9381cae4fa81eecd573577a5b34366d8ced59bdf7/simplejson-4.1.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/5e/9cedc72b9579de6b9bbba5f5004e9af68b0d650d06a808ea830ba44c7e87/connected_components_3d-4.0.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/35/04/3079499fa8cb661ea66d13d6439d5a3ae6710a7afd5c7f72e08914f275f8/matplotlib-3.11.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/44/6b744f92b37ae2833fd423cce8f806d2368859ec325a699dc30389e090b9/scikit_image-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/78/b5/915a19b3de2f7430062b509653563db1633ddbb6f021b06731521115d4e2/scipy-1.18.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/79/4c/a438d23e09ce2033c09f7b784ad2fbdb0adf529e434101ed28f142226f98/opencv_python-5.0.0.93.tar.gz + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/98/35/ba9436e579bd48a8801f2021d842d9ab4994c26e4c7dd3a4c1f1bcb57a9e/yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ac/f8/c3b222bf075b50afd8e949a07a15c4b312a4a84bd8102a332bcd953cbbb4/numpy-2.5.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/1f/18c82122547c9eec2232d800b02ada1fbd30ce2136137b5738acca9d653e/pywavelets-1.9.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c8/30/cb0eec647afea94c1d95bed3c0014a96565404e4225dba2c0c63bbdd6b9a/simpleitk-2.5.6-cp311-abi3-macosx_10_9_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h4e30115_10.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.7.0-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-he64c551_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.3-hd24854e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.6-hf4d206d_102_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-hd3d0363_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hf451053_7.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/17/e1/2c1d4b1987795a92b5bbf7c24fe249ab96aa2573ab0d7604802c189d7b86/numpy-2.5.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/18/a9/a07f76f3c44e02b25cc743af5ef93eef27f7013eadca770451b6a6ccb5db/yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/f5/83590d9355191f86ac663420fec741b82cc547a4afe7c4c1d986bf46e4db/scikit_image-0.26.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/53/a2/69acfe84ec1f32930e801a5782a07fc5c79c8c6599a507b806d859d5da8e/matplotlib-3.11.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/68/31/9a5432c433a7671107182cdc9a20ea78a70f99c4e5334aa54b6d4d0d79ed/simplejson-4.1.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/68/e8/18d2351ef7b6a17c921f1fbac3a19dc3a27f6ea7749c2f5a5877e38202b9/simpleitk-2.5.6-cp311-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/91/5c/663d6c03e9f5ed8e1d851b787d8d96a3b7d9b9b1a7933ef6be0a2bb24ac9/connected_components_3d-4.0.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9c/75/76f6ade78f6102c61034f828e2a22616708df2c9504bc8d6af9dd8f73dc5/opencv_python-5.0.0.93-cp37-abi3-macosx_13_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/d7/88/b72def7262e150d16be13fca37a96481138d624e700340bc3362a7588929/scipy-1.18.0-cp314-cp314-macosx_12_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/eb/e1/1c92ac6b538ef5388caf1a74af61cf6af16ea6d14115bb53357469cb38d6/pywavelets-1.9.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl + qc: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.1.0-ha9f2e26_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.1.0-he0feb66_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.1.0-h934c35e_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-h242f9ac_102_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.16.2-h462bb3b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/aa/18aea7d249e824686a935513f07bd845a019197dc49969d9799b92ab5cc1/connected_components_3d-4.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/0d/a17e966e620545c1548125af0b29ac812dd17b197a18a7462ac12fa859ee/matplotlib-3.11.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/73/c3/cec6a3cbaadfdcc02bd6ff02f3abfe09eaa7f4d4e0a525a1e3a3f4bce49c/scikit_image-0.26.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/78/91/3635cdb13318cb0a328abaa69e2b91251caad39d6779aa308098f341f6cb/simplejson-4.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/c4/bc41eb19b0fd0db868f4132920879019318d80cc522ad8f2bca4611af808/scipy-1.18.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9b/e8/f20557aca240d88e69850ad1ee91756821d094bb1310565c04d25c6682a2/yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/99/461bd36dbdfac6c1c53efa370bd55a83227542d0d118f1677dbf1a3dacd5/numpy-2.5.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c9/54/777e0495acd4fb008791e84889be33d6e7fc8af095b441d939390b7d2491/pywavelets-1.9.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cf/4c/c73f828fdbcd37eaf21d08fa852544a3ca7c2dbb3ea76873d64f2ea413d1/opencv_python-5.0.0.93-cp37-abi3-manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/ec/301532fb2003e6557e6a12106eb1df572ed6f74c08c05c2e7a8913353383/simpleitk-2.5.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h374f1ed_10.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.7.0-h8c408c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-ha1e9b39_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.4-h77d7759_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.3-hc881268_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.6-hb933c43_102_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.16.2-hcca44e8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hb794df6_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-hbc1a06c_7.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/07/f4/84d160e9fa8cada1e0a9381cae4fa81eecd573577a5b34366d8ced59bdf7/simplejson-4.1.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/5e/9cedc72b9579de6b9bbba5f5004e9af68b0d650d06a808ea830ba44c7e87/connected_components_3d-4.0.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/35/04/3079499fa8cb661ea66d13d6439d5a3ae6710a7afd5c7f72e08914f275f8/matplotlib-3.11.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/44/6b744f92b37ae2833fd423cce8f806d2368859ec325a699dc30389e090b9/scikit_image-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/78/b5/915a19b3de2f7430062b509653563db1633ddbb6f021b06731521115d4e2/scipy-1.18.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/79/4c/a438d23e09ce2033c09f7b784ad2fbdb0adf529e434101ed28f142226f98/opencv_python-5.0.0.93.tar.gz + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/98/35/ba9436e579bd48a8801f2021d842d9ab4994c26e4c7dd3a4c1f1bcb57a9e/yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ac/f8/c3b222bf075b50afd8e949a07a15c4b312a4a84bd8102a332bcd953cbbb4/numpy-2.5.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/1f/18c82122547c9eec2232d800b02ada1fbd30ce2136137b5738acca9d653e/pywavelets-1.9.0-cp314-cp314-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c8/30/cb0eec647afea94c1d95bed3c0014a96565404e4225dba2c0c63bbdd6b9a/simpleitk-2.5.6-cp311-abi3-macosx_10_9_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h4e30115_10.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.7.0-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-he64c551_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.3-hd24854e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.6-hf4d206d_102_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.16.2-h828de30_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-hd3d0363_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hf451053_7.conda + - pypi: ./ + - pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/17/e1/2c1d4b1987795a92b5bbf7c24fe249ab96aa2573ab0d7604802c189d7b86/numpy-2.5.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/18/a9/a07f76f3c44e02b25cc743af5ef93eef27f7013eadca770451b6a6ccb5db/yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + - pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + - pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/f5/83590d9355191f86ac663420fec741b82cc547a4afe7c4c1d986bf46e4db/scikit_image-0.26.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/53/a2/69acfe84ec1f32930e801a5782a07fc5c79c8c6599a507b806d859d5da8e/matplotlib-3.11.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/68/31/9a5432c433a7671107182cdc9a20ea78a70f99c4e5334aa54b6d4d0d79ed/simplejson-4.1.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/68/e8/18d2351ef7b6a17c921f1fbac3a19dc3a27f6ea7749c2f5a5877e38202b9/simpleitk-2.5.6-cp311-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl + - pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/91/5c/663d6c03e9f5ed8e1d851b787d8d96a3b7d9b9b1a7933ef6be0a2bb24ac9/connected_components_3d-4.0.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9c/75/76f6ade78f6102c61034f828e2a22616708df2c9504bc8d6af9dd8f73dc5/opencv_python-5.0.0.93-cp37-abi3-macosx_13_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + - pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/d7/88/b72def7262e150d16be13fca37a96481138d624e700340bc3362a7588929/scipy-1.18.0-cp314-cp314-macosx_12_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/eb/e1/1c92ac6b538ef5388caf1a74af61cf6af16ea6d14115bb53357469cb38d6/pywavelets-1.9.0-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda build_number: 20 @@ -48,51 +607,57 @@ packages: license: BSD-3-Clause license_family: BSD purls: [] + run_exports: + strong: + - _openmp_mutex >=4.5 size: 28948 timestamp: 1770939786096 -- pypi: https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl - name: annotated-types - version: 0.7.0 - sha256: 1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 - requires_dist: - - typing-extensions>=4.0.0 ; python_full_version < '3.9' - requires_python: '>=3.8' -- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 - md5: d2ffd7602c02f2b316fd921d39876885 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_10.conda + sha256: 1a0d382c515ebf55f8ee1f38c8b81bc95af5c2acc42ad53b66bc5df932032f96 + md5: e675fabcf81499adc7edf58124fb1e01 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: bzip2-1.0.6 license_family: BSD purls: [] - size: 260182 - timestamp: 1771350215188 -- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b - md5: 489b8e97e666c93f68fdb35c3c9b957f + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 257808 + timestamp: 1785906269155 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-py310h44b86e0_2.conda + sha256: 9f07834f0c546ab14d885ce0366285f61f44e326c0edd1fc63b8294e113ae432 + md5: 72a381cbad04f24b1c2a43ef707f45b4 depends: - - __unix - license: ISC + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + license: MIT + license_family: MIT purls: [] - size: 129868 - timestamp: 1779289852439 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c - md5: 18335a698559cdbcd86150a48bf54ba6 + run_exports: + weak: + - icu >=78.3,<79.0a0 + size: 14459115 + timestamp: 1786545741408 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda + sha256: 27d83f1188cd19bcb7754a078b3fa7f4cfb8527f8eb2fde54dd01fc529d1adec + md5: 449500f2c089da11c40f5c21312e3e07 depends: - __glibc >=2.17,<3.0.a0 - zstd >=1.5.7,<1.6.0a0 constrains: - - binutils_impl_linux-64 2.45.1 + - binutils_impl_linux-64 2.46.1 license: GPL-3.0-only license_family: GPL purls: [] - size: 728002 - timestamp: 1774197446916 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda - sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 - md5: 93764a5ca80616e9c10106cdaec92f74 + run_exports: {} + size: 745303 + timestamp: 1784214507189 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda + sha256: 16feffd9ddbbe5b718515d38ee376c685ba95491cd901244e24671d20b952a77 + md5: b24d3c612f71e7aa74158d92106318b2 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -101,46 +666,54 @@ packages: license: MIT license_family: MIT purls: [] - size: 77294 - timestamp: 1779278686680 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 - md5: a360c33a5abe61c07959e449fa1453eb + run_exports: {} + size: 77856 + timestamp: 1781203599810 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.7.0-h3435931_0.conda + sha256: ac38603008bf1e99b8ed379b1a656a67a70e2841f2b6a069c630cdf6316012d2 + md5: 0abe40a9880086ca4d2e5daf09dceff9 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 58592 - timestamp: 1769456073053 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda - sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 - md5: 57736f29cc2b0ec0b6c2952d3f101b6a + run_exports: + weak: + - libffi >=3.7.0,<3.8.0a0 + size: 67576 + timestamp: 1783520858222 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.1.0-ha9f2e26_1.conda + sha256: d5cb8475131c31680f8fd30512c418f373064e272e452063276a8fb14c9fa42f + md5: 5a7d954665c707c93311657cd779c705 depends: - __glibc >=2.17,<3.0.a0 - _openmp_mutex >=4.5 constrains: - - libgcc-ng ==15.2.0=*_19 - - libgomp 15.2.0 he0feb66_19 + - libgomp 16.1.0 he0feb66_1 + - libgcc-ng ==16.1.0=*_1 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 1041084 - timestamp: 1778269013026 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b - md5: faac990cb7aedc7f3a2224f2c9b0c26c + run_exports: {} + size: 1057877 + timestamp: 1785375436766 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.1.0-he0feb66_1.conda + sha256: 62cb599ad0539d99386515326d9d5e8f51f75a60c69c2131b21df76edf35bd89 + md5: 88f2d91cb1533194c323534253094d23 depends: - __glibc >=2.17,<3.0.a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 603817 - timestamp: 1778268942614 -- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda - sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d - md5: b88d90cad08e6bc8ad540cb310a761fb + run_exports: + strong: + - _openmp_mutex >=4.5 + size: 640415 + timestamp: 1785375373755 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_1.conda + sha256: 9787df8c22a59c9a70d3e5a10db9ad663485e75e9ccc3f09bd092cb7b95e0dab + md5: 1390b7c5ac0b1d8e447bc5efa6d3c8c2 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -148,66 +721,96 @@ packages: - xz 5.8.3.* license: 0BSD purls: [] - size: 113478 - timestamp: 1775825492909 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 - md5: 2c21e66f50753a083cbe6b80f38268fa + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 112995 + timestamp: 1786348617826 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_2.conda + sha256: 46820b4a835e175940ae20bec00fdddaff804cda27a1408ab1b95e77a2196437 + md5: fcfed1dc5053eb1901b66e7b1fc32588 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: BSD-2-Clause - license_family: BSD purls: [] - size: 92400 - timestamp: 1769482286018 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.1-h0c1763c_0.conda - sha256: 54cdcd3214313b62c2a8ee277e6f42150d9b748264c1b70d958bf735e420ef8d - md5: 7dc38adcbf71e6b38748e919e16e0dce + run_exports: {} + size: 92759 + timestamp: 1786650399772 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-hf4e2dac_0.conda + sha256: 72023efc207fe681e26b65fc9d668062cf0b4f0eacf3431e6eb099b95c1f2efd + md5: df088a279cd5e6fd2790b4c196434da1 depends: - __glibc >=2.17,<3.0.a0 + - icu >=78.3,<79.0a0 - libgcc >=14 - libzlib >=1.3.2,<2.0a0 license: blessing purls: [] - size: 954962 - timestamp: 1777986471789 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda - sha256: 3f0edf1280e2f6684a986f821eaa3e123d2694a00b31b96ca0d4a4c12c129231 - md5: 7d0a66598195ef00b6efc55aefc7453b + run_exports: + weak: + - libsqlite >=3.53.4,<4.0a0 + size: 964200 + timestamp: 1785016112246 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.1.0-h934c35e_1.conda + sha256: 79721dd08aeb0ab9e773f1f9ef41cf4e6c17477e3d72319147619045bce05a09 + md5: aed6cf89adc1e9b846e4367ac538e434 depends: - __glibc >=2.17,<3.0.a0 + - libgcc 16.1.0 ha9f2e26_1 + constrains: + - libstdcxx-ng ==16.1.0=*_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + run_exports: {} + size: 6631744 + timestamp: 1785375462643 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda + sha256: 9b1bdce27a7e31f7d241aeecff67a1f3101d52a2b1e33ccc2cdf2613072bf81f + md5: 01bb81d12c957de066ea7362007df642 + depends: - libgcc >=14 + - __glibc >=2.17,<3.0.a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 40163 - timestamp: 1779118517630 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 - md5: d87ff7921124eccd67248aa483c23fec + run_exports: + weak: + - libuuid >=2.42.2,<3.0a0 + size: 40017 + timestamp: 1781625522462 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_3.conda + sha256: eb8a0db0aa570124f7d2a93d7c7f596e3390df5e047818d873baad32985fc736 + md5: 0de0122d9570a8ab637c6b73db268389 depends: - __glibc >=2.17,<3.0.a0 constrains: - - zlib 1.3.2 *_2 + - zlib 1.3.2 *_3 license: Zlib license_family: Other purls: [] - size: 63629 - timestamp: 1774072609062 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 - md5: fc21868a1a5aacc937e7a18747acb8a5 + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 63713 + timestamp: 1785362952714 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_1.conda + sha256: 5d46557214ed184381dafe835b7c94a474a1c3b307a08a250b1ea4779b44ffb3 + md5: ee6c0cd80a60961a1f48aa3e0b91f986 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: X11 AND BSD-3-Clause purls: [] - size: 918956 - timestamp: 1777422145199 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb - md5: da1b85b6a87e141f5140bb9924cecab0 + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 911196 + timestamp: 1786355078102 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_1.conda + sha256: 012096056b97abf1f68c46b7146bd2cbd68c1be762340b4f5dad4fbbe99177bc + md5: c5955c27917ff2234def47f075e71e02 depends: - __glibc >=2.17,<3.0.a0 - ca-certificates @@ -215,65 +818,44 @@ packages: license: Apache-2.0 license_family: Apache purls: [] - size: 3167099 - timestamp: 1775587756857 -- pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl - name: pydantic - version: 2.13.4 - sha256: 45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba - requires_dist: - - annotated-types>=0.6.0 - - pydantic-core==2.46.4 - - typing-extensions>=4.14.1 - - typing-inspection>=0.4.2 - - email-validator>=2.0.0 ; extra == 'email' - - tzdata ; python_full_version >= '3.9' and sys_platform == 'win32' and extra == 'timezone' - requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: pydantic-core - version: 2.46.4 - sha256: 9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a - requires_dist: - - typing-extensions>=4.14.1 - requires_python: '>=3.9' -- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda - build_number: 100 - sha256: 7f77eb57648f545c1f58e10035d0d9d66b0a0efb7c4b58d3ed89ec7269afdde1 - md5: 05051be49267378d2fcd12931e319ac3 + run_exports: + weak: + - openssl >=3.6.3,<4.0a0 + size: 3182423 + timestamp: 1785913583650 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-h242f9ac_102_cp314.conda + build_number: 102 + sha256: f5ff5c1fac471dfed4fc4288856a63eb9d771e6042d9f70420d75b9f488400d8 + md5: 9b6c336ef7195fbee1c10c09bfcf901b depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.7.5,<3.0a0 - - libffi >=3.5.2,<3.6.0a0 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 - libgcc >=14 - - liblzma >=5.8.2,<6.0a0 + - liblzma >=5.8.3,<6.0a0 - libmpdec >=4.0.0,<5.0a0 - - libsqlite >=3.52.0,<4.0a0 - - libuuid >=2.42,<3.0a0 + - libsqlite >=3.53.4,<4.0a0 + - libuuid >=2.42.2,<3.0a0 - libzlib >=1.3.2,<2.0a0 - - ncurses >=6.5,<7.0a0 - - openssl >=3.5.6,<4.0a0 - - python_abi 3.13.* *_cp313 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 - readline >=8.3,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata + - zstd >=1.5.7,<1.6.0a0 license: Python-2.0 purls: [] - size: 37358322 - timestamp: 1775614712638 - python_site_packages_path: lib/python3.13/site-packages -- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - build_number: 8 - sha256: 210bffe7b121e651419cb196a2a63687b087497595c9be9d20ebe97dd06060a7 - md5: 94305520c52a4aa3f6c2b1ff6008d9f8 - constrains: - - python 3.13.* *_cp313 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 7002 - timestamp: 1752805902938 + run_exports: + weak: + - python_abi 3.14.* *_cp314 + noarch: + - python + size: 36866750 + timestamp: 1786444737142 + python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 md5: d7d95fc8287ea7bf33e0e7116d2b95ec @@ -284,49 +866,2481 @@ packages: license: GPL-3.0-only license_family: GPL purls: [] + run_exports: + weak: + - readline >=8.3,<9.0a0 size: 345073 timestamp: 1765813471974 -- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac - md5: cffd3bdd58090148f4cfcd831f4b26ab +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.16.2-h462bb3b_0.conda + noarch: python + sha256: 2730d570f45ba836f5b85700776cc4527894c640ebacb536fb5db138c845ee63 + md5: 8a00805aae730fb6266343985496ee07 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=hash-mapping + run_exports: {} + size: 9481279 + timestamp: 1786151870074 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd70dff1_3.conda + build_number: 103 + sha256: 43624eab22f5f29df7d6ffe914cf442f28fd559b55b290906255492826e636e8 + md5: 48a1049e710857572fc2a832aa394d9f depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - - libzlib >=1.3.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 constrains: - - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libx11 >=1.8.13,<2.0a0 license: TCL + purls: [] + run_exports: + weak: + - tk >=8.6.13,<8.7.0a0 + size: 3550916 + timestamp: 1784229071544 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda + sha256: 47d682b9f6d6ec9eb1a6e6c3e75ea6273e899e78fb7fc59f81d39745009fbc60 + md5: aa459086047c0e5e27023ab19f8cb86a + depends: + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.2,<2.0a0 + license: BSD-3-Clause license_family: BSD purls: [] - size: 3301196 - timestamp: 1769460227866 -- pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl - name: typing-extensions - version: 4.15.0 - sha256: f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 - requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - name: typing-inspection - version: 0.4.2 - sha256: 4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7 - requires_dist: - - typing-extensions>=4.12.0 - requires_python: '>=3.9' -- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c - md5: ad659d0a2b3e47e38d829aa8cad2d610 + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 601301 + timestamp: 1786599621503 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + sha256: 0a0544cf95f64394fe4959286f5c71f5444ad58feb0602e53becb27448d24da6 + md5: 0f51e2391ade309db462a55611263e9c + depends: + - __unix + license: ISC + purls: [] + run_exports: {} + size: 131780 + timestamp: 1784754889428 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + build_number: 8 + sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 + md5: 0539938c55b6b1a59b560e843ad864a4 + constrains: + - python 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + purls: [] + run_exports: {} + size: 6989 + timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda + sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8 + md5: fcb489df604d100968b737f2cb6076c6 license: LicenseRef-Public-Domain purls: [] - size: 119135 - timestamp: 1767016325805 -- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 - md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 + run_exports: {} + size: 118849 + timestamp: 1784250406640 +- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h374f1ed_10.conda + sha256: 4ed83961876dc8844a6f0df49c07b408efbaea275ffb0b37133e24c006990b3a + md5: 9d9a39212a876e4bb751c1cc3927b678 depends: - - __glibc >=2.17,<3.0.a0 - - libzlib >=1.3.1,<2.0a0 + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 133271 + timestamp: 1785906721507 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_1.conda + sha256: 9c96cc05e056e1bba5b545cbbd57b6e01db622dc2c82934caaaa25cfb22fe666 + md5: dcfdea7b7013beef0a4d744d776ea38f + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + purls: [] + run_exports: {} + size: 76020 + timestamp: 1781204303305 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.7.0-h8c408c4_0.conda + sha256: 525e9b574d6a62b73ccd4cb616495fccd11e80c7e6f4fd7e97a9dd5804bf4c0e + md5: b85d1868b8d9af5306443978da2961d6 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - libffi >=3.7.0,<3.8.0a0 + size: 61307 + timestamp: 1783521470318 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_1.conda + sha256: 7915dac7c71c208e40e716e2f6d3eff41a8d5584e0e7c2d46f9bf9bd5f9aa739 + md5: daf49067580fbfeae3ac7f9535400494 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + purls: [] + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 104919 + timestamp: 1786349094608 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-ha1e9b39_2.conda + sha256: 6438d0ef76e81f2b75ad7599685a525407c1d9fb2d6a7c18f360614ae6807970 + md5: b10a43915a31193e06b2781b9d11aec3 + depends: + - __osx >=11.0 + license: BSD-2-Clause + purls: [] + run_exports: {} + size: 79639 + timestamp: 1786651070313 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.4-h77d7759_0.conda + sha256: 5725d44a17d196adba9798a5fd9f692b7039a827cd6145556a072a80e1931c49 + md5: 993009426e1d3aa90eed155171bd59d8 + depends: + - __osx >=11.0 + - libzlib >=1.3.2,<2.0a0 + license: blessing + purls: [] + run_exports: + weak: + - libsqlite >=3.53.4,<4.0a0 + size: 1008531 + timestamp: 1785016345740 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_3.conda + sha256: b2dba286dd6632292b12296e761193b5ef9fb0eaeecaa481f5ba9af72c0c18e1 + md5: 7d3fa28263bb7f8ea32db11f570a5bb6 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_3 + license: Zlib + license_family: Other + purls: [] + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 58993 + timestamp: 1785276808631 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_1.conda + sha256: 12c1d676b9a0e8109b576672519312c5428308f3f3d7706f8717e2f536d5d9e7 + md5: 88a79390f87c8f3334b9999a892e78d4 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + purls: [] + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 834865 + timestamp: 1786356957789 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.3-hc881268_1.conda + sha256: d43abd09a455847108fc821e81cf4e36dba31755263a1313b6f1b538ac218998 + md5: da403ed66c373b5fb25266b4be662327 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + purls: [] + run_exports: + weak: + - openssl >=3.6.3,<4.0a0 + size: 2773506 + timestamp: 1785915436200 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.6-hb933c43_102_cp314.conda + build_number: 102 + sha256: 19e3a84df66b88348387113e2ffa5c5a5d244e15064dc02f805add29815934e2 + md5: 8c2a3f8e3e9aaca5d8336deca3ba483b + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.4,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + run_exports: + weak: + - python_abi 3.14.* *_cp314 + noarch: + - python + size: 14503943 + timestamp: 1786445946056 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + sha256: 4614af680aa0920e82b953fece85a03007e0719c3399f13d7de64176874b80d5 + md5: eefd65452dfe7cce476a519bece46704 + depends: + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + run_exports: + weak: + - readline >=8.3,<9.0a0 + size: 317819 + timestamp: 1765813692798 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.16.2-hcca44e8_0.conda + noarch: python + sha256: 6f1d6a66456e72344d007b908d56613853a571f923230f44318cec1003a5de5a + md5: 6bf1aa5b905251e3af53be763c8fd214 + depends: + - python + - __osx >=11.0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=hash-mapping + run_exports: {} + size: 9456497 + timestamp: 1786152056400 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-hb794df6_3.conda + sha256: 670a364b8285887e5738880bb026f721af2662cfefe9ef64aa9e93eff1981535 + md5: bc699b366e49399bf8e5c6de99bb8cfb + depends: + - __osx >=11.0 + - libzlib >=1.3.2,<2.0a0 + license: TCL + purls: [] + run_exports: + weak: + - tk >=8.6.13,<8.7.0a0 + size: 3516600 + timestamp: 1784229134070 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-hbc1a06c_7.conda + sha256: 5277886d9704a624dc9b79ac985861e1e431bdb39a57c082507ab577a138ec6c + md5: c1d11f04327e40537ffe6cad5b131019 + depends: + - __osx >=11.0 + - libzlib >=1.3.2,<2.0a0 license: BSD-3-Clause license_family: BSD purls: [] - size: 601375 - timestamp: 1764777111296 + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 528228 + timestamp: 1786599702092 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h4e30115_10.conda + sha256: 8ec22f0ba25cbfc2e64d70cf29459eccd7ffdf6436f6a6ff15bbfef799f7d4f6 + md5: b50612e7d190b8061ab4e7dc119cf4d5 + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + run_exports: + weak: + - bzip2 >=1.0.8,<2.0a0 + size: 124965 + timestamp: 1785906749812 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-py310h579977c_2.conda + sha256: 6cdb5dee54c72e56ab189fb3ad33cb28533553d42590e7e831160248f4416a43 + md5: a5efc0b42bb8b42e97d0a29ae3e3c187 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - icu >=78.3,<79.0a0 + size: 14070242 + timestamp: 1786545847761 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_1.conda + sha256: 5af74261101e3c777399c6294b2b5d290e508153268eb2e9ff99c4d69834612f + md5: a915151d5d3c5bf039f5ccc8402a436f + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + purls: [] + run_exports: {} + size: 69362 + timestamp: 1781203631990 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.7.0-hcf2aa1b_0.conda + sha256: 2c6ac9a6cd65af89b2bd448518bb1e13b44a2e48c0d469398e37bcfc0092e832 + md5: 92e8690d170d46d768c32553458c0105 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + run_exports: + weak: + - libffi >=3.7.0,<3.8.0a0 + size: 43734 + timestamp: 1783521647536 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_1.conda + sha256: 23d0630046a3e8b164d8f80f2b74ed2605af2e7050ab9913018056402fae4311 + md5: 8ab10323068b107661a4b9a4af84f3b5 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + purls: [] + run_exports: + weak: + - liblzma >=5.8.3,<6.0a0 + size: 91720 + timestamp: 1786348695846 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_2.conda + sha256: 04cc136c5a956a73aa14e0a160b5822b0b29714e67b299fa1b1fd16dbcba5366 + md5: ff33a4dbd93abc8a798cc4e0e7c8136d + depends: + - __osx >=11.0 + license: BSD-2-Clause + purls: [] + run_exports: {} + size: 73289 + timestamp: 1786651074391 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h1ae2325_0.conda + sha256: 745662565e103f290e9dc4263bbd88285082f8cf699854fe2d5f1e35a4a0d326 + md5: 0e3477c0c3e718dcf2eb74ccc8f68570 + depends: + - __osx >=11.0 + - icu >=78.3,<79.0a0 + - libzlib >=1.3.2,<2.0a0 + license: blessing + purls: [] + run_exports: + weak: + - libsqlite >=3.53.4,<4.0a0 + size: 929203 + timestamp: 1785016131414 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_3.conda + sha256: a18fa5d5bac452401459f966cf0d872224e8080c4ff93c77e168d43ab42ef9d7 + md5: f39288f0ea63ae962e1a2e4f355a0d75 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_3 + license: Zlib + license_family: Other + purls: [] + run_exports: + weak: + - libzlib >=1.3.2,<2.0a0 + size: 47822 + timestamp: 1785277049190 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-he64c551_1.conda + sha256: 7024a48c8c0d0114ed4ab53c76bf9275d50e91ba7cea367a9aead638d3c29c68 + md5: 3dfa0d0316dc246cd44937a557de4501 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + purls: [] + run_exports: + weak: + - ncurses >=6.6,<7.0a0 + size: 804298 + timestamp: 1786355189145 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.3-hd24854e_1.conda + sha256: 66be2283b5b37dcda1332b5e74c1782a8cb14fd2e62e0d38017c2d35bf73c119 + md5: 65d1906712b85d1679263c518d011b5b + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + purls: [] + run_exports: + weak: + - openssl >=3.6.3,<4.0a0 + size: 3109132 + timestamp: 1785913735357 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.6-hf4d206d_102_cp314.conda + build_number: 102 + sha256: 9767b5eee5cef50716708787bb3b4225d2a974bcd50653e856f9db5910a4b17e + md5: 8da4ea285021110e2617f7538c386afc + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.7.0,<3.8.0a0 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.4,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + run_exports: + weak: + - python_abi 3.14.* *_cp314 + noarch: + - python + size: 13960847 + timestamp: 1786444540722 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + sha256: a77010528efb4b548ac2a4484eaf7e1c3907f2aec86123ed9c5212ae44502477 + md5: f8381319127120ce51e081dce4865cf4 + depends: + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + run_exports: + weak: + - readline >=8.3,<9.0a0 + size: 313930 + timestamp: 1765813902568 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.16.2-h828de30_0.conda + noarch: python + sha256: 8900877bfd18dcb27077a1dd9eaa7230ccae8bd6d7fada9b91c3bfbdf705f808 + md5: 57b0c0a8868a452c34904b01e99f3e45 + depends: + - python + - __osx >=11.0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=hash-mapping + run_exports: {} + size: 8732289 + timestamp: 1786152041950 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-hd3d0363_3.conda + sha256: 47186bc7ab8d7e8bee86bbd1a917196f8c21cf63f081fc33cd6d1221af087580 + md5: 8e3cf0e455e6b54519f0b1c72c61780a + depends: + - __osx >=11.0 + - libzlib >=1.3.2,<2.0a0 + license: TCL + purls: [] + run_exports: + weak: + - tk >=8.6.13,<8.7.0a0 + size: 3338712 + timestamp: 1784229090530 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hf451053_7.conda + sha256: da867f5092eb0cb746d353694f0098031fd9817a4ce7d5743121209ae0f406ca + md5: 4ec2684c73812cc2c3d78379384a39cc + depends: + - __osx >=11.0 + - libzlib >=1.3.2,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + run_exports: + weak: + - zstd >=1.5.7,<1.6.0a0 + size: 433687 + timestamp: 1786599629846 +- pypi: ./ + name: ab-testing + requires_dist: + - simpleitk>=2.5.6,<3 + - pydantic>=2.13.4,<3 + - damply>=0.26.1,<0.27 + - med-imagetools>=2.16.0,<3 + - connected-components-3d>=4.0.0,<5 + - opencv-python>=5.0.0.93,<6 + - nibabel>=5.4.2,<6 + - readii + - click>=8.4.2,<9 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: contourpy + version: 1.3.3 + sha256: f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3 + requires_dist: + - numpy>=1.25 + - furo ; extra == 'docs' + - sphinx>=7.2 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - bokeh ; extra == 'bokeh' + - selenium ; extra == 'bokeh' + - contourpy[bokeh,docs] ; extra == 'mypy' + - bokeh ; extra == 'mypy' + - docutils-stubs ; extra == 'mypy' + - mypy==1.17.0 ; extra == 'mypy' + - types-pillow ; extra == 'mypy' + - contourpy[test-no-images] ; extra == 'test' + - matplotlib ; extra == 'test' + - pillow ; extra == 'test' + - pytest ; extra == 'test-no-images' + - pytest-cov ; extra == 'test-no-images' + - pytest-rerunfailures ; extra == 'test-no-images' + - pytest-xdist ; extra == 'test-no-images' + - wurlitzer ; extra == 'test-no-images' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/05/d1/8952806fbf9583004ab479d8f58a9496c3d35f6b6009ddd458bdd9978eaf/dpath-2.2.0-py3-none-any.whl + name: dpath + version: 2.2.0 + sha256: b330a375ded0a0d2ed404440f6c6a715deae5313af40bbb01c8a41d891900576 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/05/e8/108d641e8cc7f1a2bb8745132ba433569dfff6301cac77a0942e2f7f1ae1/pybytesize-0.8.1-py3-none-any.whl + name: pybytesize + version: 0.8.1 + sha256: ae182fa37a8f9e70e9cc0557ed1ff611b28079dbad6311a8634e778bc80ee99f + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/07/f4/84d160e9fa8cada1e0a9381cae4fa81eecd573577a5b34366d8ced59bdf7/simplejson-4.1.1-cp314-cp314-macosx_10_15_x86_64.whl + name: simplejson + version: 4.1.1 + sha256: 225c9caa324c5b554d009fb9cac22aee7711e71bd96f487938c659af467e828e + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*' +- pypi: https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl + name: python-dotenv + version: 1.2.2 + sha256: 1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a + requires_dist: + - click>=5.0 ; extra == 'cli' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl + name: loguru + version: 0.7.3 + sha256: 31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c + requires_dist: + - colorama>=0.3.4 ; sys_platform == 'win32' + - aiocontextvars>=0.2.0 ; python_full_version < '3.7' + - win32-setctime>=1.0.0 ; sys_platform == 'win32' + - pre-commit==4.0.1 ; python_full_version >= '3.9' and extra == 'dev' + - tox==3.27.1 ; python_full_version < '3.8' and extra == 'dev' + - tox==4.23.2 ; python_full_version >= '3.8' and extra == 'dev' + - pytest==6.1.2 ; python_full_version < '3.8' and extra == 'dev' + - pytest==8.3.2 ; python_full_version >= '3.8' and extra == 'dev' + - pytest-cov==2.12.1 ; python_full_version < '3.8' and extra == 'dev' + - pytest-cov==5.0.0 ; python_full_version == '3.8.*' and extra == 'dev' + - pytest-cov==6.0.0 ; python_full_version >= '3.9' and extra == 'dev' + - pytest-mypy-plugins==1.9.3 ; python_full_version >= '3.6' and python_full_version < '3.8' and extra == 'dev' + - pytest-mypy-plugins==3.1.0 ; python_full_version >= '3.8' and extra == 'dev' + - colorama==0.4.5 ; python_full_version < '3.8' and extra == 'dev' + - colorama==0.4.6 ; python_full_version >= '3.8' and extra == 'dev' + - freezegun==1.1.0 ; python_full_version < '3.8' and extra == 'dev' + - freezegun==1.5.0 ; python_full_version >= '3.8' and extra == 'dev' + - exceptiongroup==1.1.3 ; python_full_version >= '3.7' and python_full_version < '3.11' and extra == 'dev' + - mypy==0.910 ; python_full_version < '3.6' and extra == 'dev' + - mypy==0.971 ; python_full_version == '3.6.*' and extra == 'dev' + - mypy==1.4.1 ; python_full_version == '3.7.*' and extra == 'dev' + - mypy==1.13.0 ; python_full_version >= '3.8' and extra == 'dev' + - sphinx==8.1.3 ; python_full_version >= '3.11' and extra == 'dev' + - sphinx-rtd-theme==3.0.2 ; python_full_version >= '3.11' and extra == 'dev' + - myst-parser==4.0.0 ; python_full_version >= '3.11' and extra == 'dev' + - build==1.2.2 ; python_full_version >= '3.11' and extra == 'dev' + - twine==6.0.1 ; python_full_version >= '3.11' and extra == 'dev' + requires_python: '>=3.5,<4.0' +- pypi: https://files.pythonhosted.org/packages/0d/b4/fbeb1612aab895d592375692d29bc98710d7026067b9a97d8ea87d8d029c/orcestra_downloader-0.15.0-py3-none-any.whl + name: orcestra-downloader + version: 0.15.0 + sha256: 8fe5fec18ef6da3cab4513e3ad6e03a56a0c8c3c29bcdd01b87c7854f8ff490b + requires_dist: + - aiohttp>=3.11.4 + - click>=8.1.7 + - rich + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl + name: pytz + version: 2026.3.post1 + sha256: dd95840dd199baea12d9cc096a1d452caa6596a1c1e4b5f3dbd1541855d5e815 +- pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl + name: pyparsing + version: 3.3.2 + sha256: 850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d + requires_dist: + - railroad-diagrams ; extra == 'diagrams' + - jinja2 ; extra == 'diagrams' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + name: pandas + version: 3.0.2 + sha256: deeca1b5a931fdf0c2212c8a659ade6d3b1edc21f0914ce71ef24456ca7a6535 + requires_dist: + - numpy>=1.26.0 ; python_full_version < '3.14' + - numpy>=2.3.3 ; python_full_version >= '3.14' + - python-dateutil>=2.8.2 + - tzdata ; sys_platform == 'win32' + - tzdata ; sys_platform == 'emscripten' + - hypothesis>=6.116.0 ; extra == 'test' + - pytest>=8.3.4 ; extra == 'test' + - pytest-xdist>=3.6.1 ; extra == 'test' + - pyarrow>=13.0.0 ; extra == 'pyarrow' + - bottleneck>=1.4.2 ; extra == 'performance' + - numba>=0.60.0 ; extra == 'performance' + - numexpr>=2.10.2 ; extra == 'performance' + - scipy>=1.14.1 ; extra == 'computation' + - xarray>=2024.10.0 ; extra == 'computation' + - fsspec>=2024.10.0 ; extra == 'fss' + - s3fs>=2024.10.0 ; extra == 'aws' + - gcsfs>=2024.10.0 ; extra == 'gcp' + - odfpy>=1.4.1 ; extra == 'excel' + - openpyxl>=3.1.5 ; extra == 'excel' + - python-calamine>=0.3.0 ; extra == 'excel' + - pyxlsb>=1.0.10 ; extra == 'excel' + - xlrd>=2.0.1 ; extra == 'excel' + - xlsxwriter>=3.2.0 ; extra == 'excel' + - pyarrow>=13.0.0 ; extra == 'parquet' + - pyarrow>=13.0.0 ; extra == 'feather' + - pyiceberg>=0.8.1 ; extra == 'iceberg' + - tables>=3.10.1 ; extra == 'hdf5' + - pyreadstat>=1.2.8 ; extra == 'spss' + - sqlalchemy>=2.0.36 ; extra == 'postgresql' + - psycopg2>=2.9.10 ; extra == 'postgresql' + - adbc-driver-postgresql>=1.2.0 ; extra == 'postgresql' + - sqlalchemy>=2.0.36 ; extra == 'mysql' + - pymysql>=1.1.1 ; extra == 'mysql' + - sqlalchemy>=2.0.36 ; extra == 'sql-other' + - adbc-driver-postgresql>=1.2.0 ; extra == 'sql-other' + - adbc-driver-sqlite>=1.2.0 ; extra == 'sql-other' + - beautifulsoup4>=4.12.3 ; extra == 'html' + - html5lib>=1.1 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'xml' + - matplotlib>=3.9.3 ; extra == 'plot' + - jinja2>=3.1.5 ; extra == 'output-formatting' + - tabulate>=0.9.0 ; extra == 'output-formatting' + - pyqt5>=5.15.9 ; extra == 'clipboard' + - qtpy>=2.4.2 ; extra == 'clipboard' + - zstandard>=0.23.0 ; extra == 'compression' + - pytz>=2024.2 ; extra == 'timezone' + - adbc-driver-postgresql>=1.2.0 ; extra == 'all' + - adbc-driver-sqlite>=1.2.0 ; extra == 'all' + - beautifulsoup4>=4.12.3 ; extra == 'all' + - bottleneck>=1.4.2 ; extra == 'all' + - fastparquet>=2024.11.0 ; extra == 'all' + - fsspec>=2024.10.0 ; extra == 'all' + - gcsfs>=2024.10.0 ; extra == 'all' + - html5lib>=1.1 ; extra == 'all' + - hypothesis>=6.116.0 ; extra == 'all' + - jinja2>=3.1.5 ; extra == 'all' + - lxml>=5.3.0 ; extra == 'all' + - matplotlib>=3.9.3 ; extra == 'all' + - numba>=0.60.0 ; extra == 'all' + - numexpr>=2.10.2 ; extra == 'all' + - odfpy>=1.4.1 ; extra == 'all' + - openpyxl>=3.1.5 ; extra == 'all' + - psycopg2>=2.9.10 ; extra == 'all' + - pyarrow>=13.0.0 ; extra == 'all' + - pyiceberg>=0.8.1 ; extra == 'all' + - pymysql>=1.1.1 ; extra == 'all' + - pyqt5>=5.15.9 ; extra == 'all' + - pyreadstat>=1.2.8 ; extra == 'all' + - pytest>=8.3.4 ; extra == 'all' + - pytest-xdist>=3.6.1 ; extra == 'all' + - python-calamine>=0.3.0 ; extra == 'all' + - pytz>=2024.2 ; extra == 'all' + - pyxlsb>=1.0.10 ; extra == 'all' + - qtpy>=2.4.2 ; extra == 'all' + - scipy>=1.14.1 ; extra == 'all' + - s3fs>=2024.10.0 ; extra == 'all' + - sqlalchemy>=2.0.36 ; extra == 'all' + - tables>=3.10.1 ; extra == 'all' + - tabulate>=0.9.0 ; extra == 'all' + - xarray>=2024.10.0 ; extra == 'all' + - xlrd>=2.0.1 ; extra == 'all' + - xlsxwriter>=3.2.0 ; extra == 'all' + - zstandard>=0.23.0 ; extra == 'all' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/17/e1/2c1d4b1987795a92b5bbf7c24fe249ab96aa2573ab0d7604802c189d7b86/numpy-2.5.2-cp314-cp314-macosx_11_0_arm64.whl + name: numpy + version: 2.5.2 + sha256: 24b9dc2e3d84aa58523798805194e23e736f3f6ce2d1a5b92583ae734e6dbda8 + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/18/a9/a07f76f3c44e02b25cc743af5ef93eef27f7013eadca770451b6a6ccb5db/yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl + name: yarl + version: 1.24.5 + sha256: e42d75862735da90e7fc5a7b23db0c976f737113a54b3c9777a9b665e9cbff75 + requires_dist: + - idna>=2.0 + - multidict>=4.0 + - propcache>=0.2.1 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl + name: platformdirs + version: 4.11.3 + sha256: 5ed065d443751de711da036041a7a214122efc4a4de393b3f4137ba5576540e7 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl + name: idna + version: '3.18' + sha256: 7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 + requires_dist: + - ruff>=0.6.2 ; extra == 'all' + - mypy>=1.11.2 ; extra == 'all' + - pytest>=8.3.2 ; extra == 'all' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl + name: dill + version: 0.4.1 + sha256: 1e1ce33e978ae97fcfcff5638477032b801c46c7c65cf717f95fbc2248f79a9d + requires_dist: + - objgraph>=1.7.2 ; extra == 'graph' + - gprof2dot>=2022.7.29 ; extra == 'profile' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/1f/fd/ac2161cce19fd67a18c269073f8e86292b5511acec6f8ef6eab88615d032/pykwalify-1.8.0-py2.py3-none-any.whl + name: pykwalify + version: 1.8.0 + sha256: 731dfa87338cca9f559d1fca2bdea37299116e3139b73f78ca90a543722d6651 + requires_dist: + - docopt>=0.6.2 + - python-dateutil>=2.8.0 + - ruamel-yaml>=0.16.0 +- pypi: https://files.pythonhosted.org/packages/24/18/d8544811ab076f876c4892b3714f5b0dad335e1dc33aef826df431b8325d/plotly-6.9.0-py3-none-any.whl + name: plotly + version: 6.9.0 + sha256: 36bebe2f1bb13884774fe61689c329071446f6ce4a8927fb1f0d6fb24f581236 + requires_dist: + - narwhals>=1.15.1 + - packaging + - anywidget ; extra == 'dev' + - build ; extra == 'dev' + - colorcet ; extra == 'dev' + - fiona<=1.9.6 ; python_full_version < '3.9' and extra == 'dev' + - geopandas ; extra == 'dev' + - inflect ; extra == 'dev' + - jupyterlab ; extra == 'dev' + - kaleido>=1.3.0 ; extra == 'dev' + - numpy>=1.22 ; extra == 'dev' + - orjson ; extra == 'dev' + - pandas ; extra == 'dev' + - pdfrw ; extra == 'dev' + - pillow ; extra == 'dev' + - plotly-geo ; extra == 'dev' + - polars[timezone] ; extra == 'dev' + - pyarrow ; extra == 'dev' + - pyshp ; extra == 'dev' + - pytest ; extra == 'dev' + - pytz ; extra == 'dev' + - requests ; extra == 'dev' + - ruff==0.11.12 ; extra == 'dev' + - scikit-image ; extra == 'dev' + - scipy ; extra == 'dev' + - shapely ; extra == 'dev' + - statsmodels ; extra == 'dev' + - vaex ; python_full_version < '3.10' and extra == 'dev' + - xarray ; extra == 'dev' + - build ; extra == 'dev-build' + - jupyterlab ; extra == 'dev-build' + - pytest ; extra == 'dev-build' + - requests ; extra == 'dev-build' + - ruff==0.11.12 ; extra == 'dev-build' + - pytest ; extra == 'dev-core' + - requests ; extra == 'dev-core' + - ruff==0.11.12 ; extra == 'dev-core' + - anywidget ; extra == 'dev-optional' + - build ; extra == 'dev-optional' + - colorcet ; extra == 'dev-optional' + - fiona<=1.9.6 ; python_full_version < '3.9' and extra == 'dev-optional' + - geopandas ; extra == 'dev-optional' + - inflect ; extra == 'dev-optional' + - jupyterlab ; extra == 'dev-optional' + - kaleido>=1.3.0 ; extra == 'dev-optional' + - numpy>=1.22 ; extra == 'dev-optional' + - orjson ; extra == 'dev-optional' + - pandas ; extra == 'dev-optional' + - pdfrw ; extra == 'dev-optional' + - pillow ; extra == 'dev-optional' + - plotly-geo ; extra == 'dev-optional' + - polars[timezone] ; extra == 'dev-optional' + - pyarrow ; extra == 'dev-optional' + - pyshp ; extra == 'dev-optional' + - pytest ; extra == 'dev-optional' + - pytz ; extra == 'dev-optional' + - requests ; extra == 'dev-optional' + - ruff==0.11.12 ; extra == 'dev-optional' + - scikit-image ; extra == 'dev-optional' + - scipy ; extra == 'dev-optional' + - shapely ; extra == 'dev-optional' + - statsmodels ; extra == 'dev-optional' + - vaex ; python_full_version < '3.10' and extra == 'dev-optional' + - xarray ; extra == 'dev-optional' + - numpy>=1,<2 ; extra == 'dev-pandas1' + - pandas>=1,<2 ; extra == 'dev-pandas1' + - setuptools<82 ; extra == 'dev-pandas1' + - pandas>=2,<3 ; extra == 'dev-pandas2' + - pandas>=3 ; python_full_version >= '3.11' and extra == 'dev-pandas3' + - numpy>=1.22 ; extra == 'express' + - kaleido>=1.3.0 ; extra == 'kaleido' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/24/5e/9cedc72b9579de6b9bbba5f5004e9af68b0d650d06a808ea830ba44c7e87/connected_components_3d-4.0.0-cp314-cp314-macosx_10_13_x86_64.whl + name: connected-components-3d + version: 4.0.0 + sha256: a1befcc33e221e212b02348549f5b322872fef040d508da32c9f92882daaa060 + requires_dist: + - numpy + - crackle-codec ; extra == 'stack' + - fastremap ; extra == 'stack' + requires_python: '>=3.9,<4.0' +- pypi: https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl + name: fonttools + version: 4.63.0 + sha256: fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745 + requires_dist: + - lxml>=4.0 ; extra == 'lxml' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'woff' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' + - zopfli>=0.1.4 ; extra == 'woff' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'unicode' + - lz4>=1.7.4.2 ; extra == 'graphite' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'interpolatable' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'interpolatable' + - pycairo ; extra == 'interpolatable' + - matplotlib ; extra == 'plot' + - sympy ; extra == 'symfont' + - xattr ; sys_platform == 'darwin' and extra == 'type1' + - skia-pathops>=0.5.0 ; extra == 'pathops' + - uharfbuzz>=0.45.0 ; extra == 'repacker' + - lxml>=4.0 ; extra == 'all' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'all' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'all' + - zopfli>=0.1.4 ; extra == 'all' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'all' + - lz4>=1.7.4.2 ; extra == 'all' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'all' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'all' + - pycairo ; extra == 'all' + - matplotlib ; extra == 'all' + - sympy ; extra == 'all' + - xattr ; sys_platform == 'darwin' and extra == 'all' + - skia-pathops>=0.5.0 ; extra == 'all' + - uharfbuzz>=0.45.0 ; extra == 'all' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: propcache + version: 0.5.2 + sha256: e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/2c/59/98f5e19752ae8ffea9b0d15b4ad3b20022d96479201b9674d4708e3293d1/pyjpegls-1.5.1.tar.gz + name: pyjpegls + version: 1.5.1 + sha256: d0fe09dfb7f75ce78e3b1e0519912a42f1827d68bbc3609652f4f8743c956025 + requires_dist: + - numpy>=2.0 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl + name: pydantic-settings + version: 2.15.0 + sha256: 0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42 + requires_dist: + - pydantic>=2.7.0 + - python-dotenv>=0.21.0 + - typing-inspection>=0.4.0 + - boto3>=1.35.0 ; extra == 'aws-secrets-manager' + - azure-identity>=1.16.0 ; extra == 'azure-key-vault' + - azure-keyvault-secrets>=4.8.0 ; extra == 'azure-key-vault' + - google-cloud-secret-manager>=2.23.1 ; extra == 'gcp-secret-manager' + - tomli>=2.0.1 ; extra == 'toml' + - pyyaml>=6.0.1 ; extra == 'yaml' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/32/fa/f537d03512335d6f9ba4e1678679a845bc2e73c9d9c1ddbe666909e10c14/pyradiomics_bhklab-3.1.4.tar.gz + name: pyradiomics-bhklab + version: 3.1.4 + sha256: a44a087efc4ede91b5dfa5cf0de58ea3596bfaec1ef2484f278504b0a8fd5ffb + requires_dist: + - numpy + - simpleitk + - pywavelets + - pykwalify + - six + - auditwheel>=6.1.0,<7 ; extra == 'build' + - twine>=5.1.1,<6 ; extra == 'build' + requires_python: '>=3.5' +- pypi: https://files.pythonhosted.org/packages/35/04/3079499fa8cb661ea66d13d6439d5a3ae6710a7afd5c7f72e08914f275f8/matplotlib-3.11.1-cp314-cp314-macosx_10_15_x86_64.whl + name: matplotlib + version: 3.11.1 + sha256: 30c492d4ba9448595b6fd8708c6725963f8148e25c0d8842948da5b05f0ee8d3 + requires_dist: + - contourpy>=1.0.1 + - cycler>=0.10 + - fonttools>=4.28.2 + - kiwisolver>=1.3.1 + - numpy>=1.25 + - packaging>=20.0 + - pillow>=9 + - pyparsing>=3 + - python-dateutil>=2.7 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + name: fonttools + version: 4.63.0 + sha256: 308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b + requires_dist: + - lxml>=4.0 ; extra == 'lxml' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'woff' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' + - zopfli>=0.1.4 ; extra == 'woff' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'unicode' + - lz4>=1.7.4.2 ; extra == 'graphite' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'interpolatable' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'interpolatable' + - pycairo ; extra == 'interpolatable' + - matplotlib ; extra == 'plot' + - sympy ; extra == 'symfont' + - xattr ; sys_platform == 'darwin' and extra == 'type1' + - skia-pathops>=0.5.0 ; extra == 'pathops' + - uharfbuzz>=0.45.0 ; extra == 'repacker' + - lxml>=4.0 ; extra == 'all' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'all' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'all' + - zopfli>=0.1.4 ; extra == 'all' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'all' + - lz4>=1.7.4.2 ; extra == 'all' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'all' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'all' + - pycairo ; extra == 'all' + - matplotlib ; extra == 'all' + - sympy ; extra == 'all' + - xattr ; sys_platform == 'darwin' and extra == 'all' + - skia-pathops>=0.5.0 ; extra == 'all' + - uharfbuzz>=0.45.0 ; extra == 'all' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/3b/d7/601b6396b33536811668935faa790112266c70661be94555999be431f86f/nibabel-5.4.2-py3-none-any.whl + name: nibabel + version: 5.4.2 + sha256: 553482c5f1e1034fc312edf6fb7f32236c0056439845d1c29293b7e8c98d4854 + requires_dist: + - importlib-resources>=5.12 ; python_full_version < '3.12' + - numpy>=1.25 + - packaging>=20 + - typing-extensions>=4.6 ; python_full_version < '3.13' + - backports-zstd>=1.1 ; python_full_version < '3.14' and extra == 'all' + - h5py>=3.8 ; extra == 'all' + - indexed-gzip>=1.6 ; extra == 'all' + - pillow>=8.4 ; extra == 'all' + - pydicom>=2.3 ; extra == 'all' + - scipy>=1.11 ; extra == 'all' + - pydicom>=2.3 ; extra == 'dicom' + - pillow>=8.4 ; extra == 'dicomfs' + - pydicom>=2.3 ; extra == 'dicomfs' + - indexed-gzip>=1.6 ; extra == 'indexed-gzip' + - h5py>=3.8 ; extra == 'minc2' + - scipy>=1.11 ; extra == 'spm' + - coverage[toml]>=7.2 ; extra == 'test' + - pytest-cov>=6 ; extra == 'test' + - pytest-doctestplus>=1.4 ; extra == 'test' + - pytest-httpserver>=1.0.7 ; extra == 'test' + - pytest-xdist>=3.5 ; extra == 'test' + - pytest>=8 ; extra == 'test' + - matplotlib>=3.7 ; extra == 'viewers' + - backports-zstd>=1.1 ; python_full_version < '3.14' and extra == 'zstd' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl + name: imageio + version: 2.37.4 + sha256: 1ab2e22c8debf700f24c3ac43e8f95f3b3a8110c83b93411e97b4b0b2cd1c7e6 + requires_dist: + - numpy + - pillow>=8.3.2 + - imageio-ffmpeg ; extra == 'ffmpeg' + - psutil ; extra == 'ffmpeg' + - fsspec[http] ; extra == 'freeimage' + - pillow-heif ; extra == 'pillow-heif' + - tifffile ; extra == 'tifffile' + - av ; extra == 'pyav' + - astropy ; extra == 'fits' + - rawpy ; extra == 'rawpy' + - numpy>2 ; extra == 'rawpy' + - gdal ; extra == 'gdal' + - itk ; extra == 'itk' + - black ; extra == 'linting' + - flake8 ; extra == 'linting' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - fsspec[github] ; extra == 'test' + - sphinx<6 ; extra == 'docs' + - numpydoc ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - fsspec[github] ; extra == 'dev' + - black ; extra == 'dev' + - flake8 ; extra == 'dev' + - av ; extra == 'all-plugins' + - astropy ; extra == 'all-plugins' + - fsspec[http] ; extra == 'all-plugins' + - imageio-ffmpeg ; extra == 'all-plugins' + - numpy>2 ; extra == 'all-plugins' + - pillow-heif ; extra == 'all-plugins' + - psutil ; extra == 'all-plugins' + - rawpy ; extra == 'all-plugins' + - tifffile ; extra == 'all-plugins' + - fsspec[http] ; extra == 'all-plugins-pypy' + - imageio-ffmpeg ; extra == 'all-plugins-pypy' + - pillow-heif ; extra == 'all-plugins-pypy' + - psutil ; extra == 'all-plugins-pypy' + - astropy ; extra == 'full' + - av ; extra == 'full' + - black ; extra == 'full' + - flake8 ; extra == 'full' + - fsspec[github,http] ; extra == 'full' + - imageio-ffmpeg ; extra == 'full' + - numpydoc ; extra == 'full' + - numpy>2 ; extra == 'full' + - pillow-heif ; extra == 'full' + - psutil ; extra == 'full' + - pydata-sphinx-theme ; extra == 'full' + - pytest ; extra == 'full' + - pytest-cov ; extra == 'full' + - rawpy ; extra == 'full' + - sphinx<6 ; extra == 'full' + - tifffile ; extra == 'full' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/40/f5/83590d9355191f86ac663420fec741b82cc547a4afe7c4c1d986bf46e4db/scikit_image-0.26.0-cp314-cp314-macosx_11_0_arm64.whl + name: scikit-image + version: 0.26.0 + sha256: ce00600cd70d4562ed59f80523e18cdcc1fae0e10676498a01f73c255774aefd + requires_dist: + - numpy>=1.24 + - scipy>=1.11.4 + - networkx>=3.0 + - pillow>=10.1 + - imageio>=2.33,!=2.35.0 + - tifffile>=2022.8.12 + - packaging>=21 + - lazy-loader>=0.4 + - meson-python>=0.16 ; extra == 'build' + - ninja>=1.11.1.1 ; extra == 'build' + - cython>=3.0.8,!=3.2.0b1 ; extra == 'build' + - pythran>=0.16 ; extra == 'build' + - numpy>=2.0 ; extra == 'build' + - spin==0.13 ; extra == 'build' + - build>=1.2.1 ; extra == 'build' + - pooch>=1.6.0 ; extra == 'data' + - pre-commit ; extra == 'developer' + - ipython ; extra == 'developer' + - docstub==0.3.0.post0 ; extra == 'developer' + - scikit-image[asv] ; extra == 'developer' + - asv ; sys_platform != 'emscripten' and extra == 'asv' + - sphinx>=8.0 ; extra == 'docs' + - sphinx-gallery[parallel]>=0.18 ; extra == 'docs' + - numpydoc>=1.7 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - matplotlib>=3.7 ; extra == 'docs' + - dask[array]>=2023.2.0 ; extra == 'docs' + - pandas>=2.0 ; extra == 'docs' + - seaborn>=0.11 ; extra == 'docs' + - pooch>=1.6 ; extra == 'docs' + - tifffile>=2022.8.12 ; extra == 'docs' + - myst-parser ; extra == 'docs' + - intersphinx-registry>=0.2411.14 ; extra == 'docs' + - ipywidgets ; extra == 'docs' + - ipykernel ; extra == 'docs' + - plotly>=5.20 ; extra == 'docs' + - kaleido==0.2.1 ; extra == 'docs' + - scikit-learn>=1.2 ; extra == 'docs' + - sphinx-design>=0.5 ; extra == 'docs' + - pydata-sphinx-theme>=0.16 ; extra == 'docs' + - pywavelets>=1.6 ; extra == 'docs' + - pytest-doctestplus>=1.6.0 ; extra == 'docs' + - simpleitk ; sys_platform != 'emscripten' and extra == 'optional' + - scikit-learn>=1.2 ; extra == 'optional' + - pyamg>=5.2 ; python_full_version < '3.14' and sys_platform != 'emscripten' and extra == 'optional' + - scikit-image[optional-free-threaded] ; extra == 'optional' + - astropy>=6.0 ; extra == 'optional-free-threaded' + - dask[array]>=2023.2.0 ; extra == 'optional-free-threaded' + - matplotlib>=3.7 ; extra == 'optional-free-threaded' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'optional-free-threaded' + - pywavelets>=1.6 ; extra == 'optional-free-threaded' + - numpydoc>=1.7 ; extra == 'test' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'test' + - pytest>=8.3 ; extra == 'test' + - pytest-cov>=2.11.0 ; extra == 'test' + - pytest-pretty ; extra == 'test' + - pytest-localserver ; extra == 'test' + - pytest-faulthandler ; extra == 'test' + - pytest-doctestplus>=1.6.0 ; extra == 'test' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/43/aa/18aea7d249e824686a935513f07bd845a019197dc49969d9799b92ab5cc1/connected_components_3d-4.0.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + name: connected-components-3d + version: 4.0.0 + sha256: bf3d25e7f0ee9a9479fe6d3f544ad2d48deedd15ae48ccaba5c03ce8512585c6 + requires_dist: + - numpy + - crackle-codec ; extra == 'stack' + - fastremap ; extra == 'stack' + requires_python: '>=3.9,<4.0' +- pypi: https://files.pythonhosted.org/packages/46/e0/60466c6d712dad2cf807df315e39863e91609ffd1064ecb835994460bbda/pydicom-3.0.2-py3-none-any.whl + name: pydicom + version: 3.0.2 + sha256: abf971a5440f84dbaf42c4b6758e30e62480902584f8b270b9a5d146e278a07b + requires_dist: + - numpy ; extra == 'basic' + - types-pydicom ; extra == 'basic' + - black==24.8.0 ; extra == 'dev' + - mypy==1.11.2 ; extra == 'dev' + - pydicom-data ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - ruff==0.6.3 ; extra == 'dev' + - types-requests ; extra == 'dev' + - pre-commit ; extra == 'dev' + - pyfakefs>=6.1.6 ; extra == 'dev' + - numpy ; extra == 'docs' + - numpydoc ; extra == 'docs' + - matplotlib ; extra == 'docs' + - pillow ; extra == 'docs' + - sphinx ; extra == 'docs' + - sphinx-rtd-theme ; extra == 'docs' + - sphinx-gallery ; extra == 'docs' + - sphinxcontrib-napoleon ; extra == 'docs' + - sphinxcontrib-jquery ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - pylibjpeg[libjpeg] ; extra == 'gpl-license' + - numpy ; extra == 'pixeldata' + - pillow ; extra == 'pixeldata' + - pyjpegls ; extra == 'pixeldata' + - pylibjpeg[openjpeg] ; extra == 'pixeldata' + - pylibjpeg[rle] ; extra == 'pixeldata' + - python-gdcm ; extra == 'pixeldata' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl + name: kiwisolver + version: 1.5.0 + sha256: 0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl + name: typing-extensions + version: 4.16.0 + sha256: 481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/51/44/6b744f92b37ae2833fd423cce8f806d2368859ec325a699dc30389e090b9/scikit_image-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl + name: scikit-image + version: 0.26.0 + sha256: 63af3d3a26125f796f01052052f86806da5b5e54c6abef152edb752683075a9c + requires_dist: + - numpy>=1.24 + - scipy>=1.11.4 + - networkx>=3.0 + - pillow>=10.1 + - imageio>=2.33,!=2.35.0 + - tifffile>=2022.8.12 + - packaging>=21 + - lazy-loader>=0.4 + - meson-python>=0.16 ; extra == 'build' + - ninja>=1.11.1.1 ; extra == 'build' + - cython>=3.0.8,!=3.2.0b1 ; extra == 'build' + - pythran>=0.16 ; extra == 'build' + - numpy>=2.0 ; extra == 'build' + - spin==0.13 ; extra == 'build' + - build>=1.2.1 ; extra == 'build' + - pooch>=1.6.0 ; extra == 'data' + - pre-commit ; extra == 'developer' + - ipython ; extra == 'developer' + - docstub==0.3.0.post0 ; extra == 'developer' + - scikit-image[asv] ; extra == 'developer' + - asv ; sys_platform != 'emscripten' and extra == 'asv' + - sphinx>=8.0 ; extra == 'docs' + - sphinx-gallery[parallel]>=0.18 ; extra == 'docs' + - numpydoc>=1.7 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - matplotlib>=3.7 ; extra == 'docs' + - dask[array]>=2023.2.0 ; extra == 'docs' + - pandas>=2.0 ; extra == 'docs' + - seaborn>=0.11 ; extra == 'docs' + - pooch>=1.6 ; extra == 'docs' + - tifffile>=2022.8.12 ; extra == 'docs' + - myst-parser ; extra == 'docs' + - intersphinx-registry>=0.2411.14 ; extra == 'docs' + - ipywidgets ; extra == 'docs' + - ipykernel ; extra == 'docs' + - plotly>=5.20 ; extra == 'docs' + - kaleido==0.2.1 ; extra == 'docs' + - scikit-learn>=1.2 ; extra == 'docs' + - sphinx-design>=0.5 ; extra == 'docs' + - pydata-sphinx-theme>=0.16 ; extra == 'docs' + - pywavelets>=1.6 ; extra == 'docs' + - pytest-doctestplus>=1.6.0 ; extra == 'docs' + - simpleitk ; sys_platform != 'emscripten' and extra == 'optional' + - scikit-learn>=1.2 ; extra == 'optional' + - pyamg>=5.2 ; python_full_version < '3.14' and sys_platform != 'emscripten' and extra == 'optional' + - scikit-image[optional-free-threaded] ; extra == 'optional' + - astropy>=6.0 ; extra == 'optional-free-threaded' + - dask[array]>=2023.2.0 ; extra == 'optional-free-threaded' + - matplotlib>=3.7 ; extra == 'optional-free-threaded' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'optional-free-threaded' + - pywavelets>=1.6 ; extra == 'optional-free-threaded' + - numpydoc>=1.7 ; extra == 'test' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'test' + - pytest>=8.3 ; extra == 'test' + - pytest-cov>=2.11.0 ; extra == 'test' + - pytest-pretty ; extra == 'test' + - pytest-localserver ; extra == 'test' + - pytest-faulthandler ; extra == 'test' + - pytest-doctestplus>=1.6.0 ; extra == 'test' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/53/a2/69acfe84ec1f32930e801a5782a07fc5c79c8c6599a507b806d859d5da8e/matplotlib-3.11.1-cp314-cp314-macosx_11_0_arm64.whl + name: matplotlib + version: 3.11.1 + sha256: ac104be2768ffdd8655db9e71b768cbb45f2b9aa7b450cf1595e8f65d3822319 + requires_dist: + - contourpy>=1.0.1 + - cycler>=0.10 + - fonttools>=4.28.2 + - kiwisolver>=1.3.1 + - numpy>=1.25 + - packaging>=20.0 + - pillow>=9 + - pyparsing>=3 + - python-dateutil>=2.7 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/54/20/6aa79ba3570bddd1bf7e951c6123f806751e58e8cce736bad77b2cf348d7/logistro-2.0.1-py3-none-any.whl + name: logistro + version: 2.0.1 + sha256: 06ffa127b9fb4ac8b1972ae6b2a9d7fde57598bf5939cd708f43ec5bba2d31eb + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: pillow + version: 12.3.0 + sha256: 251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b + requires_dist: + - furo ; extra == 'docs' + - olefile ; extra == 'docs' + - sphinx>=8.2 ; extra == 'docs' + - sphinx-autobuild ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinx-inline-tabs ; extra == 'docs' + - sphinxext-opengraph ; extra == 'docs' + - olefile ; extra == 'fpx' + - olefile ; extra == 'mic' + - arro3-compute ; extra == 'test-arrow' + - arro3-core ; extra == 'test-arrow' + - nanoarrow ; extra == 'test-arrow' + - pyarrow ; extra == 'test-arrow' + - coverage>=7.4.2 ; extra == 'tests' + - defusedxml ; extra == 'tests' + - markdown2 ; extra == 'tests' + - olefile ; extra == 'tests' + - packaging ; extra == 'tests' + - pytest ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - pytest-timeout ; extra == 'tests' + - pytest-xdist ; extra == 'tests' + - setuptools ; extra == 'tests' + - trove-classifiers>=2024.10.12 ; extra == 'tests' + - defusedxml ; extra == 'xmp' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/61/bf/fd60001b3abc5222d8eaa4a204cd8c0ae78e75adc688f33ce4bf25b7fafa/fasteners-0.19-py3-none-any.whl + name: fasteners + version: '0.19' + sha256: 758819cb5d94cdedf4e836988b74de396ceacb8e2794d21f82d131fd9ee77237 + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl + name: packaging + version: '26.3' + sha256: d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl + name: propcache + version: 0.5.2 + sha256: 97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/64/0d/a17e966e620545c1548125af0b29ac812dd17b197a18a7462ac12fa859ee/matplotlib-3.11.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: matplotlib + version: 3.11.1 + sha256: 5af0dcda57d471440a7b5b623e70e0a61003518443d9098f211a96ecfbbc25be + requires_dist: + - contourpy>=1.0.1 + - cycler>=0.10 + - fonttools>=4.28.2 + - kiwisolver>=1.3.1 + - numpy>=1.25 + - packaging>=20.0 + - pillow>=9 + - pyparsing>=3 + - python-dateutil>=2.7 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl + name: attrs + version: 26.1.0 + sha256: c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl + name: typing-inspection + version: 0.4.4 + sha256: 65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147 + requires_dist: + - typing-extensions>=4.15.0 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/68/31/9a5432c433a7671107182cdc9a20ea78a70f99c4e5334aa54b6d4d0d79ed/simplejson-4.1.1-cp314-cp314-macosx_11_0_arm64.whl + name: simplejson + version: 4.1.1 + sha256: 95407269340c7f22f09776ea7b717a52cf56cfcf119b5e45f66faa4a26445bea + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*' +- pypi: https://files.pythonhosted.org/packages/68/e8/18d2351ef7b6a17c921f1fbac3a19dc3a27f6ea7749c2f5a5877e38202b9/simpleitk-2.5.6-cp311-abi3-macosx_11_0_arm64.whl + name: simpleitk + version: 2.5.6 + sha256: afcda49474748548fa1b7dbb9f557c3b9feafeb0dd3c2e05d771cc935c86646e +- pypi: https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl + name: aiohappyeyeballs + version: 2.7.1 + sha256: 9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl + name: contourpy + version: 1.3.3 + sha256: fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a + requires_dist: + - numpy>=1.25 + - furo ; extra == 'docs' + - sphinx>=7.2 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - bokeh ; extra == 'bokeh' + - selenium ; extra == 'bokeh' + - contourpy[bokeh,docs] ; extra == 'mypy' + - bokeh ; extra == 'mypy' + - docutils-stubs ; extra == 'mypy' + - mypy==1.17.0 ; extra == 'mypy' + - types-pillow ; extra == 'mypy' + - contourpy[test-no-images] ; extra == 'test' + - matplotlib ; extra == 'test' + - pillow ; extra == 'test' + - pytest ; extra == 'test-no-images' + - pytest-cov ; extra == 'test-no-images' + - pytest-rerunfailures ; extra == 'test-no-images' + - pytest-xdist ; extra == 'test-no-images' + - wurlitzer ; extra == 'test-no-images' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/73/c3/cec6a3cbaadfdcc02bd6ff02f3abfe09eaa7f4d4e0a525a1e3a3f4bce49c/scikit_image-0.26.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + name: scikit-image + version: 0.26.0 + sha256: c6624a76c6085218248154cc7e1500e6b488edcd9499004dd0d35040607d7505 + requires_dist: + - numpy>=1.24 + - scipy>=1.11.4 + - networkx>=3.0 + - pillow>=10.1 + - imageio>=2.33,!=2.35.0 + - tifffile>=2022.8.12 + - packaging>=21 + - lazy-loader>=0.4 + - meson-python>=0.16 ; extra == 'build' + - ninja>=1.11.1.1 ; extra == 'build' + - cython>=3.0.8,!=3.2.0b1 ; extra == 'build' + - pythran>=0.16 ; extra == 'build' + - numpy>=2.0 ; extra == 'build' + - spin==0.13 ; extra == 'build' + - build>=1.2.1 ; extra == 'build' + - pooch>=1.6.0 ; extra == 'data' + - pre-commit ; extra == 'developer' + - ipython ; extra == 'developer' + - docstub==0.3.0.post0 ; extra == 'developer' + - scikit-image[asv] ; extra == 'developer' + - asv ; sys_platform != 'emscripten' and extra == 'asv' + - sphinx>=8.0 ; extra == 'docs' + - sphinx-gallery[parallel]>=0.18 ; extra == 'docs' + - numpydoc>=1.7 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - matplotlib>=3.7 ; extra == 'docs' + - dask[array]>=2023.2.0 ; extra == 'docs' + - pandas>=2.0 ; extra == 'docs' + - seaborn>=0.11 ; extra == 'docs' + - pooch>=1.6 ; extra == 'docs' + - tifffile>=2022.8.12 ; extra == 'docs' + - myst-parser ; extra == 'docs' + - intersphinx-registry>=0.2411.14 ; extra == 'docs' + - ipywidgets ; extra == 'docs' + - ipykernel ; extra == 'docs' + - plotly>=5.20 ; extra == 'docs' + - kaleido==0.2.1 ; extra == 'docs' + - scikit-learn>=1.2 ; extra == 'docs' + - sphinx-design>=0.5 ; extra == 'docs' + - pydata-sphinx-theme>=0.16 ; extra == 'docs' + - pywavelets>=1.6 ; extra == 'docs' + - pytest-doctestplus>=1.6.0 ; extra == 'docs' + - simpleitk ; sys_platform != 'emscripten' and extra == 'optional' + - scikit-learn>=1.2 ; extra == 'optional' + - pyamg>=5.2 ; python_full_version < '3.14' and sys_platform != 'emscripten' and extra == 'optional' + - scikit-image[optional-free-threaded] ; extra == 'optional' + - astropy>=6.0 ; extra == 'optional-free-threaded' + - dask[array]>=2023.2.0 ; extra == 'optional-free-threaded' + - matplotlib>=3.7 ; extra == 'optional-free-threaded' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'optional-free-threaded' + - pywavelets>=1.6 ; extra == 'optional-free-threaded' + - numpydoc>=1.7 ; extra == 'test' + - pooch>=1.6.0 ; sys_platform != 'emscripten' and extra == 'test' + - pytest>=8.3 ; extra == 'test' + - pytest-cov>=2.11.0 ; extra == 'test' + - pytest-pretty ; extra == 'test' + - pytest-localserver ; extra == 'test' + - pytest-faulthandler ; extra == 'test' + - pytest-doctestplus>=1.6.0 ; extra == 'test' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: orjson + version: 3.11.9 + sha256: aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/78/91/3635cdb13318cb0a328abaa69e2b91251caad39d6779aa308098f341f6cb/simplejson-4.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + name: simplejson + version: 4.1.1 + sha256: 3851658d642c1184d2023f0e6c9ce44a21eb1629e74e7c84ef956b128841fe12 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*' +- pypi: https://files.pythonhosted.org/packages/78/b5/915a19b3de2f7430062b509653563db1633ddbb6f021b06731521115d4e2/scipy-1.18.0-cp314-cp314-macosx_10_15_x86_64.whl + name: scipy + version: 1.18.0 + sha256: 4c256ee70c0d1a8a2ace807e199ccd4e3f57037433842abb3fb36bc17eaa9578 + requires_dist: + - numpy>=2.0.0,<2.8 + - pytest>=8.0.0 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-xdist ; extra == 'test' + - asv ; extra == 'test' + - mpmath ; extra == 'test' + - gmpy2 ; extra == 'test' + - threadpoolctl ; extra == 'test' + - scikit-umfpack ; extra == 'test' + - pooch ; extra == 'test' + - hypothesis>=6.30 ; extra == 'test' + - array-api-strict>=2.3.1 ; extra == 'test' + - cython ; extra == 'test' + - meson ; extra == 'test' + - ninja ; sys_platform != 'emscripten' and extra == 'test' + - scipy-doctest>=2.0.0 ; extra == 'test' + - sphinx>=5.0.0,<8.2.0 ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - pydata-sphinx-theme>=0.15.2 ; extra == 'doc' + - sphinx-copybutton ; extra == 'doc' + - sphinx-design>=0.4.0 ; extra == 'doc' + - matplotlib>=3.5 ; extra == 'doc' + - numpydoc ; extra == 'doc' + - jupytext ; extra == 'doc' + - myst-nb>=1.2.0 ; extra == 'doc' + - pooch ; extra == 'doc' + - jupyterlite-sphinx>=0.19.1 ; extra == 'doc' + - jupyterlite-pyodide-kernel ; extra == 'doc' + - linkify-it-py ; extra == 'doc' + - tabulate ; extra == 'doc' + - click<8.3.0 ; extra == 'dev' + - spin ; extra == 'dev' + - mypy==1.19.1 ; extra == 'dev' + - pyrefly==0.63.0 ; extra == 'dev' + - typing-extensions ; extra == 'dev' + - types-psutil ; extra == 'dev' + - pycodestyle ; extra == 'dev' + - ruff>=0.12.0 ; extra == 'dev' + - cython-lint>=0.12.2 ; extra == 'dev' + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/79/4c/a438d23e09ce2033c09f7b784ad2fbdb0adf529e434101ed28f142226f98/opencv_python-5.0.0.93.tar.gz + name: opencv-python + version: 5.0.0.93 + sha256: 66aac3e5b5faa48d4025816592f3af19e4bfc2c68dec067bae2dbb4ca10aa9e2 + requires_dist: + - numpy<2.0 ; python_full_version < '3.9' + - numpy>=2 ; python_full_version >= '3.9' + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/79/a1/cea74d6beab94f9a44896f8d82eb23d708aeaf0715f80254720c09eff52d/highdicom-0.28.1-py3-none-any.whl + name: highdicom + version: 0.28.1 + sha256: 76d4b2ad2e104ad5d29c2901ff9a6eab52ce31f49d366bf77f36b48da82c152f + requires_dist: + - numpy>=1.19 + - pillow>=8.3 + - pydicom>=3.0.1 + - pyjpegls>=1.0.0 + - typing-extensions>=4.0.0 + - packaging>=17.1 + - pylibjpeg-libjpeg>=2.1 ; extra == 'libjpeg' + - pylibjpeg-openjpeg>=2.0.0 ; extra == 'libjpeg' + - pylibjpeg>=2.0 ; extra == 'libjpeg' + - itk>=5.4.0 ; extra == 'itk' + - simpleitk>=2.2.1 ; extra == 'simpleitk' + - nibabel>=4.0.0 ; extra == 'nibabel' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl + name: joblib + version: 1.5.3 + sha256: 5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/7e/85/a5bfaebfd305ac18b57b0854d74e37e586809061a91fda62f0bd50c8518e/narwhals-2.24.0-py3-none-any.whl + name: narwhals + version: 2.24.0 + sha256: 42fdedf44e5b2ca7505630d45b4ac3058f38d8485cba9fe1652ca23152df7489 + requires_dist: + - cudf-cu12>=24.10.0 ; sys_platform == 'linux' and extra == 'cudf' + - dask[dataframe]>=2024.8 ; extra == 'dask' + - duckdb>=1.1 ; extra == 'duckdb' + - ibis-framework>=6.0.0 ; extra == 'ibis' + - packaging>=21.3 ; extra == 'ibis' + - pyarrow-hotfix>=0.7 ; extra == 'ibis' + - modin>=0.22.0 ; extra == 'modin' + - pandas>=1.3.4 ; extra == 'pandas' + - polars>=0.20.4 ; extra == 'polars' + - pyarrow>=13.0.0 ; extra == 'pyarrow' + - pyspark>=3.5.0 ; extra == 'pyspark' + - pyspark[connect]>=3.5.0 ; extra == 'pyspark-connect' + - narwhals[duckdb] ; extra == 'sql' + - sqlparse>=0.5.5 ; extra == 'sql' + - sqlframe>=3.22.0,!=3.39.3 ; extra == 'sqlframe' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/7f/c4/bc41eb19b0fd0db868f4132920879019318d80cc522ad8f2bca4611af808/scipy-1.18.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: scipy + version: 1.18.0 + sha256: 8ca01e8ae69f1b18e9a58d91afead31be3cef0dd905a10249dac559ee15460a0 + requires_dist: + - numpy>=2.0.0,<2.8 + - pytest>=8.0.0 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-xdist ; extra == 'test' + - asv ; extra == 'test' + - mpmath ; extra == 'test' + - gmpy2 ; extra == 'test' + - threadpoolctl ; extra == 'test' + - scikit-umfpack ; extra == 'test' + - pooch ; extra == 'test' + - hypothesis>=6.30 ; extra == 'test' + - array-api-strict>=2.3.1 ; extra == 'test' + - cython ; extra == 'test' + - meson ; extra == 'test' + - ninja ; sys_platform != 'emscripten' and extra == 'test' + - scipy-doctest>=2.0.0 ; extra == 'test' + - sphinx>=5.0.0,<8.2.0 ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - pydata-sphinx-theme>=0.15.2 ; extra == 'doc' + - sphinx-copybutton ; extra == 'doc' + - sphinx-design>=0.4.0 ; extra == 'doc' + - matplotlib>=3.5 ; extra == 'doc' + - numpydoc ; extra == 'doc' + - jupytext ; extra == 'doc' + - myst-nb>=1.2.0 ; extra == 'doc' + - pooch ; extra == 'doc' + - jupyterlite-sphinx>=0.19.1 ; extra == 'doc' + - jupyterlite-pyodide-kernel ; extra == 'doc' + - linkify-it-py ; extra == 'doc' + - tabulate ; extra == 'doc' + - click<8.3.0 ; extra == 'dev' + - spin ; extra == 'dev' + - mypy==1.19.1 ; extra == 'dev' + - pyrefly==0.63.0 ; extra == 'dev' + - typing-extensions ; extra == 'dev' + - types-psutil ; extra == 'dev' + - pycodestyle ; extra == 'dev' + - ruff>=0.12.0 ; extra == 'dev' + - cython-lint>=0.12.2 ; extra == 'dev' + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl + name: rich + version: 15.0.0 + sha256: 33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb + requires_dist: + - ipywidgets>=7.5.1,<9 ; extra == 'jupyter' + - markdown-it-py>=2.2.0 + - pygments>=2.13.0,<3.0.0 + requires_python: '>=3.9.0' +- pypi: https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl + name: pillow + version: 12.3.0 + sha256: ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8 + requires_dist: + - furo ; extra == 'docs' + - olefile ; extra == 'docs' + - sphinx>=8.2 ; extra == 'docs' + - sphinx-autobuild ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinx-inline-tabs ; extra == 'docs' + - sphinxext-opengraph ; extra == 'docs' + - olefile ; extra == 'fpx' + - olefile ; extra == 'mic' + - arro3-compute ; extra == 'test-arrow' + - arro3-core ; extra == 'test-arrow' + - nanoarrow ; extra == 'test-arrow' + - pyarrow ; extra == 'test-arrow' + - coverage>=7.4.2 ; extra == 'tests' + - defusedxml ; extra == 'tests' + - markdown2 ; extra == 'tests' + - olefile ; extra == 'tests' + - packaging ; extra == 'tests' + - pytest ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - pytest-timeout ; extra == 'tests' + - pytest-xdist ; extra == 'tests' + - setuptools ; extra == 'tests' + - trove-classifiers>=2024.10.12 ; extra == 'tests' + - defusedxml ; extra == 'xmp' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/85/ed/0357a015892fd68058bf2d39d3fd1958e459b997a7db30aaa6aaa434ae96/aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl + name: aiohttp + version: 3.14.3 + sha256: db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b + requires_dist: + - aiohappyeyeballs>=2.5.0 + - aiosignal>=1.4.0 + - async-timeout>=4.0,<6.0 ; python_full_version < '3.11' + - attrs>=17.3.0 + - frozenlist>=1.1.1 + - multidict>=4.5,<7.0 + - propcache>=0.2.0 + - typing-extensions>=4.4 ; python_full_version < '3.13' + - yarl>=1.17.0,<2.0 + - aiodns>=3.3.0 ; sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotli>=1.2 ; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotlicffi>=1.2 ; platform_python_implementation != 'CPython' and extra == 'speedups' + - backports-zstd ; python_full_version < '3.14' and platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/87/0d/0f91738db1de8ecd6c2e4003a20b6f9569dcbb7fc39a42a72f89f3643791/damply-0.26.1-py3-none-any.whl + name: damply + version: 0.26.1 + sha256: af7d5fd1f210d730f9e6200ffae73563c237f48510a5b4a63e6d531900cfc96a + requires_dist: + - click>=8.2,<9 + - kaleido>=1.0.0 + - loguru>=0.7.3,<0.8 + - packaging>=25.0 + - pandas + - platformdirs>=4.3,<5 + - plotly>=6.1.0,<7 + - pybytesize>=0.8.1,<0.9 + - rich + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: pyyaml + version: 6.0.3 + sha256: c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: pydantic-core + version: 2.46.4 + sha256: 7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b + requires_dist: + - typing-extensions>=4.14.1 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl + name: lazy-loader + version: '0.5' + sha256: ab0ea149e9c554d4ffeeb21105ac60bed7f3b4fd69b1d2360a4add51b170b005 + requires_dist: + - packaging + - pytest>=8.0 ; extra == 'test' + - pytest-cov>=5.0 ; extra == 'test' + - coverage[toml]>=7.2 ; extra == 'test' + - pre-commit==4.3.0 ; extra == 'lint' + - changelist==0.5 ; extra == 'dev' + - spin==0.15 ; extra == 'dev' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl + name: pydantic-core + version: 2.46.4 + sha256: 428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb + requires_dist: + - typing-extensions>=4.14.1 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl + name: frozenlist + version: 1.8.0 + sha256: 119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl + name: orjson + version: 3.11.9 + sha256: b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/8f/2e/1841dc5ea85b40cad066461f92a52ee5aa6b500f064a02776590b944bf79/readii-1.39.0-py3-none-any.whl + name: readii + version: 1.39.0 + sha256: d6ce5561aac8731a04bc6be6743d216cfc617bf1d59fd49cbd3f3b3f174a1381 + requires_dist: + - med-imagetools>=2.13.1,<3 + - orcestra-downloader>=0.9.0,<1 + - pyradiomics-bhklab>=3.1.4,<4 + requires_python: '>=3.10,<3.13' +- pypi: https://files.pythonhosted.org/packages/91/5c/663d6c03e9f5ed8e1d851b787d8d96a3b7d9b9b1a7933ef6be0a2bb24ac9/connected_components_3d-4.0.0-cp314-cp314-macosx_11_0_arm64.whl + name: connected-components-3d + version: 4.0.0 + sha256: cd20e397f41b9087ce2ed745ac35e1ac38b226122a443f6d2a9e51fbc5388af1 + requires_dist: + - numpy + - crackle-codec ; extra == 'stack' + - fastremap ; extra == 'stack' + requires_python: '>=3.9,<4.0' +- pypi: https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl + name: pandas + version: 3.0.2 + sha256: 0555c5882688a39317179ab4a0ed41d3ebc8812ab14c69364bbee8fb7a3f6288 + requires_dist: + - numpy>=1.26.0 ; python_full_version < '3.14' + - numpy>=2.3.3 ; python_full_version >= '3.14' + - python-dateutil>=2.8.2 + - tzdata ; sys_platform == 'win32' + - tzdata ; sys_platform == 'emscripten' + - hypothesis>=6.116.0 ; extra == 'test' + - pytest>=8.3.4 ; extra == 'test' + - pytest-xdist>=3.6.1 ; extra == 'test' + - pyarrow>=13.0.0 ; extra == 'pyarrow' + - bottleneck>=1.4.2 ; extra == 'performance' + - numba>=0.60.0 ; extra == 'performance' + - numexpr>=2.10.2 ; extra == 'performance' + - scipy>=1.14.1 ; extra == 'computation' + - xarray>=2024.10.0 ; extra == 'computation' + - fsspec>=2024.10.0 ; extra == 'fss' + - s3fs>=2024.10.0 ; extra == 'aws' + - gcsfs>=2024.10.0 ; extra == 'gcp' + - odfpy>=1.4.1 ; extra == 'excel' + - openpyxl>=3.1.5 ; extra == 'excel' + - python-calamine>=0.3.0 ; extra == 'excel' + - pyxlsb>=1.0.10 ; extra == 'excel' + - xlrd>=2.0.1 ; extra == 'excel' + - xlsxwriter>=3.2.0 ; extra == 'excel' + - pyarrow>=13.0.0 ; extra == 'parquet' + - pyarrow>=13.0.0 ; extra == 'feather' + - pyiceberg>=0.8.1 ; extra == 'iceberg' + - tables>=3.10.1 ; extra == 'hdf5' + - pyreadstat>=1.2.8 ; extra == 'spss' + - sqlalchemy>=2.0.36 ; extra == 'postgresql' + - psycopg2>=2.9.10 ; extra == 'postgresql' + - adbc-driver-postgresql>=1.2.0 ; extra == 'postgresql' + - sqlalchemy>=2.0.36 ; extra == 'mysql' + - pymysql>=1.1.1 ; extra == 'mysql' + - sqlalchemy>=2.0.36 ; extra == 'sql-other' + - adbc-driver-postgresql>=1.2.0 ; extra == 'sql-other' + - adbc-driver-sqlite>=1.2.0 ; extra == 'sql-other' + - beautifulsoup4>=4.12.3 ; extra == 'html' + - html5lib>=1.1 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'xml' + - matplotlib>=3.9.3 ; extra == 'plot' + - jinja2>=3.1.5 ; extra == 'output-formatting' + - tabulate>=0.9.0 ; extra == 'output-formatting' + - pyqt5>=5.15.9 ; extra == 'clipboard' + - qtpy>=2.4.2 ; extra == 'clipboard' + - zstandard>=0.23.0 ; extra == 'compression' + - pytz>=2024.2 ; extra == 'timezone' + - adbc-driver-postgresql>=1.2.0 ; extra == 'all' + - adbc-driver-sqlite>=1.2.0 ; extra == 'all' + - beautifulsoup4>=4.12.3 ; extra == 'all' + - bottleneck>=1.4.2 ; extra == 'all' + - fastparquet>=2024.11.0 ; extra == 'all' + - fsspec>=2024.10.0 ; extra == 'all' + - gcsfs>=2024.10.0 ; extra == 'all' + - html5lib>=1.1 ; extra == 'all' + - hypothesis>=6.116.0 ; extra == 'all' + - jinja2>=3.1.5 ; extra == 'all' + - lxml>=5.3.0 ; extra == 'all' + - matplotlib>=3.9.3 ; extra == 'all' + - numba>=0.60.0 ; extra == 'all' + - numexpr>=2.10.2 ; extra == 'all' + - odfpy>=1.4.1 ; extra == 'all' + - openpyxl>=3.1.5 ; extra == 'all' + - psycopg2>=2.9.10 ; extra == 'all' + - pyarrow>=13.0.0 ; extra == 'all' + - pyiceberg>=0.8.1 ; extra == 'all' + - pymysql>=1.1.1 ; extra == 'all' + - pyqt5>=5.15.9 ; extra == 'all' + - pyreadstat>=1.2.8 ; extra == 'all' + - pytest>=8.3.4 ; extra == 'all' + - pytest-xdist>=3.6.1 ; extra == 'all' + - python-calamine>=0.3.0 ; extra == 'all' + - pytz>=2024.2 ; extra == 'all' + - pyxlsb>=1.0.10 ; extra == 'all' + - qtpy>=2.4.2 ; extra == 'all' + - scipy>=1.14.1 ; extra == 'all' + - s3fs>=2024.10.0 ; extra == 'all' + - sqlalchemy>=2.0.36 ; extra == 'all' + - tables>=3.10.1 ; extra == 'all' + - tabulate>=0.9.0 ; extra == 'all' + - xarray>=2024.10.0 ; extra == 'all' + - xlrd>=2.0.1 ; extra == 'all' + - xlsxwriter>=3.2.0 ; extra == 'all' + - zstandard>=0.23.0 ; extra == 'all' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/97/a3/7056b86dc0d9ec709ea9777eae3b0161428f943372f8b98c01c11593b682/aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl + name: aiohttp + version: 3.14.3 + sha256: ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646 + requires_dist: + - aiohappyeyeballs>=2.5.0 + - aiosignal>=1.4.0 + - async-timeout>=4.0,<6.0 ; python_full_version < '3.11' + - attrs>=17.3.0 + - frozenlist>=1.1.1 + - multidict>=4.5,<7.0 + - propcache>=0.2.0 + - typing-extensions>=4.4 ; python_full_version < '3.13' + - yarl>=1.17.0,<2.0 + - aiodns>=3.3.0 ; sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotli>=1.2 ; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotlicffi>=1.2 ; platform_python_implementation != 'CPython' and extra == 'speedups' + - backports-zstd ; python_full_version < '3.14' and platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/98/35/ba9436e579bd48a8801f2021d842d9ab4994c26e4c7dd3a4c1f1bcb57a9e/yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl + name: yarl + version: 1.24.5 + sha256: ff330d3c30db4eb6b01d79e29d2d0b407a7ecad39cfd9ec993ece57396a2ec0d + requires_dist: + - idna>=2.0 + - multidict>=4.0 + - propcache>=0.2.1 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl + name: annotated-types + version: 0.8.0 + sha256: f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/9b/e8/f20557aca240d88e69850ad1ee91756821d094bb1310565c04d25c6682a2/yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: yarl + version: 1.24.5 + sha256: 66410eb6345d467151934b49bfa70fb32f5b35a6140baa40ad97d6436abea2e9 + requires_dist: + - idna>=2.0 + - multidict>=4.0 + - propcache>=0.2.1 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/9c/75/76f6ade78f6102c61034f828e2a22616708df2c9504bc8d6af9dd8f73dc5/opencv_python-5.0.0.93-cp37-abi3-macosx_13_0_arm64.whl + name: opencv-python + version: 5.0.0.93 + sha256: 198a75138241810206a17c829dbcc40a7cb1841cda538ca86cbbfc6c7d95f898 + requires_dist: + - numpy<2.0 ; python_full_version < '3.9' + - numpy>=2 ; python_full_version >= '3.9' + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl + name: pyyaml + version: 6.0.3 + sha256: 8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/9e/b9/a6d8bb7d228940f01885bd9f327ab7f9d366a9be775c4bf366bf9d9477ae/kaleido-1.3.0-py3-none-any.whl + name: kaleido + version: 1.3.0 + sha256: 52714dfd38e8f2a114831826200c40bb10d0ca0c11d4272f3f48ad499cd8f8ea + requires_dist: + - choreographer>=1.3.0 + - logistro>=1.0.8 + - orjson>=3.10.15 + - packaging + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl + name: networkx + version: 3.6.1 + sha256: d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762 + requires_dist: + - asv ; extra == 'benchmarking' + - virtualenv ; extra == 'benchmarking' + - numpy>=1.25 ; extra == 'default' + - scipy>=1.11.2 ; extra == 'default' + - matplotlib>=3.8 ; extra == 'default' + - pandas>=2.0 ; extra == 'default' + - pre-commit>=4.1 ; extra == 'developer' + - mypy>=1.15 ; extra == 'developer' + - sphinx>=8.0 ; extra == 'doc' + - pydata-sphinx-theme>=0.16 ; extra == 'doc' + - sphinx-gallery>=0.18 ; extra == 'doc' + - numpydoc>=1.8.0 ; extra == 'doc' + - pillow>=10 ; extra == 'doc' + - texext>=0.6.7 ; extra == 'doc' + - myst-nb>=1.1 ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - osmnx>=2.0.0 ; extra == 'example' + - momepy>=0.7.2 ; extra == 'example' + - contextily>=1.6 ; extra == 'example' + - seaborn>=0.13 ; extra == 'example' + - cairocffi>=1.7 ; extra == 'example' + - igraph>=0.11 ; extra == 'example' + - scikit-learn>=1.5 ; extra == 'example' + - iplotx>=0.9.0 ; extra == 'example' + - lxml>=4.6 ; extra == 'extra' + - pygraphviz>=1.14 ; extra == 'extra' + - pydot>=3.0.1 ; extra == 'extra' + - sympy>=1.10 ; extra == 'extra' + - build>=0.10 ; extra == 'release' + - twine>=4.0 ; extra == 'release' + - wheel>=0.40 ; extra == 'release' + - changelist==0.5 ; extra == 'release' + - pytest>=7.2 ; extra == 'test' + - pytest-cov>=4.0 ; extra == 'test' + - pytest-xdist>=3.0 ; extra == 'test' + - pytest-mpl ; extra == 'test-extras' + - pytest-randomly ; extra == 'test-extras' + requires_python: '>=3.11,!=3.14.1' +- pypi: https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl + name: frozenlist + version: 1.8.0 + sha256: 4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz + name: docopt + version: 0.6.2 + sha256: 49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491 +- pypi: https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + name: frozenlist + version: 1.8.0 + sha256: cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl + name: structlog + version: 25.5.0 + sha256: a8453e9b9e636ec59bd9e79bbd4a72f025981b3ba0f5837aebf48f02f37a7f9f + requires_dist: + - typing-extensions ; python_full_version < '3.11' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/ac/f8/c3b222bf075b50afd8e949a07a15c4b312a4a84bd8102a332bcd953cbbb4/numpy-2.5.2-cp314-cp314-macosx_10_15_x86_64.whl + name: numpy + version: 2.5.2 + sha256: d787cf769c3baeb5f6235e778edb52c08dfa923789b5958f28e6450f96107cb1 + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl + name: pydantic-core + version: 2.46.4 + sha256: 23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462 + requires_dist: + - typing-extensions>=4.14.1 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + name: mdurl + version: 0.1.2 + sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl + name: markdown-it-py + version: 4.2.0 + sha256: 9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a + requires_dist: + - mdurl~=0.1 + - psutil ; extra == 'benchmarking' + - pytest ; extra == 'benchmarking' + - pytest-benchmark ; extra == 'benchmarking' + - commonmark~=0.9 ; extra == 'compare' + - markdown~=3.4 ; extra == 'compare' + - mistletoe~=1.0 ; extra == 'compare' + - mistune~=3.0 ; extra == 'compare' + - panflute~=2.3 ; extra == 'compare' + - markdown-it-pyrs ; extra == 'compare' + - linkify-it-py>=1,<3 ; extra == 'linkify' + - mdit-py-plugins>=0.5.0 ; extra == 'plugins' + - gprof2dot ; extra == 'profiling' + - mdit-py-plugins>=0.5.0 ; extra == 'rtd' + - myst-parser ; extra == 'rtd' + - pyyaml ; extra == 'rtd' + - sphinx ; extra == 'rtd' + - sphinx-copybutton ; extra == 'rtd' + - sphinx-design ; extra == 'rtd' + - sphinx-book-theme~=1.0 ; extra == 'rtd' + - jupyter-sphinx ; extra == 'rtd' + - ipykernel ; extra == 'rtd' + - coverage ; extra == 'testing' + - pytest ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-regressions ; extra == 'testing' + - pytest-timeout ; extra == 'testing' + - requests ; extra == 'testing' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl + name: propcache + version: 0.5.2 + sha256: fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + name: six + version: 1.17.0 + sha256: 4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- pypi: https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl + name: ruamel-yaml + version: 0.19.1 + sha256: 27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93 + requires_dist: + - ruamel-yaml-clib ; platform_python_implementation == 'CPython' and extra == 'oldlibyaml' + - ruamel-yaml-clibz>=0.3.7 ; platform_python_implementation == 'CPython' and extra == 'libyaml' + - ruamel-yaml-jinja2>=0.2 ; extra == 'jinja2' + - ryd ; extra == 'docs' + - mercurial>5.7 ; extra == 'docs' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/ba/1f/18c82122547c9eec2232d800b02ada1fbd30ce2136137b5738acca9d653e/pywavelets-1.9.0-cp314-cp314-macosx_10_13_x86_64.whl + name: pywavelets + version: 1.9.0 + sha256: 53043d2f3f4e55a576f51ac594fe33181e1d096d958e01524db5070eb3825306 + requires_dist: + - numpy>=1.25,<3 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/ba/6c/ff8bf52315064dbeb55cb5067e191120a5b2e58bb648d0d34cf7969dc2c2/choreographer-1.3.0-py3-none-any.whl + name: choreographer + version: 1.3.0 + sha256: cea4cb739e4f61625e4b53888a8d3fa1d3bf73948b56753e460ab44da7d8d44f + requires_dist: + - logistro>=2.0.1 + - platformdirs>=4.3.6 + - simplejson>=3.19.3 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl + name: pandas + version: 3.0.2 + sha256: db0dbfd2a6cdf3770aa60464d50333d8f3d9165b2f2671bcc299b72de5a6677b + requires_dist: + - numpy>=1.26.0 ; python_full_version < '3.14' + - numpy>=2.3.3 ; python_full_version >= '3.14' + - python-dateutil>=2.8.2 + - tzdata ; sys_platform == 'win32' + - tzdata ; sys_platform == 'emscripten' + - hypothesis>=6.116.0 ; extra == 'test' + - pytest>=8.3.4 ; extra == 'test' + - pytest-xdist>=3.6.1 ; extra == 'test' + - pyarrow>=13.0.0 ; extra == 'pyarrow' + - bottleneck>=1.4.2 ; extra == 'performance' + - numba>=0.60.0 ; extra == 'performance' + - numexpr>=2.10.2 ; extra == 'performance' + - scipy>=1.14.1 ; extra == 'computation' + - xarray>=2024.10.0 ; extra == 'computation' + - fsspec>=2024.10.0 ; extra == 'fss' + - s3fs>=2024.10.0 ; extra == 'aws' + - gcsfs>=2024.10.0 ; extra == 'gcp' + - odfpy>=1.4.1 ; extra == 'excel' + - openpyxl>=3.1.5 ; extra == 'excel' + - python-calamine>=0.3.0 ; extra == 'excel' + - pyxlsb>=1.0.10 ; extra == 'excel' + - xlrd>=2.0.1 ; extra == 'excel' + - xlsxwriter>=3.2.0 ; extra == 'excel' + - pyarrow>=13.0.0 ; extra == 'parquet' + - pyarrow>=13.0.0 ; extra == 'feather' + - pyiceberg>=0.8.1 ; extra == 'iceberg' + - tables>=3.10.1 ; extra == 'hdf5' + - pyreadstat>=1.2.8 ; extra == 'spss' + - sqlalchemy>=2.0.36 ; extra == 'postgresql' + - psycopg2>=2.9.10 ; extra == 'postgresql' + - adbc-driver-postgresql>=1.2.0 ; extra == 'postgresql' + - sqlalchemy>=2.0.36 ; extra == 'mysql' + - pymysql>=1.1.1 ; extra == 'mysql' + - sqlalchemy>=2.0.36 ; extra == 'sql-other' + - adbc-driver-postgresql>=1.2.0 ; extra == 'sql-other' + - adbc-driver-sqlite>=1.2.0 ; extra == 'sql-other' + - beautifulsoup4>=4.12.3 ; extra == 'html' + - html5lib>=1.1 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'html' + - lxml>=5.3.0 ; extra == 'xml' + - matplotlib>=3.9.3 ; extra == 'plot' + - jinja2>=3.1.5 ; extra == 'output-formatting' + - tabulate>=0.9.0 ; extra == 'output-formatting' + - pyqt5>=5.15.9 ; extra == 'clipboard' + - qtpy>=2.4.2 ; extra == 'clipboard' + - zstandard>=0.23.0 ; extra == 'compression' + - pytz>=2024.2 ; extra == 'timezone' + - adbc-driver-postgresql>=1.2.0 ; extra == 'all' + - adbc-driver-sqlite>=1.2.0 ; extra == 'all' + - beautifulsoup4>=4.12.3 ; extra == 'all' + - bottleneck>=1.4.2 ; extra == 'all' + - fastparquet>=2024.11.0 ; extra == 'all' + - fsspec>=2024.10.0 ; extra == 'all' + - gcsfs>=2024.10.0 ; extra == 'all' + - html5lib>=1.1 ; extra == 'all' + - hypothesis>=6.116.0 ; extra == 'all' + - jinja2>=3.1.5 ; extra == 'all' + - lxml>=5.3.0 ; extra == 'all' + - matplotlib>=3.9.3 ; extra == 'all' + - numba>=0.60.0 ; extra == 'all' + - numexpr>=2.10.2 ; extra == 'all' + - odfpy>=1.4.1 ; extra == 'all' + - openpyxl>=3.1.5 ; extra == 'all' + - psycopg2>=2.9.10 ; extra == 'all' + - pyarrow>=13.0.0 ; extra == 'all' + - pyiceberg>=0.8.1 ; extra == 'all' + - pymysql>=1.1.1 ; extra == 'all' + - pyqt5>=5.15.9 ; extra == 'all' + - pyreadstat>=1.2.8 ; extra == 'all' + - pytest>=8.3.4 ; extra == 'all' + - pytest-xdist>=3.6.1 ; extra == 'all' + - python-calamine>=0.3.0 ; extra == 'all' + - pytz>=2024.2 ; extra == 'all' + - pyxlsb>=1.0.10 ; extra == 'all' + - qtpy>=2.4.2 ; extra == 'all' + - scipy>=1.14.1 ; extra == 'all' + - s3fs>=2024.10.0 ; extra == 'all' + - sqlalchemy>=2.0.36 ; extra == 'all' + - tables>=3.10.1 ; extra == 'all' + - tabulate>=0.9.0 ; extra == 'all' + - xarray>=2024.10.0 ; extra == 'all' + - xlrd>=2.0.1 ; extra == 'all' + - xlsxwriter>=3.2.0 ; extra == 'all' + - zstandard>=0.23.0 ; extra == 'all' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl + name: pyyaml + version: 6.0.3 + sha256: 34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl + name: kiwisolver + version: 1.5.0 + sha256: 1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/c7/99/461bd36dbdfac6c1c53efa370bd55a83227542d0d118f1677dbf1a3dacd5/numpy-2.5.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: numpy + version: 2.5.2 + sha256: 318b9a4c845dbea06708a29c84ee429cc3065048db34cdb799047643492050ee + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl + name: pillow + version: 12.3.0 + sha256: e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0 + requires_dist: + - furo ; extra == 'docs' + - olefile ; extra == 'docs' + - sphinx>=8.2 ; extra == 'docs' + - sphinx-autobuild ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinx-inline-tabs ; extra == 'docs' + - sphinxext-opengraph ; extra == 'docs' + - olefile ; extra == 'fpx' + - olefile ; extra == 'mic' + - arro3-compute ; extra == 'test-arrow' + - arro3-core ; extra == 'test-arrow' + - nanoarrow ; extra == 'test-arrow' + - pyarrow ; extra == 'test-arrow' + - coverage>=7.4.2 ; extra == 'tests' + - defusedxml ; extra == 'tests' + - markdown2 ; extra == 'tests' + - olefile ; extra == 'tests' + - packaging ; extra == 'tests' + - pytest ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - pytest-timeout ; extra == 'tests' + - pytest-xdist ; extra == 'tests' + - setuptools ; extra == 'tests' + - trove-classifiers>=2024.10.12 ; extra == 'tests' + - defusedxml ; extra == 'xmp' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/c8/30/cb0eec647afea94c1d95bed3c0014a96565404e4225dba2c0c63bbdd6b9a/simpleitk-2.5.6-cp311-abi3-macosx_10_9_x86_64.whl + name: simpleitk + version: 2.5.6 + sha256: 36658792fe2a62814cbfedb3b236ac722ca7e00953241726bc4a3a26cc7ef5a7 +- pypi: https://files.pythonhosted.org/packages/c9/54/777e0495acd4fb008791e84889be33d6e7fc8af095b441d939390b7d2491/pywavelets-1.9.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + name: pywavelets + version: 1.9.0 + sha256: 4ee1ee7d80f88c64b8ec3b5021dd1e94545cc97f0cd479fb51aa7b10f6def08e + requires_dist: + - numpy>=1.25,<3 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl + name: fonttools + version: 4.63.0 + sha256: 6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03 + requires_dist: + - lxml>=4.0 ; extra == 'lxml' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'woff' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' + - zopfli>=0.1.4 ; extra == 'woff' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'unicode' + - lz4>=1.7.4.2 ; extra == 'graphite' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'interpolatable' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'interpolatable' + - pycairo ; extra == 'interpolatable' + - matplotlib ; extra == 'plot' + - sympy ; extra == 'symfont' + - xattr ; sys_platform == 'darwin' and extra == 'type1' + - skia-pathops>=0.5.0 ; extra == 'pathops' + - uharfbuzz>=0.45.0 ; extra == 'repacker' + - lxml>=4.0 ; extra == 'all' + - brotli>=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'all' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'all' + - zopfli>=0.1.4 ; extra == 'all' + - unicodedata2>=17.0.0 ; python_full_version < '3.15' and extra == 'all' + - lz4>=1.7.4.2 ; extra == 'all' + - scipy ; platform_python_implementation != 'PyPy' and extra == 'all' + - munkres ; platform_python_implementation == 'PyPy' and extra == 'all' + - pycairo ; extra == 'all' + - matplotlib ; extra == 'all' + - sympy ; extra == 'all' + - xattr ; sys_platform == 'darwin' and extra == 'all' + - skia-pathops>=0.5.0 ; extra == 'all' + - uharfbuzz>=0.45.0 ; extra == 'all' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/cf/4c/c73f828fdbcd37eaf21d08fa852544a3ca7c2dbb3ea76873d64f2ea413d1/opencv_python-5.0.0.93-cp37-abi3-manylinux_2_28_x86_64.whl + name: opencv-python + version: 5.0.0.93 + sha256: c8de2dec111122a02e8beb28e16c31904992dfd6186560b142a92c71403c1039 + requires_dist: + - numpy<2.0 ; python_full_version < '3.9' + - numpy>=2 ; python_full_version >= '3.9' + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl + name: multidict + version: 6.7.1 + sha256: a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2 + requires_dist: + - typing-extensions>=4.1.0 ; python_full_version < '3.11' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/d5/b7/1da684a04175473fa4cddbf9a2f572e79514c3fd27a74597f43057d4f3da/aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: aiohttp + version: 3.14.3 + sha256: 18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147 + requires_dist: + - aiohappyeyeballs>=2.5.0 + - aiosignal>=1.4.0 + - async-timeout>=4.0,<6.0 ; python_full_version < '3.11' + - attrs>=17.3.0 + - frozenlist>=1.1.1 + - multidict>=4.5,<7.0 + - propcache>=0.2.0 + - typing-extensions>=4.4 ; python_full_version < '3.13' + - yarl>=1.17.0,<2.0 + - aiodns>=3.3.0 ; sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotli>=1.2 ; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + - brotlicffi>=1.2 ; platform_python_implementation != 'CPython' and extra == 'speedups' + - backports-zstd ; python_full_version < '3.14' and platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios' and extra == 'speedups' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/d7/88/b72def7262e150d16be13fca37a96481138d624e700340bc3362a7588929/scipy-1.18.0-cp314-cp314-macosx_12_0_arm64.whl + name: scipy + version: 1.18.0 + sha256: 2ef3abc54a4ffc53765374b0d5728532dfdd2585ed23f6b11c206a1f0b1b9af8 + requires_dist: + - numpy>=2.0.0,<2.8 + - pytest>=8.0.0 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-xdist ; extra == 'test' + - asv ; extra == 'test' + - mpmath ; extra == 'test' + - gmpy2 ; extra == 'test' + - threadpoolctl ; extra == 'test' + - scikit-umfpack ; extra == 'test' + - pooch ; extra == 'test' + - hypothesis>=6.30 ; extra == 'test' + - array-api-strict>=2.3.1 ; extra == 'test' + - cython ; extra == 'test' + - meson ; extra == 'test' + - ninja ; sys_platform != 'emscripten' and extra == 'test' + - scipy-doctest>=2.0.0 ; extra == 'test' + - sphinx>=5.0.0,<8.2.0 ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - pydata-sphinx-theme>=0.15.2 ; extra == 'doc' + - sphinx-copybutton ; extra == 'doc' + - sphinx-design>=0.4.0 ; extra == 'doc' + - matplotlib>=3.5 ; extra == 'doc' + - numpydoc ; extra == 'doc' + - jupytext ; extra == 'doc' + - myst-nb>=1.2.0 ; extra == 'doc' + - pooch ; extra == 'doc' + - jupyterlite-sphinx>=0.19.1 ; extra == 'doc' + - jupyterlite-pyodide-kernel ; extra == 'doc' + - linkify-it-py ; extra == 'doc' + - tabulate ; extra == 'doc' + - click<8.3.0 ; extra == 'dev' + - spin ; extra == 'dev' + - mypy==1.19.1 ; extra == 'dev' + - pyrefly==0.63.0 ; extra == 'dev' + - typing-extensions ; extra == 'dev' + - types-psutil ; extra == 'dev' + - pycodestyle ; extra == 'dev' + - ruff>=0.12.0 ; extra == 'dev' + - cython-lint>=0.12.2 ; extra == 'dev' + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/da/ed/75bf4d6ae6fec7233ef466f27dffc99f91fde53a31e69f02640b418317ec/tifffile-2026.7.31-py3-none-any.whl + name: tifffile + version: 2026.7.31 + sha256: 81adfa08012be1c478f99b83cda2f529eef8620cfbdf94fc41eef6f1d7b47dc5 + requires_dist: + - numpy>=2.1 + - imagecodecs>=2026.5.10 ; extra == 'codecs' + - lxml ; extra == 'xml' + - zarr>=3.2.0 ; extra == 'zarr' + - fsspec ; extra == 'zarr' + - kerchunk ; extra == 'zarr' + - matplotlib ; extra == 'plot' + - imagecodecs>=2026.5.10 ; extra == 'all' + - matplotlib ; extra == 'all' + - lxml ; extra == 'all' + - zarr>=3.2.0 ; extra == 'all' + - xarray ; extra == 'all' + - fsspec ; extra == 'all' + - kerchunk ; extra == 'all' + - cmapfile ; extra == 'test' + - czifile ; extra == 'test' + - dask ; extra == 'test' + - fsspec ; extra == 'test' + - imagecodecs ; extra == 'test' + - kerchunk ; extra == 'test' + - lfdfiles ; extra == 'test' + - lxml ; extra == 'test' + - ndtiff ; extra == 'test' + - oiffile ; extra == 'test' + - psdtags ; extra == 'test' + - pytest ; extra == 'test' + - requests ; extra == 'test' + - roifile ; extra == 'test' + - xarray ; extra == 'test' + - zarr>=3.2.0 ; extra == 'test' + requires_python: '>=3.12' +- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl + name: cycler + version: 0.12.1 + sha256: 85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 + requires_dist: + - ipython ; extra == 'docs' + - matplotlib ; extra == 'docs' + - numpydoc ; extra == 'docs' + - sphinx ; extra == 'docs' + - pytest ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - pytest-xdist ; extra == 'tests' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + name: kiwisolver + version: 1.5.0 + sha256: 80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/eb/e1/1c92ac6b538ef5388caf1a74af61cf6af16ea6d14115bb53357469cb38d6/pywavelets-1.9.0-cp314-cp314-macosx_11_0_arm64.whl + name: pywavelets + version: 1.9.0 + sha256: 56bc36b42b1b125fd9cb56e7956b22f8d0f83c1093f49c77fc042135e588c799 + requires_dist: + - numpy>=1.25,<3 + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl + name: python-dateutil + version: 2.9.0.post0 + sha256: a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 + requires_dist: + - six>=1.5 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- pypi: https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl + name: multidict + version: 6.7.1 + sha256: 0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1 + requires_dist: + - typing-extensions>=4.1.0 ; python_full_version < '3.11' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + name: pygments + version: 2.20.0 + sha256: 81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176 + requires_dist: + - colorama>=0.4.6 ; extra == 'windows-terminal' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/f4/ec/301532fb2003e6557e6a12106eb1df572ed6f74c08c05c2e7a8913353383/simpleitk-2.5.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + name: simpleitk + version: 2.5.6 + sha256: 99242c333ed17138134e9749f3a484518f41baebab0fc0f0fe7c657ab8090c07 +- pypi: https://files.pythonhosted.org/packages/f6/46/e38a15232d468dbe949e615fac303d4015c59c490b11b5e3d4545f2028a1/med_imagetools-2.16.0-py3-none-any.whl + name: med-imagetools + version: 2.16.0 + sha256: a3411441c95b7c7fd1d03959529e10c32dba0aacc5d328929f40410942cae089 + requires_dist: + - click>=8.1,<9 + - dill>=0.3.8,<1 + - dpath>=2.2.0 + - fasteners==0.19 + - highdicom + - joblib>=1.4.2,<2 + - matplotlib>=3.8.4,<4 + - numpy<3 + - pandas<=3.0.2 + - pydantic-settings>=2.8.1,<3 + - pydicom>=2.4.4 + - pytz>=2026.1.post1,<2027 + - pyyaml>=6.0,<7 + - rich>=13.9.4 + - scikit-image>=0.23.2,<1 + - simpleitk>=2.4.0,<3 + - structlog>=25.0,<26 + - tqdm>=4.66.4,<5 + - aiohttp>=3.8.1 ; extra == 'all' + - pygithub>=2.5.0 ; extra == 'all' + - pyvis>=0.3.2,<0.4 ; extra == 'all' + - aiohttp>=3.8.1 ; extra == 'datasets' + - pygithub>=2.5.0 ; extra == 'datasets' + - pyvis>=0.3.2,<0.4 ; extra == 'pyvis' + requires_python: '>=3.10,<4' +- pypi: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl + name: tqdm + version: 4.70.0 + sha256: 7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953 + requires_dist: + - colorama ; sys_platform == 'win32' + - requests ; extra == 'discord' + - envwrap ; extra == 'discord' + - slack-sdk ; extra == 'slack' + - envwrap ; extra == 'slack' + - requests ; extra == 'telegram' + - envwrap ; extra == 'telegram' + - ipywidgets>=6 ; extra == 'notebook' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl + name: aiosignal + version: 1.4.0 + sha256: 053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e + requires_dist: + - frozenlist>=1.1.0 + - typing-extensions>=4.2 ; python_full_version < '3.13' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl + name: click + version: 8.4.2 + sha256: e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76 + requires_dist: + - colorama ; sys_platform == 'win32' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl + name: pydantic + version: 2.13.4 + sha256: 45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba + requires_dist: + - annotated-types>=0.6.0 + - pydantic-core==2.46.4 + - typing-extensions>=4.14.1 + - typing-inspection>=0.4.2 + - email-validator>=2.0.0 ; extra == 'email' + - tzdata ; python_full_version >= '3.9' and sys_platform == 'win32' and extra == 'timezone' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl + name: contourpy + version: 1.3.3 + sha256: cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77 + requires_dist: + - numpy>=1.25 + - furo ; extra == 'docs' + - sphinx>=7.2 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - bokeh ; extra == 'bokeh' + - selenium ; extra == 'bokeh' + - contourpy[bokeh,docs] ; extra == 'mypy' + - bokeh ; extra == 'mypy' + - docutils-stubs ; extra == 'mypy' + - mypy==1.17.0 ; extra == 'mypy' + - types-pillow ; extra == 'mypy' + - contourpy[test-no-images] ; extra == 'test' + - matplotlib ; extra == 'test' + - pillow ; extra == 'test' + - pytest ; extra == 'test-no-images' + - pytest-cov ; extra == 'test-no-images' + - pytest-rerunfailures ; extra == 'test-no-images' + - pytest-xdist ; extra == 'test-no-images' + - wurlitzer ; extra == 'test-no-images' + requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: multidict + version: 6.7.1 + sha256: 7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709 + requires_dist: + - typing-extensions>=4.1.0 ; python_full_version < '3.11' + requires_python: '>=3.9' diff --git a/pixi.toml b/pixi.toml deleted file mode 100644 index 1a4b5ee..0000000 --- a/pixi.toml +++ /dev/null @@ -1,14 +0,0 @@ -[workspace] -authors = ["Joshua Siraj "] -channels = ["conda-forge"] -name = "ab_testing" -platforms = ["linux-64"] -version = "0.1.0" - -[tasks] - -[dependencies] -python = ">=3.11,<3.14" - -[pypi-dependencies] -pydantic = ">=2.13.4, <3" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ed7c2c0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,42 @@ +[project] +authors = [{name = "Joshua Siraj", email = "joshua.siraj@ryerson.ca"}, {name = "Katy Scott", email = "bhklab.katyscott@gmail.com"}] +dependencies = [ + "simpleitk>=2.5.6,<3", + "pydantic>=2.13.4,<3", + "damply>=0.26.1,<0.27", + "med-imagetools>=2.16.0,<3", + "connected-components-3d>=4.0.0,<5", + "opencv-python>=5.0.0.93,<6", + "nibabel>=5.4.2,<6", + "readii", + "click>=8.4.2,<9", +] +name = "ab-testing" +requires-python = ">= 3.11" +version = "0.1.0" + +[build-system] +build-backend = "hatchling.build" +requires = ["hatchling"] + +[tool.pixi.workspace] +channels = ["conda-forge"] +platforms = ["linux-64", "osx-64", "osx-arm64"] + +[tool.pixi.pypi-dependencies] +ab_testing = { path = ".", editable = true } + +[tool.pixi.activation] +# convenient variables which can be used in scripts +env.CONFIG = "${PIXI_PROJECT_ROOT}/config" +env.METADATA = "${PIXI_PROJECT_ROOT}/metadata" +env.LOGS = "${PIXI_PROJECT_ROOT}/logs" +env.RAWDATA = "${PIXI_PROJECT_ROOT}/data/rawdata" +env.PROCDATA = "${PIXI_PROJECT_ROOT}/data/procdata" +env.RESULTS = "${PIXI_PROJECT_ROOT}/data/results" +env.SCRIPTS = "${PIXI_PROJECT_ROOT}/workflow/scripts" + +[tool.pixi.tasks] + +[tool.pixi.environments.qc.dependencies] +ruff = ">=0.16.2,<0.17" diff --git a/ruff.toml b/ruff.toml index 97a67b4..b19e1d0 100644 --- a/ruff.toml +++ b/ruff.toml @@ -73,8 +73,8 @@ ignore = [ "D100", # Allows modules without docstrings # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "COM812", # Avoids conflict with Ruff formatter trailing comma rules - "D206" - # Allows docstrings to be formatted flexibly + "D206", # Allows docstrings to be formatted flexibly + "N813", # Allows for Camelcase to lowercase imports ] # https://docs.astral.sh/ruff/settings/#isort diff --git a/sandbox/recist_comparison.py b/sandbox/recist_comparison.py new file mode 100644 index 0000000..00e3bb3 --- /dev/null +++ b/sandbox/recist_comparison.py @@ -0,0 +1,64 @@ +# Script to compare the calculation of a RECIST longest diameter from a 3D tumour segmentation mask. +# Compared method from MedSAM2 implementation and BHKLab implementation by Kaitlyn Kobayashi. + +import cv2 +import matplotlib as mpl +import matplotlib.colors as mcolors +import matplotlib.pyplot as plt +import numpy as np +from damply import dirs +from readii.image_processing import displayCTSegOverlay + +from ab_testing.utils.annotations import get_line_from_recist, get_recist_pts +from ab_testing.utils.conver_nifti_to_recist_npz import ( + compute_recist_line, + generate_recist, + read_case, +) + +cool_cmap = mpl.colormaps['cool'] +binary_magenta = mcolors.ListedColormap([(0,0,0,0.1), cool_cmap(400)]) + +sample_scan = "LUNG1-012_0011/CT_55636694" +sample_mask = "LUNG1-012_0011/RTSTRUCT_38424583" + +sample_id = sample_scan.split("/", maxsplit=1)[0] + +scan_path = dirs.RAWDATA / "TCIA_NSCLC-Radiomics/images/mit_NSCLC-Radiomics" / f"{sample_scan}" / "CT.nii.gz" +mask_path = dirs.RAWDATA / "TCIA_NSCLC-Radiomics/images/mit_NSCLC-Radiomics" / f"{sample_mask}" / "GTV.nii.gz" + +scan, mask, spacing, direction, origin, reader = read_case(scan_path, mask_path) + +key_slice = int(np.argmax(np.sum(mask, axis=(1, 2)))) + +r_fig, r_ax = plt.subplots(1,3, figsize=(21,8.5), layout='tight') +plt.suptitle(f'RECIST line comparison for NSCLC-Radiomics {sample_id}') + +# MedSAM2 method +p1, p2 = compute_recist_line(mask[key_slice]) +m_recist_line, short_ids = generate_recist(mask, spacing) + +displayCTSegOverlay(scan, mask, sliceIdx=key_slice, dispMin=-1350, dispMax=150, ax=r_ax[0], alpha=0.3) +r_ax[0].imshow(m_recist_line[key_slice], cmap=binary_magenta, alpha=0.7) +r_ax[0].set_title(f"MedSAM2 \n Coordinates: p1={p1}, p2={p2}") + +# Kaitlyn's method +recist_pts = get_recist_pts(mask[key_slice]) +k_recist_line = get_line_from_recist(recist_pts, key_slice, mask.shape) +f_k_pts = f"Coordinates: p1=[{recist_pts[2]:.2f} {recist_pts[3]:.2f}], p2=[{recist_pts[0]:.2f} {recist_pts[1]:.2f}]" + +displayCTSegOverlay(scan, mask, sliceIdx=key_slice, dispMin=-1350, dispMax=150, ax=r_ax[1], alpha=0.3) +r_ax[1].imshow(k_recist_line[key_slice], cmap=binary_magenta, alpha=0.7) +r_ax[1].set_title(f"BHKLab \n {f_k_pts}") + +# Draw line like MedSAM method with Kaitlyn's coordinates +k_thick_line = np.zeros_like(mask, dtype=np.uint16) +cv2.line(k_thick_line[key_slice], (int(recist_pts[0]), int(recist_pts[1])), (int(recist_pts[2]), int(recist_pts[3])), + color=1, thickness=2) +f_kt_pts = f"Coordinates: p1=[{int(recist_pts[2])} {int(recist_pts[3])}], p2=[{int(recist_pts[0])} {int(recist_pts[1])}]" + +displayCTSegOverlay(scan, mask, sliceIdx=key_slice, dispMin=-1350, dispMax=150, ax=r_ax[2], alpha=0.3) +r_ax[2].imshow(k_thick_line[key_slice], cmap=binary_magenta, alpha=0.7) +r_ax[2].set_title(f"BHKLab drawn like MedSAM2 \n {f_kt_pts}") + +r_fig.savefig(dirs.RESULTS / f"recist_comparison_{sample_id}.png") \ No newline at end of file diff --git a/src/ab_testing/__init__.py b/src/ab_testing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/contract.py b/src/ab_testing/contract.py similarity index 62% rename from contract.py rename to src/ab_testing/contract.py index 1e50a33..ab646cf 100644 --- a/contract.py +++ b/src/ab_testing/contract.py @@ -1,6 +1,7 @@ from pydantic import BaseModel -from input import SUPPORTED_INPUT_TYPES -from output import SUPPORTED_OUTPUT_TYPES + +from ab_testing.input import SUPPORTED_INPUT_TYPES +from ab_testing.output import SUPPORTED_OUTPUT_TYPES class ModelContract(BaseModel): diff --git a/input.py b/src/ab_testing/input.py similarity index 84% rename from input.py rename to src/ab_testing/input.py index 29fa7de..333dab5 100644 --- a/input.py +++ b/src/ab_testing/input.py @@ -1,4 +1,3 @@ -from tarfile import SUPPORTED_TYPES from pydantic import BaseModel diff --git a/models/medsam2/medsam.def b/src/ab_testing/models/medsam2/medsam.def similarity index 100% rename from models/medsam2/medsam.def rename to src/ab_testing/models/medsam2/medsam.def diff --git a/src/ab_testing/models/medsam2/prepare.py b/src/ab_testing/models/medsam2/prepare.py new file mode 100644 index 0000000..dfa392a --- /dev/null +++ b/src/ab_testing/models/medsam2/prepare.py @@ -0,0 +1,141 @@ +import logging +from pathlib import Path + +import click +from damply import dirs + +from ab_testing.utils.conver_nifti_to_recist_npz import ( + MIN_LABEL_SLICES, + MIN_RECIST_MM, + run_dataset, +) + +logfile = dirs.LOGS / "models" / "prepare_medsam2.log" +logfile.parent.mkdir(parents=True, exist_ok=True) + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + filename=logfile +) + +logger = logging.getLogger(__name__) + +ANATOMICAL_BUCKETS = [ + "lung", + "soft_tissue", # includes heart + "bone", + "brain", +] + +@click.command(no_args_is_help=True) +@click.argument( + "dataset", + type=str, +) +@click.argument( + "mit_directory", + type=click.Path( + file_okay=False, dir_okay=True, writable=False, path_type=Path, resolve_path=True, exists=True + ), +) +@click.argument( + "output_directory", + type=click.Path( + file_okay=False, dir_okay=True, writable=True, path_type=Path, resolve_path=True + ), +) +@click.option( + "--anat-window", + type=click.Choice(ANATOMICAL_BUCKETS), + required=True, + help=f"Anatomical windowing to apply for this dataset. Must be one of {ANATOMICAL_BUCKETS}." +) +@click.option( + "--min-slices", + type=int, + default=MIN_LABEL_SLICES, + show_default=True, + help="Minimum labelled slice count required for npz conversion." +) +@click.option( + "--min-recist-mm", + type=float, + default=MIN_RECIST_MM, + show_default=True, + help="Minimum RECIST diameter measurement required for npz conversion in millimetres (mm)." +) +@click.option( + "--workers", + type=int, + default=24, + help="Number of parallel processes to use." +) +@click.option( + "--overwrite", + is_flag=True, + help="Whether to overwrite existing files." +) +def prepare_data( + dataset: str, + mit_directory: str | Path, + output_directory: str | Path, + anat_window: str, + *, + min_slices: int = MIN_LABEL_SLICES, + min_recist_mm: float = MIN_RECIST_MM, + workers: int = 24, + overwrite: bool = False, + ) -> int: + """Process a med-imagetools nifti dataset by pair of image-masks and save into npzs. + + Converted npz contains: + * imgs: The image, windowed based on the anatomical window specified, + * gts: The corresponding 3D segmentation mask, + * spacing: Original image/mask spacing, from SimpleITK + * direction: Original image/mask direction, from SimpleITK + * origin: Original image/mask origin, from SimpleTIK + * reader: What library was used to load in the image/mask, will be sitk or nibabel_orthofix + * recist: Reverse-engineered RECIST longest diameter annotation derived from gts + + Based on min_slices and min_recist_mm, samples will be pruned and not saved as npz if they fall below the threshold. + + Args: + dataset: str, dataset name + mit_directory: str | Path, pathway to the image and mask directory + output_directory: str | Path, output directory npz files will be saved to + anat_window: anatomical windowing to apply for this dataset + min_slices: int, minimum number of axial slices with label for lesion inclusion (default 5) + min_recist_mm: float, RECIST diameter threshold in millimetres for lesion inclusion (default 10) + workers: int, number of parallel processes to use (default 24) + overwrite: bool, whether to reconvert every case (default False, skip existing npz) + + Returns: + 0 if successful, 1 if errors occurred. + """ + written, skipped, filtered, errors, dropped_lesions, _z_kept, _z_total = run_dataset( + ds = dataset, + root = Path(mit_directory), + out_root = Path(output_directory), + workers = workers, + with_recist = True, + overwrite = overwrite, + min_slices = min_slices, + min_recist_mm = min_recist_mm, + prune_filtered = True, + anat_window = anat_window, + pair_builder = 'mit', + ) + + logger.info(f"\nTOTAL written={written} skipped={skipped} " + f"filtered={filtered} errors={errors} " + f"small_lesions_dropped={dropped_lesions}") + + return 1 if errors else 0 + + + + + +if __name__ == "__main__": + prepare_data() diff --git a/output.py b/src/ab_testing/output.py similarity index 100% rename from output.py rename to src/ab_testing/output.py diff --git a/src/ab_testing/utils/annotations.py b/src/ab_testing/utils/annotations.py new file mode 100644 index 0000000..47b8743 --- /dev/null +++ b/src/ab_testing/utils/annotations.py @@ -0,0 +1,83 @@ + +import numpy as np +from skimage.draw import line +from skimage.measure import regionprops + + +def get_slice_properties(mask_slice: np.ndarray) -> tuple[float, float, float, float, float]: + """Utility function for prompt generation function to get properties of a given mask slice.""" + try: + props = regionprops(mask_slice)[0] + y_cent, x_cent = props.centroid + orientation = props.orientation + semi_maj_axis_len = props.axis_major_length / 2 + except Exception as e: + # Usually errors will arise here if there is an issue with region props calculation and the mask being too small to calculate anything from. + message = f'error {e} and sum of mask slice is {mask_slice.sum()}' + raise Exception(message) from e + + return x_cent, y_cent, orientation, semi_maj_axis_len + + +def get_recist_pts(mask_slice: np.ndarray) -> np.ndarray: + """Get the coordinates of the endpoints of the an automatically generated RECIST line in a mask array. + + Parameters + ---------- + mask_slice: np.ndarray[int, int] + The ground truth segmentation at the largest area slice. Expects (z, x, y) format. + + Returns + ------- + recist_pts: np.ndarray[float, float, float, float] + Holds the information for the found RERECIST line in the form [x_r1, y_r1, x_r2, y_r2] + """ + x_cent, y_cent, orientation, semi_maj_axis_len = get_slice_properties(mask_slice) + + x_r1 = x_cent - np.sin(orientation) * semi_maj_axis_len + y_r1 = y_cent - np.cos(orientation) * semi_maj_axis_len + + x_r2 = x_cent + np.sin(orientation) * semi_maj_axis_len + y_r2 = y_cent + np.cos(orientation) * semi_maj_axis_len + + recist_pts = np.array([x_r1, y_r1, x_r2, y_r2]) + + return recist_pts + + +def get_line_from_recist( + recist_pts: np.ndarray, + slice_idx: int, + scan_size: np.ndarray +) -> np.ndarray: + ''' + From the RECIST measurement coordinates, generate a line connecting both coordinates on the correct slice and return an np.ndarray the same shape as the image. + Output to be compatible with the ['recist'] array of the .npz files needed for MedSAM2-RECIST. + + Parameters + ---------- + recist_pts: array + A list of coordinates in [x1, y1, x2, y2] format that defines the RECIST measurement + slice_idx: int + The slice that the measurement was taken on + scan_size: np.array + The x, y, and z size of the image in [z_space, x_space, y_space] format + + Returns + ---------- + recist_arr: np.ndarray + A binary array of the same shape as the image with the pixels of the line = 1 + ''' + # Generate an array in the same size as the image filled with all zeros + recist_arr = np.zeros(scan_size) + + # Round the coordinate values to their nearest integers + coords_round = np.rint(recist_pts).astype(int) + + # Draw line using coordinates + rr, cc = line(coords_round[0], coords_round[1], coords_round[2], coords_round[3]) + + # Put line into the correct slice in the RECIST array of all zeros + recist_arr[slice_idx][cc, rr] = 1 + + return recist_arr diff --git a/src/ab_testing/utils/conver_nifti_to_recist_npz.py b/src/ab_testing/utils/conver_nifti_to_recist_npz.py new file mode 100644 index 0000000..1c5b29a --- /dev/null +++ b/src/ab_testing/utils/conver_nifti_to_recist_npz.py @@ -0,0 +1,814 @@ +#!/usr/bin/env python3 +"""Self-contained single-file NIfTI -> RECIST NPZ converter (resumable). + +Converts nifti cancer datasets to per-case npz. Each +dataset is windowed by its anatomical region (location-based windowing), then +per-lesion RECIST longest-diameter lines are computed. Runs are resumable: +cases whose npz already exists and opens cleanly (with the expected keys) are +skipped, so an interrupted run can simply be re-launched. Use --overwrite to +force every case to be rewritten. + +Each npz is written to a temp file and atomically renamed into place, so a +killed run never leaves a truncated npz that would be mistaken for done. + +Lesions whose RECIST longest diameter is shorter than MIN_RECIST_MM (10 mm, in +physical units from the image spacing) are excluded from BOTH 'gts' and +'recist' -- they are not sub-threshold segmentation targets without a prompt, +they are gone. On by default; disable with --no-exclude-small-lesions. Surviving +lesions keep their original cc3d ids, so ids may be non-contiguous. + +--tumor-slices-only (off by default) crops every array along Z to the tumor +ROI: the contiguous span of axial slices holding label, optionally padded by +--tumor-slice-margin. This is the big size lever. The span is contiguous rather +than the exact set of labeled slices, so the result stays a real volume with a +meaningful z spacing; 'origin' is shifted to the new first slice so the npz is +still geometrically correct, and 'z_crop' records [z_start, z_stop) in the +original volume. + +Whole-body datasets (Dataset011_WholeBody, Dataset5310) are intentionally NOT +included -- they are multi-region per case and need per-lesion bucketing. + +Per-case NPZ contract: + imgs float16 (Z, Y, X) CT windowed to [0, 255.0] + gts uint16 (Z, Y, X) cc3d 26-connectivity instance labels + recist uint16 (Z, Y, X) per-lesion longest-diameter line, value == lesion id + spacing float64 (3,) sitk GetSpacing (x, y, z) + direction float64 (9,) sitk GetDirection + origin float64 (3,) sitk GetOrigin (of slice z_crop[0] when cropped) + reader str 'sitk' | 'nibabel_orthofix' + z_crop int64 (2,) [z_start, z_stop) kept; only with --tumor-slices-only +(--no-recist skips the RECIST computation and omits the 'recist' key.) + +Usage: + python conver_nifti_to_recist_npz.py --all + python conver_nifti_to_recist_npz.py --dataset Dataset003_LungCancer + python conver_nifti_to_recist_npz.py --all --workers 8 + python conver_nifti_to_recist_npz.py --all --no-recist # imgs/gts only + python conver_nifti_to_recist_npz.py --all --overwrite # ignore existing npz + python conver_nifti_to_recist_npz.py --all --min-label-slices 0 # keep every case + python conver_nifti_to_recist_npz.py --all --prune-filtered # delete npz now filtered out + python conver_nifti_to_recist_npz.py --all --no-exclude-small-lesions # keep <10mm lesions + python conver_nifti_to_recist_npz.py --all --tumor-slices-only # crop Z to the tumor ROI + python conver_nifti_to_recist_npz.py --all --tumor-slices-only --tumor-slice-margin 5 + +ab_testing notes: + - img == scan + - lbl == mask + +""" +from __future__ import annotations + +import argparse +import itertools +import os +import sys +import tempfile +import zipfile +from concurrent.futures import ProcessPoolExecutor, as_completed +from pathlib import Path +from typing import Any + +import cc3d +import cv2 +import nibabel as nib +import numpy as np +import pandas as pd +import SimpleITK as sitk +from scipy.spatial.distance import pdist, squareform + +# We parallelize across cases with ProcessPoolExecutor; disable OpenCV's own +# internal thread pool so N workers don't oversubscribe cores (and to silence +# "Can't spawn new thread" (EAGAIN) on thread-capped login/compute nodes). +cv2.setNumThreads(0) + +# ─── Constants ─────────────────────────────────────────────────────────────── + +MIN_LABEL_SLICES = 5 # exclude the case if the label spans fewer axial slices +MIN_RECIST_MM = 10.0 # drop lesions whose RECIST longest diameter is shorter (mm) +RECIST_LINE_THICKNESS = 2 # cv2.line thickness +MAX_CONTOUR_PTS = 500 # subsample cap before the O(n^2) pairwise distance +IMG_SUFFIX = "_0000.nii.gz" +ROOT_DEFAULT = "train_per_cancer_type" +MIN_POINT_COUNT = 2 + +# The 4 anatomical window buckets (level / width in HU). +WINDOW_BUCKET: dict[str, dict[str, int]] = { + "lung": {"level": -600, "width": 1500}, + "soft_tissue": {"level": 40, "width": 400}, # includes heart + "bone": {"level": 400, "width": 1800}, + "brain": {"level": 40, "width": 80}, +} + +# dataset -> window bucket (location-based). Whole-body 011 / 5310 excluded. +DATASET_WINDOW: dict[str, str] = { + "Dataset002_EsophagusCancer": "soft_tissue", + "Dataset003_LungCancer": "lung", + "Dataset004_LiverCancer": "soft_tissue", + "Dataset005_AdrenalCancer": "soft_tissue", + "Dataset006_PancreaticCancer": "soft_tissue", + "Dataset007_KidneyCancer": "soft_tissue", + "Dataset008_LymphNodes": "soft_tissue", + "Dataset009_ColonCancer": "soft_tissue", + "Dataset010_EndometrialCancer": "soft_tissue" +} + + +# ─── CT windowing ───────────────────────────────────────────────────────────── + +def ct_window( + data: np.ndarray, + level: int, + width: int +) -> np.ndarray: + """Apply windowing to CT HU data and then standardize to [0, 255.0] float16. + Args: + data: (Z, Y, X) float32 CT array in Hounsfield units + level: window level (center) + width: window width + + Returns: + Standardized image with values between [0, 255.0], windowed based on level and width inputs. + """ + lo = level - width / 2 + hi = level + width / 2 + data = np.clip(data, lo, hi) + return ((data - lo) / (hi - lo) * 255.0).astype(np.float16) + + +# ─── NIfTI reading (sitk, with a nibabel fallback for non-orthonormal sforms) ── + +def _orthogonalize(direction: np.ndarray) -> np.ndarray: + u, _, vt = np.linalg.svd(direction) + return u @ vt + + +def _meta_from_affine(affine: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + matrix = np.asarray(affine[:3, :3], dtype=np.float64) + spacing = np.linalg.norm(matrix, axis=0) + if np.any(spacing == 0): + message = "NIfTI affine has a zero-length spatial axis" + raise RuntimeError(message) + direction = _orthogonalize(matrix / spacing) + origin = np.asarray(affine[:3, 3], dtype=np.float64) + return spacing, direction.reshape(-1), origin + + +def read_case( + img_path: str | Path, + lbl_path: str | Path +) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, str]: + """Read scan (CT) and segmentation mask from nifti and return as (Z,Y,X) numpy arrays, where Z is slices. Fall back to nibabel for sforms ITK rejects. + Args: + img_path: path to the image file + lbl_path: path to the label file + Returns: + ct: (Z,Y,X) float32 CT array + lbl: (Z,Y,X) uint8 label array + spacing: (3,) float64 image spacing from sitk.GetSpacing (x,y,z) + direction: (9,) float64 image direction from sitk.GetDirection + origin: (3,) float64 image origin from sitk.GetOrigin + reader: str, which reader was used to load the image and label, either 'sitk' or 'nibabel_orthofix' + """ + try: + img = sitk.ReadImage(str(img_path)) + ct = sitk.GetArrayFromImage(img).astype(np.float32) + lbl = sitk.GetArrayFromImage(sitk.ReadImage(str(lbl_path))) + return (ct, lbl, np.array(img.GetSpacing()), np.array(img.GetDirection()), + np.array(img.GetOrigin()), "sitk") + except RuntimeError as exc: + if "orthonormal direction cosines" not in str(exc): + raise + img_nib = nib.load(str(img_path)) + lbl_nib = nib.load(str(lbl_path)) + ct = np.asanyarray(img_nib.dataobj).astype(np.float32).transpose(2, 1, 0) + lbl = np.asanyarray(lbl_nib.dataobj).transpose(2, 1, 0) + spacing, direction, origin = _meta_from_affine(np.asarray(img_nib.affine)) + return ct, lbl, spacing, direction, origin, "nibabel_orthofix" + + +# ─── Label extent filter ─────────────────────────────────────────────────────── + +def count_label_slices(lbl_path: str | Path) -> int: + """Number of axial slices containing any foreground label. + + Read with nibabel and counted on the *last* array axis, which is the axis + read_case transposes to front as Z -- so this matches the pipeline's notion + of a slice without needing the CT (the expensive read) at all. + """ + lbl = np.asanyarray(nib.load(str(lbl_path)).dataobj) + return int(np.count_nonzero(np.any(lbl > 0, axis=(0, 1)))) + + +# ─── RECIST longest-diameter line ───────────────────────────────────────────── + +def compute_recist_line(mask_2d: np.ndarray) -> tuple[np.ndarray, np.ndarray] | None: + """Farthest pair of external-contour pixels on a 2D lesion slice (clinical LD). + + Args: + mask_2d: 2D uint8 binary mask of a single lesion on a single axial slice + + Returns: + p1, p2: (2,) int32 pixel coordinates of the endpoints of the longest-diameter line, in (col, row) order + None: if the mask is degenerate (no contour or a single pixel) + """ + contours, _ = cv2.findContours( + mask_2d.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE + ) + if not contours: + return None + pts = np.vstack(contours).squeeze() + # Fail if points are not 2 dimensional (x,y) or the number of points is less than MIN_POINT_COUNT (default 2) + if pts.ndim != 2 or len(pts) < MIN_POINT_COUNT: # noqa + return None + if len(pts) > MAX_CONTOUR_PTS: + pts = pts[np.linspace(0, len(pts) - 1, MAX_CONTOUR_PTS, dtype=int)] + dist = squareform(pdist(pts)) + i, j = np.unravel_index(np.argmax(dist), dist.shape) + return pts[i].astype(int), pts[j].astype(int) + + +def recist_length_mm( + p1: np.ndarray, + p2: np.ndarray, + spacing: np.ndarray +) -> float: + """Physical length of an in-plane RECIST line. + + Contour points are cv2 (col, row) == (X, Y) on an axial slice; `spacing` is + sitk order (x, y, z), so component 0 scales the column delta and component 1 + the row delta. The line is in-plane, so z spacing never enters. + + Args: + p1: (2,) int32 pixel coordinates of one endpoint of the RECIST line, in (col, row) order + p2: (2,) int32 pixel coordinates of the other endpoint of the RECIST line, in (col, row) order + spacing: (3,) float64 image spacing from sitk.GetSpacing (x,y,z) + + Returns: + length_mm: float, physical length of the RECIST line in millimeters + """ + dx = (float(p1[0]) - float(p2[0])) * float(spacing[0]) + dy = (float(p1[1]) - float(p2[1])) * float(spacing[1]) + return float(np.hypot(dx, dy)) + + +def generate_recist( + instance: np.ndarray, + spacing: np.ndarray, + min_recist_mm: float = 0.0, +) -> tuple[np.ndarray, list[int]]: + """Draw each lesion's longest-diameter line on its largest-area axial slice. + + Returns (recist, short_ids). short_ids are lesions whose longest diameter is + below min_recist_mm (empty when the filter is off, i.e. min_recist_mm <= 0); + they get no line, and the caller drops them from `gts` too. There is no voxel + -count floor: min_recist_mm already excludes small lesions, and in physical + units rather than voxels. + + Args: + instance: segmentation mask, (Z, Y, X) uint16 cc3d 26-connectivity, can have multiple lesions with different label values + spacing: mask spacing (3,) float64 (x, y, z) + min_recist_mm: minimum diameter threshold for removal of small lesions from gts + + Returns: + recist: array of generated longest-diameter line recist annotations per-lesion (Z, Y, X) uint16, value == lesion id + short_ids: list of lesion ids whose longest diameter is below min_recist_mm + """ + recist = np.zeros_like(instance, dtype=np.uint16) + short_ids: list[int] = [] + for lid in np.unique(instance): + if lid == 0: + continue + # isolate individual lesion mask and find the axial slice with the largest area (most voxels) + mask = (instance == lid).astype(np.uint8) + key_slice = int(np.argmax(np.sum(mask, axis=(1, 2)))) + # Compute RECIST measurement endpoints + result = compute_recist_line(mask[key_slice]) + if result is None: + # Degenerate lesion (largest slice is a single pixel), so its + # diameter is 0 mm -- short by any positive cutoff. Counting it as + # short keeps the "nothing in gts without a prompt" invariant. + if min_recist_mm > 0: + short_ids.append(int(lid)) + continue + p1, p2 = result + if min_recist_mm > 0 and recist_length_mm(p1, p2, spacing) < min_recist_mm: + # Lesion diameter is below the threshold, so it is not included in the RECIST prompt. + short_ids.append(int(lid)) + continue + # Draw RECIST line for largest enough lesions + cv2.line(recist[key_slice], (int(p1[0]), int(p1[1])), (int(p2[0]), int(p2[1])), + color=int(lid), thickness=RECIST_LINE_THICKNESS) + + return recist, short_ids + + +# ─── Tumor ROI crop along Z ──────────────────────────────────────────────────── + +def tumor_z_range( + instance: np.ndarray, + margin: int = 0 +) -> tuple[int, int] | None: + """[z_start, z_stop) contiguous span of axial slices holding label, + margin. + + Contiguous on purpose: the exact set of labeled slices would drop the gaps + between separate lesions and leave a stack whose z spacing is a lie. None + when the volume holds no label at all. + """ + idx = np.flatnonzero(np.any(instance > 0, axis=(1, 2))) + if idx.size == 0: + return None + z0 = max(0, int(idx[0]) - margin) + z1 = min(int(instance.shape[0]), int(idx[-1]) + 1 + margin) + return z0, z1 + + +def shift_origin_z( + origin: np.ndarray, + spacing: np.ndarray, + direction: np.ndarray, + z0: int +) -> np.ndarray: + """Physical origin of the sub-volume that starts at axial index z0. + + sitk maps index->physical as origin + D @ (spacing * index) with D the 3x3 + direction matrix (GetDirection is its row-major flattening), so moving the + first slice to z0 shifts the origin along D's third column. The nibabel + fallback in read_case builds direction with the same column convention. + """ + if z0 == 0: + return np.asarray(origin, dtype=np.float64) + d = np.asarray(direction, dtype=np.float64).reshape(3, 3) + return np.asarray(origin, dtype=np.float64) + d[:, 2] * float(spacing[2]) * float(z0) + + +# ─── Resume support ──────────────────────────────────────────────────────────── + +def expected_keys( + with_recist: bool, + with_zcrop: bool = False +) -> set[str]: + """Helper function for is_complete to check if the npz has the expected keys. + + Args: + with_recist: bool, whether the npz should have the 'recist' key + with_zcrop: bool, whether the npz should have the 'z_crop' key + + Returns: + keys: set of expected keys in the npz file + """ + keys = {"imgs", "gts", "spacing", "direction", "origin", "reader"} + if with_recist: + keys.add("recist") + if with_zcrop: + keys.add("z_crop") + return keys + + +def is_complete( + out_path: str | Path, + with_recist: bool, + with_zcrop: bool = False +) -> bool: + """True if out_path is an npz that opens cleanly and holds the expected keys. + + Only the zip central directory + member names are read (np.load is lazy), so + this is cheap. A truncated/corrupt file from a killed run reads as False and + gets reconverted. 'z_crop' must be present iff cropping is requested, so + flipping --tumor-slices-only reconverts stale npz without needing + --overwrite. + """ + out_path = Path(out_path) + if not out_path.is_file() or out_path.stat().st_size == 0: + return False + try: + with np.load(str(out_path), allow_pickle=False) as data: + files = set(data.files) + except (zipfile.BadZipFile, OSError, ValueError, EOFError): + return False + if not with_zcrop and "z_crop" in files: + return False + return expected_keys(with_recist, with_zcrop).issubset(files) + + +def savez_atomic( + out_path: Path, + arrays: dict[str, Any] +) -> None: + """np.savez_compressed via a temp file + rename, so readers never see a partial npz.""" + out_path.parent.mkdir(parents=True, exist_ok=True) + # NamedTemporaryFile in the destination dir keeps the rename on one filesystem. + # Suffix must end in '.npz' -- np.savez_compressed appends '.npz' otherwise. + fd, tmp = tempfile.mkstemp(dir=str(out_path.parent), prefix=f".{out_path.stem}.", suffix=".tmp.npz") + os.close(fd) + try: + np.savez_compressed(tmp, **arrays) + Path(tmp).replace(out_path) + except BaseException: + Path(tmp).unlink(missing_ok=True) + raise + + +# ─── One case ────────────────────────────────────────────────────────────────── + +def case_to_npz( + img_path: str | Path, + lbl_path: str | Path, + out_path: str | Path, + *, + level: int, + width: int, + with_recist: bool = True, + min_recist_mm: float = 0.0, + tumor_slices_only: bool = False, + tumor_slice_margin: int = 0, +) -> dict[str, int]: + """Window one NIfTI image+label -> npz. Always (over)writes; caller handles skipping. + + -> {'dropped', 'remaining', 'z0', 'z1', 'nz_full'} (z* == 0/nz_full when uncropped) + + Args: + img_path: str | Path, path to the image/scan file + lbl_path: str | Path, path to the segmentation label/mask file + out_path: str | Path, path to save the output npz file + level: int, window level (center) for image windowing + width: int, window width for image windowing + with_recist: bool, whether to compute RECIST longest-diameter lines + min_recist_mm: float, minimum diameter threshold for inclusion of lesions in gts and recist, default 0.0 (no filtering) + tumor_slices_only: bool, whether to crop the output arrays along Z to the tumor ROI, default False + tumor_slice_margin: int, margin to add around the tumor slice crop, default 0 + + Returns: + stats: dict[str, int], statistics about the conversion, including: + 'dropped': number of lesions dropped due to min_recist_mm + 'remaining': number of lesions remaining in gts after filtering + 'z0': starting slice index of the tumor crop (0 if uncropped) + 'z1': ending slice index of the tumor crop (nz_full if uncropped) + 'nz_full': total number of slices in the original volume + """ + ct, lbl, spacing, direction, origin, reader = read_case(img_path, lbl_path) + imgs = ct_window(ct, level, width) + + instance = cc3d.connected_components((lbl > 0).astype(np.uint8), connectivity=26).astype(np.uint16) + + recist = None + short_ids: list[int] = [] + if with_recist: + recist, short_ids = generate_recist(instance, spacing, min_recist_mm=min_recist_mm) + if short_ids: + # Drop sub-threshold lesions from the segmentation target as well, so + # gts never contains a lesion that has no RECIST prompt. Surviving + # lesions keep their original ids (gaps are expected). + instance[np.isin(instance, short_ids)] = 0 + + nz_full = int(instance.shape[0]) + z0, z1 = 0, nz_full + if tumor_slices_only: + # Derived from the post-filter instance map, so lesions dropped above do + # not hold the crop open. A case with no label left keeps its full extent + # -- a zero-slice npz would just be a broken file. + span = tumor_z_range(instance, margin=tumor_slice_margin) + if span is not None: + z0, z1 = span + imgs = imgs[z0:z1] + instance = instance[z0:z1] + if recist is not None: + recist = recist[z0:z1] + origin = shift_origin_z(origin, spacing, direction, z0) + + arrays: dict[str, Any] = { + "imgs": imgs, "gts": instance, "spacing": spacing, + "direction": direction, "origin": origin, "reader": np.array(reader), + } + if recist is not None: + arrays["recist"] = recist + if tumor_slices_only: + arrays["z_crop"] = np.array([z0, z1], dtype=np.int64) + + savez_atomic(Path(out_path), arrays) + return {"dropped": len(short_ids), "remaining": int(len(np.unique(instance)) - 1), + "z0": z0, "z1": z1, "nz_full": nz_full} + + +def _convert_one(job: dict[str, Any]) -> tuple[str, str, str | None, dict[str, int]]: + """-> (status, out_path, detail, stats). status: ok | skip | filtered | error.""" + out = job["out"] + try: + # Label-extent filter runs BEFORE the resume check, so a case that no + # longer qualifies is reported (and optionally pruned) even when its npz + # was written by an earlier run. Only the label is read here, not the CT. + min_slices = job["min_slices"] + if min_slices > 0: + n_slices = count_label_slices(job["lbl"]) + if n_slices < min_slices: + existed = Path(out).exists() + if existed and job["prune_filtered"]: + Path(out).unlink(missing_ok=True) + detail = f"{n_slices} label slice(s) < {min_slices}" + if existed: + detail += " [pruned existing npz]" if job["prune_filtered"] else " [existing npz LEFT in place]" + return ("filtered", out, detail, {}) + + if not job["overwrite"] and is_complete(out, job["with_recist"], job["tumor_slices_only"]): + return ("skip", out, None, {}) + stats = case_to_npz( + job["img"], job["lbl"], out, level=job["level"], width=job["width"], + with_recist=job["with_recist"], min_recist_mm=job["min_recist_mm"], + tumor_slices_only=job["tumor_slices_only"], + tumor_slice_margin=job["tumor_slice_margin"]) + dropped, remaining = stats["dropped"], stats["remaining"] + detail = None + if dropped: + detail = f"dropped {dropped} lesion(s) with RECIST < {job['min_recist_mm']:g} mm" + if remaining == 0: + detail += " -- NO lesions left in gts" + # Consider moving this statement to an else block + return ("ok", out, detail, stats) + except Exception as exc: # noqa: BLE001 -- per-case error, collected not fatal + return ("error", out, repr(exc), {}) + + +# ─── Batch ───────────────────────────────────────────────────────────────────── + +def build_pairs( + ds: str, + root: Path +) -> list[tuple[Path, Path, str]]: + """(image, label, case_id) triples. Fail loud on structural problems.""" + # Dataset must exist in the DATASET_WINDOW constant at the top of this script + if ds not in DATASET_WINDOW: + message = f"[setup] unknown dataset {ds!r} (known: {sorted(DATASET_WINDOW)})" + raise SystemExit(message) + + images_tr = root / ds / "imagesTr" + labels_tr = root / ds / "labelsTr" + # Check that images and labels paths point to directories + if not images_tr.is_dir(): + message = f"[setup] missing imagesTr: {images_tr}" + raise SystemExit(message) + if not labels_tr.is_dir(): + message = f"[setup] missing labelsTr: {labels_tr}" + raise SystemExit(message) + + images = sorted(images_tr.glob(f"*{IMG_SUFFIX}")) + # Check that nifti files were found in the images directory + if not images: + message = f"[setup] no '*{IMG_SUFFIX}' images under {images_tr}" + raise SystemExit(message) + # Generate tuples with matching image and label file paths and a case ID to label the output with + pairs: list[tuple[Path, Path, str]] = [] + for img in images: + case = img.name[: -len(IMG_SUFFIX)] + lbl = labels_tr / f"{case}.nii.gz" + # Fail if an image does not have a corresponding label + if not lbl.exists(): + message = f"[fail-loud] image without label: {img.name} -> expected {lbl}" + raise SystemExit(message) + pairs.append((img, lbl, case)) + return pairs + + +def build_pairs_from_mit( + mit_dir: Path +) -> list[tuple[Path, Path, str]]: + """Set up (image, label, case_id) triples to iterate over from a med-imagetools autopipeline index. case_id will be the label for the npz file. + """ + if not mit_dir.exists(): + message = f"[setup] med-imagetools directory not found at {mit_dir}" + raise SystemExit(message) + + # Get just the name of the MIT directory to use for index file loading + mit_ds = mit_dir.stem + + # Load med-imagetools index into a dataframe + mit_index_path = mit_dir / f"{mit_ds}_index-simple.csv" + mit_index = pd.read_csv(mit_index_path) + + pairs: list[tuple[Path, Path, str]] = [] + + # group the dataframe by SampleNumber + for _sample_num, group in mit_index.groupby('SampleNumber'): + # Get all of the images and segmentation masks + images = mit_dir / group.loc[group['class'] == 'Scan', 'filepath'].astype(str) + labels = mit_dir / group.loc[group['class'] == 'Mask', 'filepath'].astype(str) + # Extract the case_id from the beginning of the filepath + case_id = group['filepath'].to_numpy[0].split('/')[0] + + # Get each pair of the scan and it's labels, and add the sample number as the case for the pair triplet + for pair in itertools.product(images, labels, [case_id]): + pairs.append(pair) + + return pairs + + +def run_dataset( + ds: str, + root: Path, + out_root: Path, + workers: int, + with_recist: bool, + *, # handles too many variables qa check in ruff + overwrite: bool = False, + min_slices: int = MIN_LABEL_SLICES, + prune_filtered: bool = False, + min_recist_mm: float = MIN_RECIST_MM, + tumor_slices_only: bool = False, + tumor_slice_margin: int = 0, + anat_window: str = 'soft-tissue', + pair_builder: str = 'nnunet' +) -> tuple[int, int, int, int, int, int, int]: + """Convert one dataset to per-case npz, with optional RECIST and tumor-slice cropping. + + Args: + ds: str, dataset name + root: Path, pathway to the image and mask directories (nnU-Net raw root) + out_root: Path, output directory for the npz files + workers: int, number of parallel processes to use + with_recist: bool, whether to compute RECIST longest-diameter lines + overwrite: bool, whether to reconvert every case (default False, skip existing npz) + min_slices: int, minimum number of axial slices with label for inclusion of a case + prune_filtered: bool, whether to delete npz that no longer meets the min_slices + min_recist_mm: float, minimum diameter threshold for inclusion of lesions in gts and recist, default 0.0 (no filtering) + tumor_slices_only: bool, whether to crop the output arrays along Z to the tumor ROI, default False + tumor_slice_margin: int, margin to add around the tumor slice crop, default 0 + anat_window: str, anatomical windowing to apply to the images + pair_builder: str, method to use for generating list of pairs to process + Returns: + tuple of counts: (written, skipped, filtered, errors, dropped_lesions, z_kept, z_total) + """ + # bucket = DATASET_WINDOW[ds] + win = WINDOW_BUCKET[anat_window] + level, width = win["level"], win["width"] + + # Get list of (image_path, label_path, case_id) to iterate over + match pair_builder: + case 'nnunet': + pairs = build_pairs(ds, root) + case 'mit': + pairs = build_pairs_from_mit(mit_dir = root) + case _: + message = f"Incompatible pair_builder input: {pair_builder}. Must be 'nnunet' or 'mit'." + raise ValueError(message) + + # Create output directory + out_dir = out_root # / ds + out_dir.mkdir(parents=True, exist_ok=True) + + print(f"\n=== {ds} anat_window={anat_window} window=L{level}/W{width} cases={len(pairs)} " # noqa + f"recist={'on' if with_recist else 'off'} " + f"mode={'overwrite' if overwrite else 'resume'} " + f"min_label_slices={min_slices or 'off'} " + f"min_recist_mm={f'{min_recist_mm:g}' if min_recist_mm > 0 else 'off'} " + f"tumor_slices_only={f'on(+{tumor_slice_margin})' if tumor_slices_only else 'off'} ===", + flush=True) + + jobs = [{"img": str(img), "lbl": str(lbl), "out": str(out_dir / f"{case}.npz"), + "level": level, "width": width, "with_recist": with_recist, + "overwrite": overwrite, "min_slices": min_slices, + "prune_filtered": prune_filtered, "min_recist_mm": min_recist_mm, + "tumor_slices_only": tumor_slices_only, + "tumor_slice_margin": tumor_slice_margin} + for img, lbl, case in pairs] + + written = skipped = dropped_lesions = z_kept = z_total = 0 + small: list[tuple[str, str | None]] = [] + filtered: list[tuple[str, str | None]] = [] + errors: list[tuple[str, str | None]] = [] + with ProcessPoolExecutor(max_workers=workers) as ex: + futures = [ex.submit(_convert_one, j) for j in jobs] + for i, fut in enumerate(as_completed(futures), 1): + status, out, detail, stats = fut.result() + dropped_lesions += stats.get("dropped", 0) + + z_kept += stats["z1"] - stats["z0"] if stats else 0 + z_total += stats["nz_full"] if stats else 0 + + match status: + case "ok": + written += 1 + if detail: + small.append((out, detail)) + case "skip": + skipped += 1 + case "filtered": + filtered.append((out, detail)) + case _: + errors.append((out, detail)) + + # log at every 50 samples + if i % 50 == 0 or i == len(futures): + print(f" {i}/{len(futures)} done; written={written} skipped={skipped} "# noqa + f"filtered={len(filtered)} errors={len(errors)} " + f"small_lesions_dropped={dropped_lesions}", flush=True) + + for out, detail in small: + print(f" SMALL {Path(out).stem}: {detail}", flush=True) # noqa + for out, detail in filtered: + print(f" FILTERED {Path(out).stem}: {detail}", flush=True) # noqa + for out, detail in errors[:10]: + print(f" ERROR {out}: {detail}", flush=True) # noqa + + crop_note = f" slices_kept={z_kept}/{z_total} ({100.0 * z_kept / z_total:.1f}%)" if tumor_slices_only and z_total else "" + + print(f" summary: {ds} written={written} skipped={skipped} " # noqa + f"filtered={len(filtered)} errors={len(errors)} " + f"small_lesions_dropped={dropped_lesions}{crop_note}", flush=True) + + return written, skipped, len(filtered), len(errors), dropped_lesions, z_kept, z_total + + +def main(argv: list[str] | None = None) -> int: + p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + g = p.add_mutually_exclusive_group(required=True) + g.add_argument("--dataset", choices=sorted(DATASET_WINDOW), help="convert one dataset") + g.add_argument("--all", action="store_true", help="convert all 14 datasets") + p.add_argument("--root", type=Path, default=Path(ROOT_DEFAULT), help="nnU-Net raw root OR med-imagetools autopipeline output dir") + p.add_argument("--out-root", type=Path, default='./RECIST-npz', + help="output dir (default /npz_version_data)") + p.add_argument("--workers", type=int, default=24, help="process-pool size") + p.add_argument("--no-recist", action="store_true", + help="skip RECIST line generation and omit the 'recist' key") + p.add_argument("--overwrite", action="store_true", + help="reconvert every case (default: skip cases whose npz is already complete)") + p.add_argument("--min-label-slices", type=int, default=MIN_LABEL_SLICES, + help=f"exclude cases whose label spans fewer axial slices " + f"(default {MIN_LABEL_SLICES}; 0 disables the filter)") + p.add_argument("--prune-filtered", action="store_true", + help="delete existing npz for cases the label-slice filter now excludes " + "(default: report them and leave the files alone)") + p.add_argument("--exclude-small-lesions", action=argparse.BooleanOptionalAction, default=True, + help=f"drop lesions whose RECIST longest diameter is < --min-recist-mm from " + f"both 'gts' and 'recist' (default: on, threshold {MIN_RECIST_MM:g} mm)") + p.add_argument("--min-recist-mm", type=float, default=MIN_RECIST_MM, + help=f"RECIST longest-diameter cutoff in mm for --exclude-small-lesions " + f"(default {MIN_RECIST_MM:g})") + p.add_argument("--tumor-slices-only", action="store_true", + help="crop every array along Z to the contiguous span of axial slices " + "holding label (default: off, keep the full volume); shifts 'origin' " + "and records 'z_crop'") + p.add_argument("--tumor-slice-margin", type=int, default=0, + help="extra axial slices to keep on each side of the tumor span " + "(default 0; only with --tumor-slices-only)") + p.add_argument("--anat-window", type=str, default='soft-tissue', + help=f"window settings to use for processing CT. Must be one of {WINDOW_BUCKET.keys()} " + f"(default: 'soft-tissue')") + p.add_argument("--pair-builder", type=str, default='nnunet', + help="method to use for pair building, based on directory structure of niftis. Can be nnunet or mit (for med-imagetools). " + "(default: 'nnunet')") + args = p.parse_args(argv) + + if args.min_label_slices < 0: + p.error("--min-label-slices must be >= 0") + if args.min_recist_mm < 0: + p.error("--min-recist-mm must be >= 0") + if args.tumor_slice_margin < 0: + p.error("--tumor-slice-margin must be >= 0") + if args.tumor_slice_margin and not args.tumor_slices_only: + p.error("--tumor-slice-margin has no effect without --tumor-slices-only") + if args.anat_window not in WINDOW_BUCKET: + p.error(f"--anat-window must be one of {WINDOW_BUCKET.keys()}") + + out_root = args.out_root or (args.root / "npz_version_data") + datasets = sorted(DATASET_WINDOW) if args.all else [args.dataset] + with_recist = not args.no_recist + min_recist_mm = args.min_recist_mm if args.exclude_small_lesions else 0.0 + + # The cutoff is measured on the RECIST line, so it cannot be applied at all + # without computing one. + if min_recist_mm > 0 and not with_recist: + p.error("--exclude-small-lesions needs the RECIST lines; drop --no-recist " + "or pass --no-exclude-small-lesions") + + print(f"root={args.root} out_root={out_root} datasets={len(datasets)} " # noqa + f"workers={args.workers} recist={'on' if with_recist else 'off'} " + f"mode={'overwrite' if args.overwrite else 'resume'} " + f"min_label_slices={args.min_label_slices or 'off'} " + f"min_recist_mm={f'{min_recist_mm:g}' if min_recist_mm > 0 else 'off'} " + f"tumor_slices_only={f'on(+{args.tumor_slice_margin})' if args.tumor_slices_only else 'off'}" + f"{' prune_filtered=on' if args.prune_filtered else ''}", + f"anat_window={args.anat_window} ", flush=True) + + total_written = total_skipped = total_filtered = total_err = total_dropped = total_z_kept = total_z_full = 0 + for ds in datasets: + w, s, f, e, d, zk, zt = run_dataset( + ds, args.root, out_root, args.workers, with_recist, args.overwrite, + args.min_label_slices, args.prune_filtered, min_recist_mm, + args.tumor_slices_only, args.tumor_slice_margin) + total_written += w + total_skipped += s + total_filtered += f + total_err += e + total_dropped += d + total_z_kept += zk + total_z_full += zt + + crop_note = (f" slices_kept={total_z_kept}/{total_z_full} ({100.0 * total_z_kept / total_z_full:.1f}%)") if args.tumor_slices_only and total_z_full else "" + + print(f"\nTOTAL written={total_written} skipped={total_skipped} " # noqa + f"filtered={total_filtered} errors={total_err} " + f"small_lesions_dropped={total_dropped}{crop_note}", flush=True) + + return 1 if total_err else 0 + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/src/ab_testing/utils/masks.py b/src/ab_testing/utils/masks.py new file mode 100644 index 0000000..3024d59 --- /dev/null +++ b/src/ab_testing/utils/masks.py @@ -0,0 +1,34 @@ +import numpy as np +import SimpleITK as sitk + + +def get_max_area_slice(mask: np.ndarray | sitk.Image) -> tuple[np.ndarray|sitk.Image, int]: + ''' + Find maximum area slice of a given ground truth segmentation. Will be the slice + to calculate RERECIST on. + + Parameters + ---------- + mask: np.ndarray | sitk.Image + 3D segmentation mask to find the maximum area slice in. + + Returns + ---------- + max_area_slice: np.ndarray | sitk.Image + 2D slice with the largest masked area. Returned in same format as mask input. + max_area_slice_idx: int + The index of the slice (z-axis) with the largest masked area. + ''' + if isinstance(mask, sitk.Image): + # Convert mask to array for calculations + mask = sitk.GetArrayFromImage(mask) + + slice_sums = np.sum(mask, axis = (1, 2)) # Get the pixel area of each slice + max_area_slice_idx = np.argmax(slice_sums) # Get the slice index with the largest pixel area + max_area_slice = mask[max_area_slice_idx] # Get the slice out of the mask array + + + if isinstance(mask, sitk.Image): + max_area_slice = sitk.GetImageFromArray(max_area_slice) + + return max_area_slice, max_area_slice_idx \ No newline at end of file diff --git a/workflow/notebooks/README.md b/workflow/notebooks/README.md deleted file mode 100644 index 9e8c74c..0000000 --- a/workflow/notebooks/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Notebooks Directory - -## Purpose - -This directory contains **Jupyter/RMarkdown/Quarto notebooks** used for: - -- Interactive data exploration and visualization -- Prototype analysis development -- Results generation with embedded documentation -- Educational demonstrations of analysis methods - -## Best Practices for Notebooks - -To ensure your notebooks are useful to others: - -- Include markdown cells that explain the purpose and methodology -- Document all data inputs and their sources -- Keep code cells focused and documented with comments -- Include visualization outputs in the committed notebook -- Consider using [nbdev](https://nbdev.fast.ai/) or similar tools for notebook-driven development - -## Git Synchronization - -Unlike data directories, **notebooks ARE tracked in Git** and should be: - -- Well-documented with clear purposes -- Cleaned of large outputs before committing (consider tools like [nbstripout](https://github.com/kynan/nbstripout)) -- Named descriptively (e.g., `01_data_exploration.ipynb`, `02_feature_selection.ipynb`) -WARNING: if the data you are working with cannot be publicly shared (e.g. internal datasets), make sure no results are pushed to Git in your notebooks! -## Organization Recommendations - -Organize notebooks in a logical sequence that follows your analysis workflow: - -1. Data loading and exploration notebooks -2. Data processing notebooks -3. Analysis notebooks -4. Visualization and results notebooks - -## Data References - -When accessing data in notebooks: - -- Use relative paths with symbolic links to reference data in the `data/` directories - - **DO NOT** hard-code absolute paths like `/home/user/project/data/rawdata/` or `/cluster/project/data/rawdata/` -- Document the specific data files used in markdown cells - -Remember that notebooks serve as interactive documentation of your analysis process and should be readable and reproducible by others! diff --git a/workflow/notebooks/example_notebook.ipynb b/workflow/notebooks/example_notebook.ipynb deleted file mode 100644 index 983cd67..0000000 --- a/workflow/notebooks/example_notebook.ipynb +++ /dev/null @@ -1,75 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "442beff9", - "metadata": {}, - "source": [ - "# Example Notebook\n", - "\n", - "This is just a quick example showing how to use the template." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "75fde9f9", - "metadata": {}, - "outputs": [], - "source": [ - "import logging\n", - "\n", - "logging.basicConfig(\n", - "\tlevel=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s'\n", - ")\n", - "\n", - "logger = logging.getLogger(__name__)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d08bd5d", - "metadata": {}, - "outputs": [], - "source": [ - "from damply import dirs\n", - "\n", - "print(dirs)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ac1f9617", - "metadata": {}, - "outputs": [], - "source": [ - "print(f'{dirs.RAWDATA=} has {len(list(dirs.RAWDATA.glob(\"*\")))} files')\n", - "print(f'{dirs.PROCDATA=} has {len(list(dirs.PROCDATA.glob(\"*\")))} files')\n", - "print(f'{dirs.SCRIPTS=} has {len(list(dirs.SCRIPTS.glob(\"*\")))} files')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "default", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.13.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/workflow/scripts/README.md b/workflow/scripts/README.md deleted file mode 100644 index 4ef2dfb..0000000 --- a/workflow/scripts/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Scripts Directory - -## Purpose - -This directory contains **reusable code scripts** for: - -- Data processing pipelines -- Analysis workflows -- Utility functions -- Automation tasks - -## Best Practices for Scripts - -For maximum usability, scripts should: - -- Include a detailed docstring/header explaining purpose, inputs, outputs -- Contain inline comments for complex logic -- Be modular and follow the single responsibility principle -- Include proper error handling and logging -- Have command-line interfaces when appropriate - -## Git Synchronization - -Scripts **ARE tracked in Git** and represent the core reproducible components of your analysis. Ensure scripts: - -- Are well-tested before committing -- Have clear versioning (consider semantic versioning) -- Include usage examples in comments or separate documentation - -## Organization Recommendations - -Consider organizing scripts by their function: - -```console -/scripts/preprocessing/ -/scripts/analysis/ -/scripts/visualization/ -/scripts/utilities/ -``` - -## Data References - -When scripts access data: - -- Use command-line arguments or configuration files for file paths -- Document in `docs/data_sources.md` which scripts use which data sources -- Consider using symbolic links for consistent references across environments - -## Documentation Requirement - -It is **highly recommended** to convert scripts to CLI tools using popular libraries -like `click` or `typer`, which can make them more user-friendly and easier to document. - -```console -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -script_name.py -Usage: script_name.py [options] - -Arguments: - input Description of input - output Description of output - -Options: - -h --help Show this help - -v --verbose Verbose output -""" -``` - -Remember that well-documented scripts are essential for reproducible research and enable others to understand and build upon your work! diff --git a/workflow/scripts/example_script.py b/workflow/scripts/example_script.py deleted file mode 100644 index 98cf78a..0000000 --- a/workflow/scripts/example_script.py +++ /dev/null @@ -1,33 +0,0 @@ -import logging -from pathlib import Path - -from damply import dirs - -logging.basicConfig( - level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' -) - -logger = logging.getLogger(__name__) - - -def main() -> None: - print(f'{dirs.PROJECT_ROOT=}') - - print(f'{dirs.RAWDATA=} has {len(list(dirs.RAWDATA.glob("*")))} files') - print(f'{dirs.PROCDATA=} has {len(list(dirs.PROCDATA.glob("*")))} files') - print(f'{dirs.SCRIPTS=} has {len(list(dirs.SCRIPTS.glob("*")))} files') - - # these are all available via the `dirs`` object - # CONFIG : ├── config - # LOGS : ├── logs - # METADATA : ├── metadata - # NOTEBOOKS : ├── workflow/notebooks - # PROCDATA : ├── data/procdata - # RAWDATA : ├── data/rawdata - # RESULTS : ├── data/results - # SCRIPTS : └── workflow/scripts - - -if __name__ == '__main__': - logger.info(f'Starting example script from {Path().cwd()=}') - main()