From 0f02e506aa61f984db45f51436e39624e49de90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Wed, 22 Nov 2023 15:13:03 +0100 Subject: [PATCH 01/79] feat: core structure --- .flake8 | 3 + .gitignore | 173 ++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 25 ++++++ LICENSE | 21 +++++ README.md | 0 pyproject.toml | 80 +++++++++++++++++++ tests/__init__.py | 0 7 files changed, 302 insertions(+) create mode 100644 .flake8 create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pyproject.toml create mode 100644 tests/__init__.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..63ea673 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length=88 +extend-ignore=E203 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e8d849 --- /dev/null +++ b/.gitignore @@ -0,0 +1,173 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm-project.org/#use-with-ide +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# ruff +.ruff_cache/ + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# VSCode +.vscode/ + +# MacOS +.DS_Store + + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ce38961 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,25 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + +- repo: https://github.com/compilerla/conventional-pre-commit + rev: v2.3.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: ["exp"] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.5 + hooks: + # Run the linter. + - id: ruff + types_or: [ python, pyi, jupyter ] + args: [ --fix ] + # Run the formatter. + - id: ruff-format + types_or: [ python, pyi, jupyter ] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..caebf45 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 RationAI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..846269e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,80 @@ +[project] +name = "" +version = "0.1.0" +description = "" +authors = [] +requires-python = ">=3.11,<3.12" +readme = "README.md" +license = { file = "LICENSE" } + + +##################################### +# Dependencies +##################################### + +dependencies = [] + +[tool.pdm.dev-dependencies] +dev = ["mypy", "pre-commit", "ruff", "pytest"] + + +##################################### +# Scripts +##################################### + +[tool.pdm.scripts] +l = { composite = ["lint", "format", "mypy"] } +tests = "pytest tests" +lint = "ruff check ." +format = "ruff format ." +mypy = "mypy ." +post_install = { composite = [ + "pre-commit install", + "pre-commit install --hook-type commit-msg", +] } + + +##################################### +# Tool configuration +##################################### + +[tool.pylint.messages_control] +disable = ["missing-docstring", "redefined-builtin"] + +[tool.mypy] +strict = true +show_error_codes = true +ignore_missing_imports = true + +[tool.ruff] +fix = true +line-length = 88 +target-version = "py311" +extend-ignore = ["ERA001"] + +[tool.ruff.lint] +unfixable = [ + "ERA", # do not autoremove commented out code +] +extend-select = [ + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "ERA", # flake8-eradicate/eradicate + "I", # isort + "N", # pep8-naming + "PIE", # flake8-pie + "PGH", # pygrep + "RUF", # ruff checks + "SIM", # flake8-simplify + "TCH", # flake8-type-checking + "TID", # flake8-tidy-imports + "UP", # pyupgrade +] + +[tool.ruff.lint.flake8-tidy-imports] +ban-relative-imports = "all" + +[tool.ruff.lint.isort] +lines-between-types = 1 +lines-after-imports = 2 +known-first-party = ["tests"] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 From 3c62cb678246d6761ac349e74b0b9f7de8d8f8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 12:36:54 +0100 Subject: [PATCH 02/79] feat: script for syncing project with template --- sync-with-template.sh | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100755 sync-with-template.sh diff --git a/sync-with-template.sh b/sync-with-template.sh new file mode 100755 index 0000000..01efa74 --- /dev/null +++ b/sync-with-template.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +TEMPLATE_REPO="git@gitlab.ics.muni.cz:rationai/digital-pathology/templates/python.git" +TEMPLATE_BRANCH="master" +COMMIT_FILE="last-template-commit.txt" + + +echo "🔄 Syncing with the template..." + +# Exit on error +set -e + +# Remove template remote if exists +if git remote | grep -q template; then + git remote remove template +fi + +# Add template remote +git remote add template "${TEMPLATE_REPO}" +git fetch template > /dev/null 2>&1 + +# Get last synced commit hash or fallback to the first commit +if [ -s "${COMMIT_FILE}" ] +then + COMMIT_HASH=$(cat "${COMMIT_FILE}") +else + COMMIT_HASH=$(git rev-list --max-parents=0 "template/${TEMPLATE_BRANCH}") +fi + +# Merge template/master into current branch from the last synced commit hash +LATEST_COMMIT=$(git rev-parse "template/${TEMPLATE_BRANCH}") +if [ "$COMMIT_HASH" != "$LATEST_COMMIT" ]; then + set +e + git cherry-pick "${COMMIT_HASH}".."template/${TEMPLATE_BRANCH}" + RETURN_CODE=$? + set -e + + if [ $RETURN_CODE -eq 0 ]; then + git rev-parse template/master > "${COMMIT_FILE}" + echo "🚀 The repository has been successfully synced with the template." + elif [ $RETURN_CODE -eq 1 ]; then + git rev-parse template/master > "${COMMIT_FILE}" + echo "❗️ Auto-syncing failed. Please resolve the conflicts manually." + else + echo "❌ There was a problem with syncing the repository with the template." + fi + git cherry-pick --quit +else + echo "🚀 The repository is already up to date with the template." +fi + +# Clean up +git remote remove template From b0f97c1609a349b7842106ca19608173a560bffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 13:50:19 +0100 Subject: [PATCH 03/79] fix: remove default "exp" type from commit --- .gitignore | 1 - .pre-commit-config.yaml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9e8d849..26295c3 100644 --- a/.gitignore +++ b/.gitignore @@ -170,4 +170,3 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce38961..7d2c5e4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: hooks: - id: conventional-pre-commit stages: [commit-msg] - args: ["exp"] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] + args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.5 From 2a22665f4d972f36ac3233230009f8ade4bd28a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 14:04:24 +0100 Subject: [PATCH 04/79] fix: remove silence --- sync-with-template.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sync-with-template.sh b/sync-with-template.sh index 01efa74..432b121 100755 --- a/sync-with-template.sh +++ b/sync-with-template.sh @@ -17,7 +17,7 @@ fi # Add template remote git remote add template "${TEMPLATE_REPO}" -git fetch template > /dev/null 2>&1 +git fetch template # Get last synced commit hash or fallback to the first commit if [ -s "${COMMIT_FILE}" ] From 13f7425063b43290be56865eeabf89d35c6e8ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 14:36:05 +0100 Subject: [PATCH 05/79] fix: ignore mlruns --- .gitignore | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 26295c3..237c723 100644 --- a/.gitignore +++ b/.gitignore @@ -163,10 +163,5 @@ cython_debug/ # MacOS .DS_Store - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +# Mlflow +mlruns/ From b8db313f501746956b9eee3a5d940d09d68fade2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 15:48:40 +0100 Subject: [PATCH 06/79] fix: remove empty line between import types --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 846269e..3da8fd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,5 @@ extend-select = [ ban-relative-imports = "all" [tool.ruff.lint.isort] -lines-between-types = 1 lines-after-imports = 2 known-first-party = ["tests"] From 6f290ec9ee2e5dc22cc7f33cf7abbd30eac6109c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 Nov 2023 18:19:49 +0100 Subject: [PATCH 07/79] feat: separate test dependencies --- pyproject.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3da8fd7..c5f9b6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,8 @@ license = { file = "LICENSE" } dependencies = [] [tool.pdm.dev-dependencies] -dev = ["mypy", "pre-commit", "ruff", "pytest"] +dev = ["mypy", "pre-commit", "ruff"] +test = ["pytest"] ##################################### @@ -50,7 +51,9 @@ ignore_missing_imports = true fix = true line-length = 88 target-version = "py311" -extend-ignore = ["ERA001"] +extend-ignore = [ + "ERA001", # commented out code +] [tool.ruff.lint] unfixable = [ From 2b5660f8cc15e1a6ead6f891aedf109bce270318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Thu, 30 Nov 2023 22:02:21 +0100 Subject: [PATCH 08/79] feat: CI/CD --- .gitlab-ci.yml | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..19a43bf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,63 @@ +image: python:3.11 + +# Runs jobs only in merge request pipelines. +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +# Change pip's cache directory to be inside the project directory since we can +# only cache local items. +variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + +# Pip's cache doesn't store the python packages +# https://pip.pypa.io/en/stable/topics/caching/ +# +# If you want to also cache the installed packages, you have to install +# them in a virtualenv and cache it as well. +cache: + paths: + - .cache/pip + - .venv + +stages: + - lint + - test + +before_script: + - python --version ; pip --version # For debugging + - pip install -q pdm + - pdm install --no-lock -q + + +ruff-lint: + stage: lint + script: + - pdm lint + +ruff-format: + stage: lint + script: + - pdm format --check + +mypy: + stage: lint + allow_failure: true + script: + - pdm mypy + cache: + paths: + - .mypy_cache + +pytest: + stage: test + script: + - pdm test --junitxml=report.xml + artifacts: + when: always + reports: + junit: report.xml + cache: + paths: + - .pytest_cache diff --git a/pyproject.toml b/pyproject.toml index c5f9b6f..1cb7f6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ test = ["pytest"] [tool.pdm.scripts] l = { composite = ["lint", "format", "mypy"] } -tests = "pytest tests" +test = "pytest tests" lint = "ruff check ." format = "ruff format ." mypy = "mypy ." From 69357fcf7531cf774c024506dd148f1ea47635f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Thu, 30 Nov 2023 22:24:00 +0100 Subject: [PATCH 09/79] fix: pytest allow empty tests --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 19a43bf..d710098 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,7 +53,8 @@ mypy: pytest: stage: test script: - - pdm test --junitxml=report.xml + # Allow pytest to fail with exit code 5 (no tests collected) + - pdm test --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) artifacts: when: always reports: From da6624562396af7aa87a099ea3a2c8af925d6800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Mon, 4 Dec 2023 19:07:11 +0100 Subject: [PATCH 10/79] feat: syncing pipeline + google code styles --- .gitignore | 7 + .gitlab-ci.yml | 74 +++----- .gitlab/ci/lint.yml | 24 +++ .gitlab/ci/sync.yml | 25 +++ .gitlab/ci/test.yml | 14 ++ .pylintrc | 399 ++++++++++++++++++++++++++++++++++++++++++ README.md | 58 ++++++ pyproject.toml | 17 +- sync-with-template.sh | 53 ------ 9 files changed, 563 insertions(+), 108 deletions(-) create mode 100644 .gitlab/ci/lint.yml create mode 100644 .gitlab/ci/sync.yml create mode 100644 .gitlab/ci/test.yml create mode 100644 .pylintrc delete mode 100755 sync-with-template.sh diff --git a/.gitignore b/.gitignore index 237c723..a42f203 100644 --- a/.gitignore +++ b/.gitignore @@ -165,3 +165,10 @@ cython_debug/ # Mlflow mlruns/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d710098..b4bddaa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,64 +1,36 @@ -image: python:3.11 +default: + image: python:3.11 + before_script: + - python --version ; pip --version # For debugging + - pip install -q pdm + - pdm install --no-lock -q --skip=post_install # skip pre-commit hooks + + # Pip's cache doesn't store the python packages + # https://pip.pypa.io/en/stable/topics/caching/ + cache: + paths: + - .cache/pip + - .venv -# Runs jobs only in merge request pipelines. -workflow: - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Change pip's cache directory to be inside the project directory since we can # only cache local items. variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + TEMPLATE_CI_BRANCH: "ci/template" + + +# Runs jobs only in merge request pipelines or if the branch is TEMPLATE_CI_BRANCH +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + - if: $CI_COMMIT_BRANCH == $TEMPLATE_CI_BRANCH -# Pip's cache doesn't store the python packages -# https://pip.pypa.io/en/stable/topics/caching/ -# -# If you want to also cache the installed packages, you have to install -# them in a virtualenv and cache it as well. -cache: - paths: - - .cache/pip - - .venv stages: - lint - test -before_script: - - python --version ; pip --version # For debugging - - pip install -q pdm - - pdm install --no-lock -q - - -ruff-lint: - stage: lint - script: - - pdm lint - -ruff-format: - stage: lint - script: - - pdm format --check -mypy: - stage: lint - allow_failure: true - script: - - pdm mypy - cache: - paths: - - .mypy_cache - -pytest: - stage: test - script: - # Allow pytest to fail with exit code 5 (no tests collected) - - pdm test --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) - artifacts: - when: always - reports: - junit: report.xml - cache: - paths: - - .pytest_cache +include: .gitlab/ci/*.yml diff --git a/.gitlab/ci/lint.yml b/.gitlab/ci/lint.yml new file mode 100644 index 0000000..6fe5ff9 --- /dev/null +++ b/.gitlab/ci/lint.yml @@ -0,0 +1,24 @@ +ruff-lint: + stage: lint + script: + - pdm lint + rules: + - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + +ruff-format: + stage: lint + script: + - pdm format --check + rules: + - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + +mypy: + stage: lint + allow_failure: true + script: + - pdm mypy + cache: + paths: + - .mypy_cache + rules: + - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' diff --git a/.gitlab/ci/sync.yml b/.gitlab/ci/sync.yml new file mode 100644 index 0000000..ef84c36 --- /dev/null +++ b/.gitlab/ci/sync.yml @@ -0,0 +1,25 @@ +sync: + image: bitnami/git + variables: + USER_NAME: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742" + USER_EMAIL: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742@noreply.gitlab.ics.muni.cz" + TEMPLATE_REPO: https://${USER_NAME}:${GROUP_ACCESS_TOKEN_RW}@gitlab.ics.muni.cz/rationai/digital-pathology/templates/python.git + COMMIT_MESSAGE: "ci: sync with template repository" + MERGE_REQUEST_TITLE: "ci: automated MR from Template" + before_script: + - git config --global user.name "${USER_NAME}" + - git config --global user.email "${USER_EMAIL}" + script: + - git pull "${TEMPLATE_REPO}" --no-rebase --allow-unrelated-histories --no-commit -X theirs + - > + if ! git diff --cached --quiet; then + echo "📂 Files that will be commited:" + git diff --cached --name-only + + git commit -m "${COMMIT_MESSAGE}" + git push "https://${USER_NAME}:${GROUP_ACCESS_TOKEN_RW}@${CI_REPOSITORY_URL#*@}" HEAD:$CI_COMMIT_REF_NAME \ + -o merge_request.create -o merge_request.target=${CI_DEFAULT_BRANCH} -o merge_request.remove_source_branch -o merge_request.title="${MERGE_REQUEST_TITLE}" + fi + rules: + - if: $CI_COMMIT_BRANCH == $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE == 'schedule' + cache: {} diff --git a/.gitlab/ci/test.yml b/.gitlab/ci/test.yml new file mode 100644 index 0000000..3de6cf2 --- /dev/null +++ b/.gitlab/ci/test.yml @@ -0,0 +1,14 @@ +pytest: + stage: test + script: + # Allow pytest to fail with exit code 5 (no tests collected) + - pdm test --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) + artifacts: + when: always + reports: + junit: report.xml + cache: + paths: + - .pytest_cache + rules: + - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..cd99157 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,399 @@ +# This Pylint rcfile contains a best-effort configuration to uphold the +# best-practices and style described in the Google Python style guide: +# https://google.github.io/styleguide/pyguide.html +# +# Its canonical open-source location is: +# https://google.github.io/styleguide/pylintrc + +[MAIN] + +# Files or directories to be skipped. They should be base names, not paths. +ignore=third_party + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. +ignore-patterns= + +# Pickle collected data for later comparisons. +persistent=no + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=R, + abstract-method, + apply-builtin, + arguments-differ, + attribute-defined-outside-init, + backtick, + bad-option-value, + basestring-builtin, + buffer-builtin, + c-extension-no-member, + consider-using-enumerate, + cmp-builtin, + cmp-method, + coerce-builtin, + coerce-method, + delslice-method, + div-method, + eq-without-hash, + execfile-builtin, + file-builtin, + filter-builtin-not-iterating, + fixme, + getslice-method, + global-statement, + hex-method, + idiv-method, + implicit-str-concat, + import-error, + import-self, + import-star-module-level, + input-builtin, + intern-builtin, + invalid-str-codec, + locally-disabled, + long-builtin, + long-suffix, + map-builtin-not-iterating, + misplaced-comparison-constant, + missing-function-docstring, + metaclass-assignment, + next-method-called, + next-method-defined, + no-absolute-import, + no-init, # added + no-member, + no-name-in-module, + no-self-use, + nonzero-method, + oct-method, + old-division, + old-ne-operator, + old-octal-literal, + old-raise-syntax, + parameter-unpacking, + print-statement, + raising-string, + range-builtin-not-iterating, + raw_input-builtin, + rdiv-method, + reduce-builtin, + relative-import, + reload-builtin, + round-builtin, + setslice-method, + signature-differs, + standarderror-builtin, + suppressed-message, + sys-max-int, + trailing-newlines, + unichr-builtin, + unicode-builtin, + unnecessary-pass, + unpacking-in-except, + useless-else-on-loop, + useless-suppression, + using-cmp-argument, + wrong-import-order, + xrange-builtin, + zip-builtin-not-iterating, + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# Good variable names which should always be accepted, separated by a comma +good-names=main,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl + +# Regular expression matching correct function names +function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*)|(?P_?[a-z][a-z0-9_]*))$ + +# Regular expression matching correct variable names +variable-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct constant names +const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ + +# Regular expression matching correct attribute names +attr-rgx=^_{0,2}[a-z][a-z0-9_]*$ + +# Regular expression matching correct argument names +argument-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct class names +class-rgx=^_?[A-Z][a-zA-Z0-9]*$ + +# Regular expression matching correct module names +module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$ + +# Regular expression matching correct method names +method-rgx=(?x)^(?:(?P_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P_{0,2}[a-z][a-z0-9_]*))$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=12 + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt +# lines made too long by directives to pytype. + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=(?x)( + ^\s*(\#\ )??$| + ^\s*(from\s+\S+\s+)?import\s+.+$) + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=yes + +# Maximum number of lines in a module +max-module-lines=99999 + +# String used as indentation unit. The internal Google style guide mandates 2 +# spaces. Google's externaly-published style guide says 4, consistent with +# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google +# projects (like TensorFlow). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=TODO + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=yes + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_) + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging,absl.logging,tensorflow.io.logging + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub, + TERMIOS, + Bastion, + rexec, + sets + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant, absl + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls, + class_ + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs diff --git a/README.md b/README.md index e69de29..cd979cd 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,58 @@ +# Python project template + +This project template serves as a robust foundation for Python projects, promoting best practices and streamlining development workflows. It comes preconfigured with essential tools and features to enhance the development experience. + +## Tools Included + +- [PDM](https://pdm-project.org) for efficient dependency management. +- [Ruff](https://docs.astral.sh/ruff) for comprehensive linting and code formatting. +- [Pytest](https://docs.pytest.org) for running tests and ensuring code reliability. +- [pre-commit](https://pre-commit.com) for managing pre-commit git hooks ([Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), ruff check, ruff format) +- [GitLab CI/CD](https://docs.gitlab.com/ee/ci) for continuous integration. +- [Pylint](https://pylint.readthedocs.io) for static code analysis, adhering to the [Google style](https://google.github.io/styleguide/pyguide.html). +- [Pydocstyle](https://www.pydocstyle.org) for validating docstring styles, also following the [Google style](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings). +- [Mypy](https://mypy-lang.org) for static type checking. + + +## Usage + +Key commands for effective project management: + +- `pdm install` - Installs all project dependencies. +- `pdm add ` - Adds a new dependency to the project. +- `pdm l` - Runs linting, formatting, and mypy checks. +- `pdm test` - Executes tests located in the tests directory. +- `pdm run ` - Runs the specified command within the virtual environment. + +## CI/CD + +Two defined pipelines enhance project development: + +1. **Synchronization pipeline(`ci/template` branch):** + - Triggered by a scheduler for the ci/template branch. + - Handles [synchronization](#synchronizing-the-template) with the template repository. + +2. **Project Pipeline (Main branch and Merge Requests):** + - Triggered by any push to the main branch or any merge request to the main branch. + - Consists of the following stages: + - `lint` - Runs linting, formatting, and mypy checks (ruff check, ruff format, mypy). + - `test` - Executes tests using Pytest. + + +## Synchronizing the Template + +For seamless integration with the template repository: + +1. Create a protected branch named `ci/template`. +2. [Schedule a pipeline](https://docs.gitlab.com/ee/ci/pipelines/schedules.html) for the `ci/template` branch to automatically synchronize with the template repository. +3. Ensure the `ci/template` branch tracks the last synchronized commit. +4. The synchronization pipeline will: + - Check out the last synchronized commit. + - Merge the latest commit from the template repository, prioritizing template changes in case of conflicts. + - Commit and push the changes to the `ci/template` branch. + - Create a merge request to the default branch. + + + +> **Note:** +> Resolve any conflicts manually, ensuring the **last synchronized commit** is retained in the ci/template branch to prevent reappearing conflicts during subsequent synchronizations. diff --git a/pyproject.toml b/pyproject.toml index 1cb7f6b..8b810ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "" version = "0.1.0" description = "" authors = [] -requires-python = ">=3.11,<3.12" +requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } @@ -39,9 +39,6 @@ post_install = { composite = [ # Tool configuration ##################################### -[tool.pylint.messages_control] -disable = ["missing-docstring", "redefined-builtin"] - [tool.mypy] strict = true show_error_codes = true @@ -53,6 +50,14 @@ line-length = 88 target-version = "py311" extend-ignore = [ "ERA001", # commented out code + "D100", # missing docstring in public module + "D101", # missing docstring in public class + "D102", # missing docstring in public method + "D103", # missing docstring in public function + "D104", # missing docstring in public package + "D105", # missing docstring in magic method + "D106", # missing docstring in public nested class + "D107", # missing docstring in __init__ ] [tool.ruff.lint] @@ -72,6 +77,7 @@ extend-select = [ "TCH", # flake8-type-checking "TID", # flake8-tidy-imports "UP", # pyupgrade + "D", # pydocstyle ] [tool.ruff.lint.flake8-tidy-imports] @@ -80,3 +86,6 @@ ban-relative-imports = "all" [tool.ruff.lint.isort] lines-after-imports = 2 known-first-party = ["tests"] + +[tool.ruff.lint.pydocstyle] +convention = "google" diff --git a/sync-with-template.sh b/sync-with-template.sh deleted file mode 100755 index 432b121..0000000 --- a/sync-with-template.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -TEMPLATE_REPO="git@gitlab.ics.muni.cz:rationai/digital-pathology/templates/python.git" -TEMPLATE_BRANCH="master" -COMMIT_FILE="last-template-commit.txt" - - -echo "🔄 Syncing with the template..." - -# Exit on error -set -e - -# Remove template remote if exists -if git remote | grep -q template; then - git remote remove template -fi - -# Add template remote -git remote add template "${TEMPLATE_REPO}" -git fetch template - -# Get last synced commit hash or fallback to the first commit -if [ -s "${COMMIT_FILE}" ] -then - COMMIT_HASH=$(cat "${COMMIT_FILE}") -else - COMMIT_HASH=$(git rev-list --max-parents=0 "template/${TEMPLATE_BRANCH}") -fi - -# Merge template/master into current branch from the last synced commit hash -LATEST_COMMIT=$(git rev-parse "template/${TEMPLATE_BRANCH}") -if [ "$COMMIT_HASH" != "$LATEST_COMMIT" ]; then - set +e - git cherry-pick "${COMMIT_HASH}".."template/${TEMPLATE_BRANCH}" - RETURN_CODE=$? - set -e - - if [ $RETURN_CODE -eq 0 ]; then - git rev-parse template/master > "${COMMIT_FILE}" - echo "🚀 The repository has been successfully synced with the template." - elif [ $RETURN_CODE -eq 1 ]; then - git rev-parse template/master > "${COMMIT_FILE}" - echo "❗️ Auto-syncing failed. Please resolve the conflicts manually." - else - echo "❌ There was a problem with syncing the repository with the template." - fi - git cherry-pick --quit -else - echo "🚀 The repository is already up to date with the template." -fi - -# Clean up -git remote remove template From 97e76976f99fd51000db9e55cb9a98854d9e4359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Wed, 6 Dec 2023 14:42:51 +0100 Subject: [PATCH 11/79] fix: pipeline rules --- .gitlab-ci.yml | 16 +++++++--------- .gitlab/ci/lint.yml | 8 +++++--- .gitlab/ci/sync.yml | 1 + .gitlab/ci/test.yml | 2 +- .pre-commit-config.yaml | 3 ++- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b4bddaa..117b461 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,15 +17,6 @@ default: # only cache local items. variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" - TEMPLATE_CI_BRANCH: "ci/template" - - -# Runs jobs only in merge request pipelines or if the branch is TEMPLATE_CI_BRANCH -workflow: - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - - if: $CI_COMMIT_BRANCH == $TEMPLATE_CI_BRANCH stages: @@ -33,4 +24,11 @@ stages: - test +# Runs jobs only in merge request pipelines +.merge_request_pipelines: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + + include: .gitlab/ci/*.yml diff --git a/.gitlab/ci/lint.yml b/.gitlab/ci/lint.yml index 6fe5ff9..d28060a 100644 --- a/.gitlab/ci/lint.yml +++ b/.gitlab/ci/lint.yml @@ -3,14 +3,16 @@ ruff-lint: script: - pdm lint rules: - - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + - !reference [.merge_request_pipelines, rules] + ruff-format: stage: lint script: - pdm format --check rules: - - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + - !reference [.merge_request_pipelines, rules] + mypy: stage: lint @@ -21,4 +23,4 @@ mypy: paths: - .mypy_cache rules: - - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + - !reference [.merge_request_pipelines, rules] diff --git a/.gitlab/ci/sync.yml b/.gitlab/ci/sync.yml index ef84c36..543dfc6 100644 --- a/.gitlab/ci/sync.yml +++ b/.gitlab/ci/sync.yml @@ -1,6 +1,7 @@ sync: image: bitnami/git variables: + TEMPLATE_CI_BRANCH: "ci/template" USER_NAME: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742" USER_EMAIL: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742@noreply.gitlab.ics.muni.cz" TEMPLATE_REPO: https://${USER_NAME}:${GROUP_ACCESS_TOKEN_RW}@gitlab.ics.muni.cz/rationai/digital-pathology/templates/python.git diff --git a/.gitlab/ci/test.yml b/.gitlab/ci/test.yml index 3de6cf2..8c89f03 100644 --- a/.gitlab/ci/test.yml +++ b/.gitlab/ci/test.yml @@ -11,4 +11,4 @@ pytest: paths: - .pytest_cache rules: - - if: $CI_COMMIT_BRANCH != $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE != 'schedule' + - !reference [.merge_request_pipelines, rules] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7d2c5e4..01516a5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,12 +5,13 @@ repos: rev: v4.5.0 hooks: - id: check-yaml + args: [ --unsafe ] - repo: https://github.com/compilerla/conventional-pre-commit rev: v2.3.0 hooks: - id: conventional-pre-commit - stages: [commit-msg] + stages: [ commit-msg ] args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit From 225ee7778969518fe53dcd76412d7266e08a27e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Wed, 6 Dec 2023 14:53:12 +0100 Subject: [PATCH 12/79] fix: pylint max line length 88 --- .pylintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index cd99157..c608030 100644 --- a/.pylintrc +++ b/.pylintrc @@ -238,7 +238,7 @@ generated-members= [FORMAT] # Maximum number of characters on a single line. -max-line-length=80 +max-line-length=88 # TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt # lines made too long by directives to pytype. From 56cdb9c45bea405676dd660406fc4311f7eceef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Thu, 21 Dec 2023 22:30:06 +0100 Subject: [PATCH 13/79] refactor: new bot user --- .gitlab/ci/sync.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab/ci/sync.yml b/.gitlab/ci/sync.yml index 543dfc6..3094fd8 100644 --- a/.gitlab/ci/sync.yml +++ b/.gitlab/ci/sync.yml @@ -2,13 +2,14 @@ sync: image: bitnami/git variables: TEMPLATE_CI_BRANCH: "ci/template" - USER_NAME: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742" - USER_EMAIL: "group_1021_bot_390f0b45d22bcd3d4999f51de6ad8742@noreply.gitlab.ics.muni.cz" - TEMPLATE_REPO: https://${USER_NAME}:${GROUP_ACCESS_TOKEN_RW}@gitlab.ics.muni.cz/rationai/digital-pathology/templates/python.git + NAME: "🤖 Template Bot 🤖" + USER_NAME: "group_1021_bot_62f237df79b4aaf1aeeb93687a941fbb" + USER_EMAIL: "group_1021_bot_62f237df79b4aaf1aeeb93687a941fbb@noreply.gitlab.ics.muni.cz" + TEMPLATE_REPO: https://${USER_NAME}:${GROUP_ACCESS_TOKEN_TEMPLATE_BOT_RW}@gitlab.ics.muni.cz/rationai/digital-pathology/templates/python.git COMMIT_MESSAGE: "ci: sync with template repository" MERGE_REQUEST_TITLE: "ci: automated MR from Template" before_script: - - git config --global user.name "${USER_NAME}" + - git config --global user.name "${NAME}" - git config --global user.email "${USER_EMAIL}" script: - git pull "${TEMPLATE_REPO}" --no-rebase --allow-unrelated-histories --no-commit -X theirs @@ -18,7 +19,7 @@ sync: git diff --cached --name-only git commit -m "${COMMIT_MESSAGE}" - git push "https://${USER_NAME}:${GROUP_ACCESS_TOKEN_RW}@${CI_REPOSITORY_URL#*@}" HEAD:$CI_COMMIT_REF_NAME \ + git push "https://${USER_NAME}:${GROUP_ACCESS_TOKEN_TEMPLATE_BOT_RW}@${CI_REPOSITORY_URL#*@}" HEAD:$CI_COMMIT_REF_NAME \ -o merge_request.create -o merge_request.target=${CI_DEFAULT_BRANCH} -o merge_request.remove_source_branch -o merge_request.title="${MERGE_REQUEST_TITLE}" fi rules: From 0dd2b046a3aca5590bed8ea8388880cd4e2dd7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Thu, 21 Dec 2023 22:39:56 +0100 Subject: [PATCH 14/79] chore: format yaml --- .gitlab-ci.yml | 6 +----- .gitlab/ci/lint.yml | 2 -- .pre-commit-config.yaml | 28 ++++++++++++++-------------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 117b461..b3246be 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ default: image: python:3.11 before_script: - - python --version ; pip --version # For debugging + - python --version ; pip --version # For debugging - pip install -q pdm - pdm install --no-lock -q --skip=post_install # skip pre-commit hooks @@ -12,23 +12,19 @@ default: - .cache/pip - .venv - # Change pip's cache directory to be inside the project directory since we can # only cache local items. variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" - stages: - lint - test - # Runs jobs only in merge request pipelines .merge_request_pipelines: rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - include: .gitlab/ci/*.yml diff --git a/.gitlab/ci/lint.yml b/.gitlab/ci/lint.yml index d28060a..618a148 100644 --- a/.gitlab/ci/lint.yml +++ b/.gitlab/ci/lint.yml @@ -5,7 +5,6 @@ ruff-lint: rules: - !reference [.merge_request_pipelines, rules] - ruff-format: stage: lint script: @@ -13,7 +12,6 @@ ruff-format: rules: - !reference [.merge_request_pipelines, rules] - mypy: stage: lint allow_failure: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 01516a5..3464bab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,26 +1,26 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: -- repo: https://github.com/pre-commit/pre-commit-hooks + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - - id: check-yaml - args: [ --unsafe ] + - id: check-yaml + args: [--unsafe] -- repo: https://github.com/compilerla/conventional-pre-commit + - repo: https://github.com/compilerla/conventional-pre-commit rev: v2.3.0 hooks: - - id: conventional-pre-commit - stages: [ commit-msg ] + - id: conventional-pre-commit + stages: [commit-msg] args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] -- repo: https://github.com/astral-sh/ruff-pre-commit + - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.5 hooks: - # Run the linter. - - id: ruff - types_or: [ python, pyi, jupyter ] - args: [ --fix ] - # Run the formatter. - - id: ruff-format - types_or: [ python, pyi, jupyter ] + # Run the linter. + - id: ruff + types_or: [python, pyi, jupyter] + args: [--fix] + # Run the formatter. + - id: ruff-format + types_or: [python, pyi, jupyter] From 9ed4f98aed6f4b32de0b64da800d614cbf40ce3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 22 Dec 2023 15:19:31 +0100 Subject: [PATCH 15/79] feat: docstring code format --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8b810ef..15bfe62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ post_install = { composite = [ [tool.mypy] strict = true -show_error_codes = true ignore_missing_imports = true [tool.ruff] @@ -60,6 +59,10 @@ extend-ignore = [ "D107", # missing docstring in __init__ ] +[tool.ruff.format] +# Enable reformatting of code snippets in docstrings. +docstring-code-format = true + [tool.ruff.lint] unfixable = [ "ERA", # do not autoremove commented out code From c62740a3c65eb235c7e25ee20015ad545f167a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 22 Dec 2023 15:40:37 +0100 Subject: [PATCH 16/79] fix: update pre-commit versions --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3464bab..a602928 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,14 +8,14 @@ repos: args: [--unsafe] - repo: https://github.com/compilerla/conventional-pre-commit - rev: v2.3.0 + rev: v3.0.0 hooks: - id: conventional-pre-commit stages: [commit-msg] args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.5 + rev: v0.1.9 hooks: # Run the linter. - id: ruff From ff95fb808afba42a68eecde07a33eef229655236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Sat, 23 Dec 2023 15:42:32 +0100 Subject: [PATCH 17/79] feat: test coverage --- .gitlab/ci/test.yml | 6 +++++- pyproject.toml | 13 ++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/test.yml b/.gitlab/ci/test.yml index 8c89f03..9b1e717 100644 --- a/.gitlab/ci/test.yml +++ b/.gitlab/ci/test.yml @@ -2,11 +2,15 @@ pytest: stage: test script: # Allow pytest to fail with exit code 5 (no tests collected) - - pdm test --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) + - pdm test --cov --cov-report term --cov-report xml:coverage.xml --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) + coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' artifacts: when: always reports: junit: report.xml + coverage_report: + coverage_format: cobertura + path: coverage.xml cache: paths: - .pytest_cache diff --git a/pyproject.toml b/pyproject.toml index 15bfe62..d9c3da4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [] [tool.pdm.dev-dependencies] dev = ["mypy", "pre-commit", "ruff"] -test = ["pytest"] +test = ["pytest", "pytest-cov"] ##################################### @@ -39,6 +39,17 @@ post_install = { composite = [ # Tool configuration ##################################### +[tool.coverage.run] +branch = true +omit = ["tests/*"] +source = ["."] + +[tool.coverage.report] +exclude_also = [ + # Don't complain about abstract methods, they aren't run: + "@(abc\\.)?abstractmethod", +] + [tool.mypy] strict = true ignore_missing_imports = true From 603ab7dbfa5758129be8df6ef7b076af8ed00db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Mon, 25 Dec 2023 14:46:11 +0100 Subject: [PATCH 18/79] feat: allow installing gitlab dependecies in CI/CD --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b3246be..9357c60 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,8 @@ default: before_script: - python --version ; pip --version # For debugging - pip install -q pdm + # allow pdm to install dependencies from gitlab + - git config --global url."https://${DEPLOY_TOKEN_USERNAME}:${DEPLOY_TOKEN_PASSWORD}@gitlab.ics.muni.cz/".insteadOf "ssh://git@gitlab.ics.muni.cz/" - pdm install --no-lock -q --skip=post_install # skip pre-commit hooks # Pip's cache doesn't store the python packages From cdc32c10051953b276808d58efa9d5e4ecb444e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Sat, 6 Jan 2024 18:18:43 +0100 Subject: [PATCH 19/79] chore: ignore mlflow_store --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a42f203..f490645 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,7 @@ cython_debug/ # Mlflow mlruns/ +mlflow_store/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can From 584cdf216c6b423c242a72d933071aa0a75d9228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Fri, 24 May 2024 10:43:04 +0200 Subject: [PATCH 20/79] chore: new libary template --- .gitlab-ci.yml | 33 +--- .gitlab/ci/lint.yml | 24 --- .gitlab/ci/sync.yml | 27 --- .gitlab/ci/test.yml | 18 -- .mypy.ini | 5 + .ruff.toml | 51 +++++ LICENSE | 2 +- README.md | 59 +----- pdm.lock | 362 ++++++++++++++++++++++++++++++++++ pyproject.toml | 87 +------- rationai/staining/__init__.py | 0 11 files changed, 428 insertions(+), 240 deletions(-) delete mode 100644 .gitlab/ci/lint.yml delete mode 100644 .gitlab/ci/sync.yml delete mode 100644 .gitlab/ci/test.yml create mode 100644 .mypy.ini create mode 100644 .ruff.toml create mode 100644 pdm.lock create mode 100644 rationai/staining/__init__.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9357c60..1675c5c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,32 +1,9 @@ -default: - image: python:3.11 - before_script: - - python --version ; pip --version # For debugging - - pip install -q pdm - # allow pdm to install dependencies from gitlab - - git config --global url."https://${DEPLOY_TOKEN_USERNAME}:${DEPLOY_TOKEN_PASSWORD}@gitlab.ics.muni.cz/".insteadOf "ssh://git@gitlab.ics.muni.cz/" - - pdm install --no-lock -q --skip=post_install # skip pre-commit hooks - - # Pip's cache doesn't store the python packages - # https://pip.pypa.io/en/stable/topics/caching/ - cache: - paths: - - .cache/pip - - .venv - -# Change pip's cache directory to be inside the project directory since we can -# only cache local items. -variables: - PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" +include: + project: rationai/digital-pathology/templates/ci-templates + file: + - Pytest.gitlab-ci.yml + - Python-Lint.gitlab-ci.yml stages: - lint - test - -# Runs jobs only in merge request pipelines -.merge_request_pipelines: - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - -include: .gitlab/ci/*.yml diff --git a/.gitlab/ci/lint.yml b/.gitlab/ci/lint.yml deleted file mode 100644 index 618a148..0000000 --- a/.gitlab/ci/lint.yml +++ /dev/null @@ -1,24 +0,0 @@ -ruff-lint: - stage: lint - script: - - pdm lint - rules: - - !reference [.merge_request_pipelines, rules] - -ruff-format: - stage: lint - script: - - pdm format --check - rules: - - !reference [.merge_request_pipelines, rules] - -mypy: - stage: lint - allow_failure: true - script: - - pdm mypy - cache: - paths: - - .mypy_cache - rules: - - !reference [.merge_request_pipelines, rules] diff --git a/.gitlab/ci/sync.yml b/.gitlab/ci/sync.yml deleted file mode 100644 index 3094fd8..0000000 --- a/.gitlab/ci/sync.yml +++ /dev/null @@ -1,27 +0,0 @@ -sync: - image: bitnami/git - variables: - TEMPLATE_CI_BRANCH: "ci/template" - NAME: "🤖 Template Bot 🤖" - USER_NAME: "group_1021_bot_62f237df79b4aaf1aeeb93687a941fbb" - USER_EMAIL: "group_1021_bot_62f237df79b4aaf1aeeb93687a941fbb@noreply.gitlab.ics.muni.cz" - TEMPLATE_REPO: https://${USER_NAME}:${GROUP_ACCESS_TOKEN_TEMPLATE_BOT_RW}@gitlab.ics.muni.cz/rationai/digital-pathology/templates/python.git - COMMIT_MESSAGE: "ci: sync with template repository" - MERGE_REQUEST_TITLE: "ci: automated MR from Template" - before_script: - - git config --global user.name "${NAME}" - - git config --global user.email "${USER_EMAIL}" - script: - - git pull "${TEMPLATE_REPO}" --no-rebase --allow-unrelated-histories --no-commit -X theirs - - > - if ! git diff --cached --quiet; then - echo "📂 Files that will be commited:" - git diff --cached --name-only - - git commit -m "${COMMIT_MESSAGE}" - git push "https://${USER_NAME}:${GROUP_ACCESS_TOKEN_TEMPLATE_BOT_RW}@${CI_REPOSITORY_URL#*@}" HEAD:$CI_COMMIT_REF_NAME \ - -o merge_request.create -o merge_request.target=${CI_DEFAULT_BRANCH} -o merge_request.remove_source_branch -o merge_request.title="${MERGE_REQUEST_TITLE}" - fi - rules: - - if: $CI_COMMIT_BRANCH == $TEMPLATE_CI_BRANCH && $CI_PIPELINE_SOURCE == 'schedule' - cache: {} diff --git a/.gitlab/ci/test.yml b/.gitlab/ci/test.yml deleted file mode 100644 index 9b1e717..0000000 --- a/.gitlab/ci/test.yml +++ /dev/null @@ -1,18 +0,0 @@ -pytest: - stage: test - script: - # Allow pytest to fail with exit code 5 (no tests collected) - - pdm test --cov --cov-report term --cov-report xml:coverage.xml --junitxml=report.xml || ( exit_code=$?; [ $exit_code -eq 5 ] && exit 0 || exit $exit_code ) - coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' - artifacts: - when: always - reports: - junit: report.xml - coverage_report: - coverage_format: cobertura - path: coverage.xml - cache: - paths: - - .pytest_cache - rules: - - !reference [.merge_request_pipelines, rules] diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..1c6f44e --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,5 @@ +[mypy] +strict = True +ignore_missing_imports = True +disallow_untyped_calls = False +disable_error_code = no-any-return \ No newline at end of file diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..fb5e992 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,51 @@ +fix = true +line-length = 88 +target-version = "py311" + +[format] +# Enable reformatting of code snippets in docstrings. +docstring-code-format = true + +[lint] +unfixable = [ + "ERA", # do not autoremove commented out code +] +extend-select = [ + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "ERA", # flake8-eradicate/eradicate + "I", # isort + "N", # pep8-naming + "PIE", # flake8-pie + "PGH", # pygrep + "RUF", # ruff checks + "SIM", # flake8-simplify + "TCH", # flake8-type-checking + "TID", # flake8-tidy-imports + "UP", # pyupgrade + "D", # pydocstyle +] +extend-ignore = [ + "ERA001", # commented out code + "D100", # missing docstring in public module + "D101", # missing docstring in public class + "D102", # missing docstring in public method + "D103", # missing docstring in public function + "D104", # missing docstring in public package + "D105", # missing docstring in magic method + "D106", # missing docstring in public nested class + "D107", # missing docstring in __init__ + "N812", # lowercase imported as non lowercase + "TCH002", # move third-party into a type-checking block + "F722", # jaxtyping +] + +[lint.flake8-tidy-imports] +ban-relative-imports = "all" + +[lint.isort] +lines-after-imports = 2 +known-first-party = ["tests"] + +[lint.pydocstyle] +convention = "google" diff --git a/LICENSE b/LICENSE index caebf45..1ee08b6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 RationAI +Copyright (c) 2024 RationAI Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index cd979cd..e79c243 100644 --- a/README.md +++ b/README.md @@ -1,58 +1 @@ -# Python project template - -This project template serves as a robust foundation for Python projects, promoting best practices and streamlining development workflows. It comes preconfigured with essential tools and features to enhance the development experience. - -## Tools Included - -- [PDM](https://pdm-project.org) for efficient dependency management. -- [Ruff](https://docs.astral.sh/ruff) for comprehensive linting and code formatting. -- [Pytest](https://docs.pytest.org) for running tests and ensuring code reliability. -- [pre-commit](https://pre-commit.com) for managing pre-commit git hooks ([Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), ruff check, ruff format) -- [GitLab CI/CD](https://docs.gitlab.com/ee/ci) for continuous integration. -- [Pylint](https://pylint.readthedocs.io) for static code analysis, adhering to the [Google style](https://google.github.io/styleguide/pyguide.html). -- [Pydocstyle](https://www.pydocstyle.org) for validating docstring styles, also following the [Google style](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings). -- [Mypy](https://mypy-lang.org) for static type checking. - - -## Usage - -Key commands for effective project management: - -- `pdm install` - Installs all project dependencies. -- `pdm add ` - Adds a new dependency to the project. -- `pdm l` - Runs linting, formatting, and mypy checks. -- `pdm test` - Executes tests located in the tests directory. -- `pdm run ` - Runs the specified command within the virtual environment. - -## CI/CD - -Two defined pipelines enhance project development: - -1. **Synchronization pipeline(`ci/template` branch):** - - Triggered by a scheduler for the ci/template branch. - - Handles [synchronization](#synchronizing-the-template) with the template repository. - -2. **Project Pipeline (Main branch and Merge Requests):** - - Triggered by any push to the main branch or any merge request to the main branch. - - Consists of the following stages: - - `lint` - Runs linting, formatting, and mypy checks (ruff check, ruff format, mypy). - - `test` - Executes tests using Pytest. - - -## Synchronizing the Template - -For seamless integration with the template repository: - -1. Create a protected branch named `ci/template`. -2. [Schedule a pipeline](https://docs.gitlab.com/ee/ci/pipelines/schedules.html) for the `ci/template` branch to automatically synchronize with the template repository. -3. Ensure the `ci/template` branch tracks the last synchronized commit. -4. The synchronization pipeline will: - - Check out the last synchronized commit. - - Merge the latest commit from the template repository, prioritizing template changes in case of conflicts. - - Commit and push the changes to the `ci/template` branch. - - Create a merge request to the default branch. - - - -> **Note:** -> Resolve any conflicts manually, ensuring the **last synchronized commit** is retained in the ci/template branch to prevent reappearing conflicts during subsequent synchronizations. +# Staining \ No newline at end of file diff --git a/pdm.lock b/pdm.lock new file mode 100644 index 0000000..e37f981 --- /dev/null +++ b/pdm.lock @@ -0,0 +1,362 @@ +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "dev", "test"] +strategy = ["cross_platform", "inherit_metadata"] +lock_version = "4.4.1" +content_hash = "sha256:a47116b50eb36761e82c588a7bd1e9db7d133253b95d0a734e324389a42b7b90" + +[[package]] +name = "cfgv" +version = "3.4.0" +requires_python = ">=3.8" +summary = "Validate configuration and produce human readable error messages." +groups = ["dev"] +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["test"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.5.1" +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +groups = ["test"] +files = [ + {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, + {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, + {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, + {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, + {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, + {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, + {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, +] + +[[package]] +name = "coverage" +version = "7.5.1" +extras = ["toml"] +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +groups = ["test"] +dependencies = [ + "coverage==7.5.1", +] +files = [ + {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, + {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, + {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, + {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, + {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, + {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, + {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, +] + +[[package]] +name = "distlib" +version = "0.3.8" +summary = "Distribution utilities" +groups = ["dev"] +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[[package]] +name = "filelock" +version = "3.14.0" +requires_python = ">=3.8" +summary = "A platform independent file lock." +groups = ["dev"] +files = [ + {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, + {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, +] + +[[package]] +name = "identify" +version = "2.5.36" +requires_python = ">=3.8" +summary = "File identification library for Python" +groups = ["dev"] +files = [ + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" +groups = ["test"] +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "mypy" +version = "1.10.0" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +groups = ["dev"] +dependencies = [ + "mypy-extensions>=1.0.0", + "typing-extensions>=4.1.0", +] +files = [ + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +summary = "Node.js virtual environment builder" +groups = ["dev"] +dependencies = [ + "setuptools", +] +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[[package]] +name = "packaging" +version = "24.0" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" +groups = ["test"] +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["dev"] +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" +groups = ["test"] +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[[package]] +name = "pre-commit" +version = "3.7.1" +requires_python = ">=3.9" +summary = "A framework for managing and maintaining multi-language pre-commit hooks." +groups = ["dev"] +dependencies = [ + "cfgv>=2.0.0", + "identify>=1.0.0", + "nodeenv>=0.11.1", + "pyyaml>=5.1", + "virtualenv>=20.10.0", +] +files = [ + {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, + {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, +] + +[[package]] +name = "pytest" +version = "8.2.1" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +groups = ["test"] +dependencies = [ + "colorama; sys_platform == \"win32\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=1.5", +] +files = [ + {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, + {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, +] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +requires_python = ">=3.8" +summary = "Pytest plugin for measuring coverage." +groups = ["test"] +dependencies = [ + "coverage[toml]>=5.2.1", + "pytest>=4.6", +] +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +requires_python = ">=3.6" +summary = "YAML parser and emitter for Python" +groups = ["dev"] +files = [ + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "ruff" +version = "0.4.5" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["dev"] +files = [ + {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, + {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, + {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, + {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, + {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, + {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, + {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, + {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, +] + +[[package]] +name = "setuptools" +version = "70.0.0" +requires_python = ">=3.8" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" +groups = ["dev"] +files = [ + {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, + {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.0" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["dev"] +files = [ + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, +] + +[[package]] +name = "virtualenv" +version = "20.26.2" +requires_python = ">=3.7" +summary = "Virtual Python Environment builder" +groups = ["dev"] +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.12.2", + "platformdirs<5,>=3.9.1", +] +files = [ + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, +] diff --git a/pyproject.toml b/pyproject.toml index d9c3da4..309b89a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,105 +1,24 @@ [project] -name = "" +name = "rationai-staining" version = "0.1.0" description = "" authors = [] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } - - -##################################### -# Dependencies -##################################### - dependencies = [] [tool.pdm.dev-dependencies] dev = ["mypy", "pre-commit", "ruff"] test = ["pytest", "pytest-cov"] - -##################################### -# Scripts -##################################### - [tool.pdm.scripts] l = { composite = ["lint", "format", "mypy"] } test = "pytest tests" -lint = "ruff check ." -format = "ruff format ." +lint = "ruff check" +format = "ruff format" mypy = "mypy ." post_install = { composite = [ "pre-commit install", "pre-commit install --hook-type commit-msg", ] } - - -##################################### -# Tool configuration -##################################### - -[tool.coverage.run] -branch = true -omit = ["tests/*"] -source = ["."] - -[tool.coverage.report] -exclude_also = [ - # Don't complain about abstract methods, they aren't run: - "@(abc\\.)?abstractmethod", -] - -[tool.mypy] -strict = true -ignore_missing_imports = true - -[tool.ruff] -fix = true -line-length = 88 -target-version = "py311" -extend-ignore = [ - "ERA001", # commented out code - "D100", # missing docstring in public module - "D101", # missing docstring in public class - "D102", # missing docstring in public method - "D103", # missing docstring in public function - "D104", # missing docstring in public package - "D105", # missing docstring in magic method - "D106", # missing docstring in public nested class - "D107", # missing docstring in __init__ -] - -[tool.ruff.format] -# Enable reformatting of code snippets in docstrings. -docstring-code-format = true - -[tool.ruff.lint] -unfixable = [ - "ERA", # do not autoremove commented out code -] -extend-select = [ - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "ERA", # flake8-eradicate/eradicate - "I", # isort - "N", # pep8-naming - "PIE", # flake8-pie - "PGH", # pygrep - "RUF", # ruff checks - "SIM", # flake8-simplify - "TCH", # flake8-type-checking - "TID", # flake8-tidy-imports - "UP", # pyupgrade - "D", # pydocstyle -] - -[tool.ruff.lint.flake8-tidy-imports] -ban-relative-imports = "all" - -[tool.ruff.lint.isort] -lines-after-imports = 2 -known-first-party = ["tests"] - -[tool.ruff.lint.pydocstyle] -convention = "google" diff --git a/rationai/staining/__init__.py b/rationai/staining/__init__.py new file mode 100644 index 0000000..e69de29 From 168b7957966b639e18c08f5d4a00df225a692b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Bal=C3=A1k?= <525126@mail.muni.cz> Date: Sat, 17 Aug 2024 14:50:24 +0200 Subject: [PATCH 21/79] feat: routines for separating and combining stain channels, and stain estimation --- .gitlab-ci.yml | 2 + .mypy.ini | 3 +- .pre-commit-config.yaml | 13 +- README.md | 4 +- docs/index.md | 1 + docs/installation.md | 13 + docs/reference/color-conversion.md | 1 + docs/reference/constants.md | 1 + docs/reference/estimate-stain-vectors.md | 1 + docs/reference/index.md | 4 + docs/reference/typing.md | 1 + mkdocs.yml | 68 +++ pdm.lock | 510 ++++++++++++++------ pyproject.toml | 13 +- pytest.ini | 6 + rationai/staining/__init__.py | 14 + rationai/staining/constants.py | 14 + rationai/staining/convert_color.py | 135 ++++++ rationai/staining/estimate_stain_vectors.py | 63 +++ rationai/staining/typing.py | 36 ++ rationai/staining/utils/__init__.py | 6 + rationai/staining/utils/inv_mat.py | 8 + rationai/staining/utils/normalize.py | 9 + rationai/staining/utils/residual.py | 12 + tests/__init__.py | 0 tests/conftest.py | 42 ++ tests/data/generated/h_dab.jpg | Bin 0 -> 43338 bytes tests/data/generated/h_e.jpg | Bin 0 -> 42565 bytes tests/data/sample1/eosin.png | Bin 0 -> 183161 bytes tests/data/sample1/hematoxylin.png | Bin 0 -> 203258 bytes tests/data/sample1/original.jpg | Bin 0 -> 83398 bytes tests/data/sample1/residual.png | Bin 0 -> 79895 bytes tests/scripts/generate_artifical_tissue.py | 68 +++ tests/test_color_conversion.py | 31 ++ tests/test_stain_estimator.py | 105 ++++ tests/test_stain_reconstruction.py | 40 ++ tests/test_stain_separation.py | 52 ++ 37 files changed, 1127 insertions(+), 149 deletions(-) create mode 100644 docs/index.md create mode 100644 docs/installation.md create mode 100644 docs/reference/color-conversion.md create mode 100644 docs/reference/constants.md create mode 100644 docs/reference/estimate-stain-vectors.md create mode 100644 docs/reference/index.md create mode 100644 docs/reference/typing.md create mode 100644 mkdocs.yml create mode 100644 pytest.ini create mode 100644 rationai/staining/constants.py create mode 100644 rationai/staining/convert_color.py create mode 100644 rationai/staining/estimate_stain_vectors.py create mode 100644 rationai/staining/typing.py create mode 100644 rationai/staining/utils/__init__.py create mode 100644 rationai/staining/utils/inv_mat.py create mode 100644 rationai/staining/utils/normalize.py create mode 100644 rationai/staining/utils/residual.py delete mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/data/generated/h_dab.jpg create mode 100644 tests/data/generated/h_e.jpg create mode 100644 tests/data/sample1/eosin.png create mode 100644 tests/data/sample1/hematoxylin.png create mode 100644 tests/data/sample1/original.jpg create mode 100644 tests/data/sample1/residual.png create mode 100644 tests/scripts/generate_artifical_tissue.py create mode 100644 tests/test_color_conversion.py create mode 100644 tests/test_stain_estimator.py create mode 100644 tests/test_stain_reconstruction.py create mode 100644 tests/test_stain_separation.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1675c5c..9d40d40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,9 @@ include: file: - Pytest.gitlab-ci.yml - Python-Lint.gitlab-ci.yml + - MkDocs.gitlab-ci.yml stages: - lint - test + - deploy diff --git a/.mypy.ini b/.mypy.ini index 1c6f44e..8d15f3c 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -2,4 +2,5 @@ strict = True ignore_missing_imports = True disallow_untyped_calls = False -disable_error_code = no-any-return \ No newline at end of file +disable_error_code = no-any-return +explicit_package_bases = True \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a602928..83fa055 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,25 +2,24 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-yaml args: [--unsafe] - repo: https://github.com/compilerla/conventional-pre-commit - rev: v3.0.0 + rev: v3.4.0 hooks: - id: conventional-pre-commit stages: [commit-msg] args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 + rev: v0.6.1 hooks: # Run the linter. - id: ruff - types_or: [python, pyi, jupyter] - args: [--fix] - # Run the formatter. + entry: pdm lint --force-exclude + # Run the formatter. - id: ruff-format - types_or: [python, pyi, jupyter] + entry: pdm format --force-exclude diff --git a/README.md b/README.md index e79c243..1328bc6 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# Staining \ No newline at end of file +# Staining + +[[`Documentation`](https://rationai.gitlab-pages.ics.muni.cz/digital-pathology/libraries/staining)] \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..00dd3b4 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +Staining library \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..15a16f7 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,13 @@ +# Installation + +=== "pip" + + ```bash + pip install git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git + ``` + +=== "pdm" + + ```bash + pdm add git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git + ``` diff --git a/docs/reference/color-conversion.md b/docs/reference/color-conversion.md new file mode 100644 index 0000000..43b6952 --- /dev/null +++ b/docs/reference/color-conversion.md @@ -0,0 +1 @@ +::: rationai.staining.convert_color \ No newline at end of file diff --git a/docs/reference/constants.md b/docs/reference/constants.md new file mode 100644 index 0000000..616707f --- /dev/null +++ b/docs/reference/constants.md @@ -0,0 +1 @@ +::: rationai.staining.constants diff --git a/docs/reference/estimate-stain-vectors.md b/docs/reference/estimate-stain-vectors.md new file mode 100644 index 0000000..520ea02 --- /dev/null +++ b/docs/reference/estimate-stain-vectors.md @@ -0,0 +1 @@ +::: rationai.staining.estimate_stain_vectors \ No newline at end of file diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 0000000..47a1bf1 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,4 @@ +# Reference + +Here's the reference or code API, the classes, functions, parameters, attributes, and +all the `rationai-staining` parts you can use in your applications. \ No newline at end of file diff --git a/docs/reference/typing.md b/docs/reference/typing.md new file mode 100644 index 0000000..36b0bbe --- /dev/null +++ b/docs/reference/typing.md @@ -0,0 +1 @@ +::: rationai.staining.typing \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..7df5f07 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,68 @@ +site_name: Staining + +nav: + - Home: index.md + - Getting Started: + - Installation: installation.md + - Reference: + - reference/index.md + - reference/color-conversion.md + - reference/estimate-stain-vectors.md + - reference/constants.md + - reference/typing.md + +theme: + name: material + features: + - announce.dismiss + - content.action.edit + - content.action.view + - content.code.annotate + - content.code.copy + - content.tooltips + - navigation.indexes + - navigation.sections + - navigation.top + - navigation.tabs + - navigation.footer + - navigation.tracking + - search.highlight + - search.share + - search.suggest + - toc.follow + palette: + - media: "(prefers-color-scheme)" + toggle: + icon: material/link + name: Switch to light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/toggle-switch + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: black + accent: indigo + toggle: + icon: material/toggle-switch-off + name: Switch to system preference + +plugins: + - search + - mkdocstrings + +markdown_extensions: + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + combine_header_slug: true + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower diff --git a/pdm.lock b/pdm.lock index e37f981..e698408 100644 --- a/pdm.lock +++ b/pdm.lock @@ -3,9 +3,12 @@ [metadata] groups = ["default", "dev", "test"] -strategy = ["cross_platform", "inherit_metadata"] -lock_version = "4.4.1" -content_hash = "sha256:a47116b50eb36761e82c588a7bd1e9db7d133253b95d0a734e324389a42b7b90" +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:a7dd9cc2a5c546a0337b5d1b9ab80d4197f0e484eeb9bbd3c3dcad0709af7758" + +[[metadata.targets]] +requires_python = ">=3.11" [[package]] name = "cfgv" @@ -32,68 +35,107 @@ files = [ [[package]] name = "coverage" -version = "7.5.1" +version = "7.6.1" requires_python = ">=3.8" summary = "Code coverage measurement for Python" groups = ["test"] files = [ - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [[package]] name = "coverage" -version = "7.5.1" +version = "7.6.1" extras = ["toml"] requires_python = ">=3.8" summary = "Code coverage measurement for Python" groups = ["test"] dependencies = [ - "coverage==7.5.1", + "coverage==7.6.1", + "tomli; python_full_version <= \"3.11.0a6\"", ] files = [ - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [[package]] @@ -108,24 +150,39 @@ files = [ [[package]] name = "filelock" -version = "3.14.0" +version = "3.15.4" requires_python = ">=3.8" summary = "A platform independent file lock." groups = ["dev"] files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [[package]] name = "identify" -version = "2.5.36" +version = "2.6.0" requires_python = ">=3.8" summary = "File identification library for Python" groups = ["dev"] files = [ - {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, + {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, + {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, +] + +[[package]] +name = "imageio" +version = "2.35.0" +requires_python = ">=3.8" +summary = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." +groups = ["default"] +dependencies = [ + "numpy<2.0.0", + "pillow>=8.3.2", +] +files = [ + {file = "imageio-2.35.0-py3-none-any.whl", hash = "sha256:ebfb39c0ad7acf93750d7ee151664238aaa9208f202288ea6f3ca7cb0ed719c3"}, + {file = "imageio-2.35.0.tar.gz", hash = "sha256:e88f759803d2968e19a55fa8372e9fbe12967a8598fe042d8719ca46d03f4256"}, ] [[package]] @@ -139,29 +196,45 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "lazy-loader" +version = "0.4" +requires_python = ">=3.7" +summary = "Makes it easy to load subpackages and functions on demand." +groups = ["default"] +dependencies = [ + "importlib-metadata; python_version < \"3.8\"", + "packaging", +] +files = [ + {file = "lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"}, + {file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"}, +] + [[package]] name = "mypy" -version = "1.10.0" +version = "1.11.1" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["dev"] dependencies = [ "mypy-extensions>=1.0.0", - "typing-extensions>=4.1.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, - {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, - {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, - {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, - {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, - {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, - {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, - {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, - {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, - {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, - {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, + {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, + {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, + {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, + {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, + {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, + {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, + {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, + {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, ] [[package]] @@ -175,29 +248,116 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "networkx" +version = "3.3" +requires_python = ">=3.10" +summary = "Python package for creating and manipulating graphs and networks" +groups = ["default"] +files = [ + {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, + {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, +] + [[package]] name = "nodeenv" -version = "1.8.0" -requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +version = "1.9.1" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Node.js virtual environment builder" groups = ["dev"] -dependencies = [ - "setuptools", +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] + +[[package]] +name = "numpy" +version = "1.26.4" +requires_python = ">=3.9" +summary = "Fundamental package for array computing in Python" +groups = ["default"] files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "packaging" -version = "24.0" -requires_python = ">=3.7" +version = "24.1" +requires_python = ">=3.8" summary = "Core utilities for Python packages" +groups = ["default", "test"] +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "perlin-noise" +version = "1.13" +summary = "Python implementation for Perlin Noise with unlimited coordinates space" groups = ["test"] files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "perlin_noise-1.13-py3-none-any.whl", hash = "sha256:09f274c8da38f5a2a48b1626032a1b7738990df758a3bc7549ff3464869c6ca4"}, + {file = "perlin_noise-1.13.tar.gz", hash = "sha256:0e0f074743336fbe9cf2cdbdeb74c75d43780a8b3cbc3415859cd396ab4da177"}, +] + +[[package]] +name = "pillow" +version = "10.4.0" +requires_python = ">=3.8" +summary = "Python Imaging Library (Fork)" +groups = ["default"] +files = [ + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, ] [[package]] @@ -224,7 +384,7 @@ files = [ [[package]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" requires_python = ">=3.9" summary = "A framework for managing and maintaining multi-language pre-commit hooks." groups = ["dev"] @@ -236,25 +396,27 @@ dependencies = [ "virtualenv>=20.10.0", ] files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [[package]] name = "pytest" -version = "8.2.1" +version = "8.3.2" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" groups = ["test"] dependencies = [ "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", "iniconfig", "packaging", - "pluggy<2.0,>=1.5", + "pluggy<2,>=1.5", + "tomli>=1; python_version < \"3.11\"", ] files = [ - {file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, - {file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, + {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, + {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, ] [[package]] @@ -274,89 +436,165 @@ files = [ [[package]] name = "pyyaml" -version = "6.0.1" -requires_python = ">=3.6" +version = "6.0.2" +requires_python = ">=3.8" summary = "YAML parser and emitter for Python" groups = ["dev"] files = [ - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "ruff" -version = "0.4.5" +version = "0.6.1" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev"] files = [ - {file = "ruff-0.4.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8f58e615dec58b1a6b291769b559e12fdffb53cc4187160a2fc83250eaf54e96"}, - {file = "ruff-0.4.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84dd157474e16e3a82745d2afa1016c17d27cb5d52b12e3d45d418bcc6d49264"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f483ad9d50b00e7fd577f6d0305aa18494c6af139bce7319c68a17180087f4"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:63fde3bf6f3ad4e990357af1d30e8ba2730860a954ea9282c95fc0846f5f64af"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e3ba4620dee27f76bbcad97067766026c918ba0f2d035c2fc25cbdd04d9c97"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:441dab55c568e38d02bbda68a926a3d0b54f5510095c9de7f95e47a39e0168aa"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1169e47e9c4136c997f08f9857ae889d614c5035d87d38fda9b44b4338909cdf"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:755ac9ac2598a941512fc36a9070a13c88d72ff874a9781493eb237ab02d75df"}, - {file = "ruff-0.4.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4b02a65985be2b34b170025a8b92449088ce61e33e69956ce4d316c0fe7cce0"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:75a426506a183d9201e7e5664de3f6b414ad3850d7625764106f7b6d0486f0a1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6e1b139b45e2911419044237d90b60e472f57285950e1492c757dfc88259bb06"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6f29a8221d2e3d85ff0c7b4371c0e37b39c87732c969b4d90f3dad2e721c5b1"}, - {file = "ruff-0.4.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d6ef817124d72b54cc923f3444828ba24fa45c3164bc9e8f1813db2f3d3a8a11"}, - {file = "ruff-0.4.5-py3-none-win32.whl", hash = "sha256:aed8166c18b1a169a5d3ec28a49b43340949e400665555b51ee06f22813ef062"}, - {file = "ruff-0.4.5-py3-none-win_amd64.whl", hash = "sha256:b0b03c619d2b4350b4a27e34fd2ac64d0dabe1afbf43de57d0f9d8a05ecffa45"}, - {file = "ruff-0.4.5-py3-none-win_arm64.whl", hash = "sha256:9d15de3425f53161b3f5a5658d4522e4eee5ea002bf2ac7aa380743dd9ad5fba"}, - {file = "ruff-0.4.5.tar.gz", hash = "sha256:286eabd47e7d4d521d199cab84deca135557e6d1e0f0d01c29e757c3cb151b54"}, + {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, + {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, + {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, + {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, + {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, + {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, + {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, + {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, + {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, ] [[package]] -name = "setuptools" -version = "70.0.0" -requires_python = ">=3.8" -summary = "Easily download, build, install, upgrade, and uninstall Python packages" -groups = ["dev"] +name = "scikit-image" +version = "0.24.0" +requires_python = ">=3.9" +summary = "Image processing in Python" +groups = ["default"] +dependencies = [ + "imageio>=2.33", + "lazy-loader>=0.4", + "networkx>=2.8", + "numpy>=1.23", + "packaging>=21", + "pillow>=9.1", + "scipy>=1.9", + "tifffile>=2022.8.12", +] +files = [ + {file = "scikit_image-0.24.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:272909e02a59cea3ed4aa03739bb88df2625daa809f633f40b5053cf09241831"}, + {file = "scikit_image-0.24.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:190ebde80b4470fe8838764b9b15f232a964f1a20391663e31008d76f0c696f7"}, + {file = "scikit_image-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c98cc695005faf2b79904e4663796c977af22586ddf1b12d6af2fa22842dc2"}, + {file = "scikit_image-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa27b3a0dbad807b966b8db2d78da734cb812ca4787f7fbb143764800ce2fa9c"}, + {file = "scikit_image-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:dacf591ac0c272a111181afad4b788a27fe70d213cfddd631d151cbc34f8ca2c"}, + {file = "scikit_image-0.24.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6fccceb54c9574590abcddc8caf6cefa57c13b5b8b4260ab3ff88ad8f3c252b3"}, + {file = "scikit_image-0.24.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ccc01e4760d655aab7601c1ba7aa4ddd8b46f494ac46ec9c268df6f33ccddf4c"}, + {file = "scikit_image-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18836a18d3a7b6aca5376a2d805f0045826bc6c9fc85331659c33b4813e0b563"}, + {file = "scikit_image-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8579bda9c3f78cb3b3ed8b9425213c53a25fa7e994b7ac01f2440b395babf660"}, + {file = "scikit_image-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:82ab903afa60b2da1da2e6f0c8c65e7c8868c60a869464c41971da929b3e82bc"}, + {file = "scikit_image-0.24.0.tar.gz", hash = "sha256:5d16efe95da8edbeb363e0c4157b99becbd650a60b77f6e3af5768b66cf007ab"}, +] + +[[package]] +name = "scipy" +version = "1.14.0" +requires_python = ">=3.10" +summary = "Fundamental algorithms for scientific computing in Python" +groups = ["default"] +dependencies = [ + "numpy<2.3,>=1.23.5", +] +files = [ + {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, + {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, + {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, + {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, + {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, + {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, +] + +[[package]] +name = "tifffile" +version = "2024.8.10" +requires_python = ">=3.9" +summary = "Read and write TIFF files" +groups = ["default"] +dependencies = [ + "numpy", +] files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "tifffile-2024.8.10-py3-none-any.whl", hash = "sha256:1c224564fa92e7e9f9a0ed65880b2ece97c3f0d10029ffbebfa5e62b3f6b343d"}, + {file = "tifffile-2024.8.10.tar.gz", hash = "sha256:fdc12124f1478a07b1524641dc6b50cf6bde0483011a63fd2a773094090c3dcf"}, ] [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" groups = ["dev"] files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "virtualenv" -version = "20.26.2" +version = "20.26.3" requires_python = ">=3.7" summary = "Virtual Python Environment builder" groups = ["dev"] dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", + "importlib-metadata>=6.6; python_version < \"3.8\"", "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, - {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] diff --git a/pyproject.toml b/pyproject.toml index 309b89a..2291c91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,23 +2,28 @@ name = "rationai-staining" version = "0.1.0" description = "" -authors = [] +authors = [{ name = "Tomáš Balák" }] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } -dependencies = [] +dependencies = [ + "numpy>=1.26.4", + "pillow>=10.3.0", + "scikit-image>=0.23.2", +] [tool.pdm.dev-dependencies] dev = ["mypy", "pre-commit", "ruff"] -test = ["pytest", "pytest-cov"] +test = ["pytest", "pytest-cov", "perlin-noise>=1.12"] [tool.pdm.scripts] l = { composite = ["lint", "format", "mypy"] } test = "pytest tests" -lint = "ruff check" +lint = "ruff check --fix" format = "ruff format" mypy = "mypy ." post_install = { composite = [ + "pre-commit autoupdate", "pre-commit install", "pre-commit install --hook-type commit-msg", ] } diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..276b351 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,6 @@ +[pytest] +markers = + color_conversion: tests expected values and method behavior of the ColorConversion Enum + stain_separation: tests expected behavior of the stain separation functionality + stain_reconstruction: tests that applying color combination after color separation return yields roughly the same image + stain_estimator: tests stain estimation functionality \ No newline at end of file diff --git a/rationai/staining/__init__.py b/rationai/staining/__init__.py index e69de29..e71fe94 100644 --- a/rationai/staining/__init__.py +++ b/rationai/staining/__init__.py @@ -0,0 +1,14 @@ +from rationai.staining.convert_color import ( + ColorConversion, + ConversionType, + convert_color, +) +from rationai.staining.estimate_stain_vectors import estimate_stain_vectors + + +__all__ = [ + "ColorConversion", + "ConversionType", + "convert_color", + "estimate_stain_vectors", +] diff --git a/rationai/staining/constants.py b/rationai/staining/constants.py new file mode 100644 index 0000000..6e26e51 --- /dev/null +++ b/rationai/staining/constants.py @@ -0,0 +1,14 @@ +QUPATH_H = (0.651, 0.701, 0.290) +""" +QuPath value for default Hematoxylin staining vector. +""" + +QUPATH_E = (0.216, 0.801, 0.558) +""" +QuPath value for default Eosin staining vector. +""" + +QUPATH_DAB = (0.269, 0.568, 0.778) +""" +QuPath value for default DAB staining vector. +""" diff --git a/rationai/staining/convert_color.py b/rationai/staining/convert_color.py new file mode 100644 index 0000000..5ae45da --- /dev/null +++ b/rationai/staining/convert_color.py @@ -0,0 +1,135 @@ +from enum import Enum, auto, unique +from typing import overload + +import numpy as np +from PIL.Image import Image +from skimage.color import combine_stains, separate_stains + +from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.typing import ( + RGBArray, + StainArray, +) +from rationai.staining.utils import inv_mat, residual + + +@unique +class ConversionType(Enum): + """Enum representing different types of conversions.""" + + STAIN2RGB = auto() + RGB2STAIN = auto() + + +@unique +class ColorConversion(Enum): + """Enum representing different color conversions. + + Value of the enum is a tuple with deconvolution matrix and + the type of the conversion. + + Note: + Stain channels are denoted by their first letters + (H for hematoxylin, D for DAB, ...) and residual channel + is denoted by the letter R. + """ + + HER2RGB = ( + (QUPATH_H, QUPATH_E, residual(QUPATH_H, QUPATH_E)), + ConversionType.STAIN2RGB, + ) + """**Combines** `Hematoxylin`, `Eosin` and `Residual` channels **to RGB**.""" + + HDR2RGB = ( + (QUPATH_H, QUPATH_DAB, residual(QUPATH_H, QUPATH_DAB)), + ConversionType.STAIN2RGB, + ) + """**Combines** `Hematoxylin`, `DAB` and `Residual` channels **to RGB**.""" + + RGB2HER = (inv_mat(HER2RGB[0]), ConversionType.RGB2STAIN) + """**Separates RGB image** into `Hematoxylin`, `Eosin` and `Residual` channels.""" + + RGB2HDR = (inv_mat(HDR2RGB[0]), ConversionType.RGB2STAIN) + """**Separates RGB image** into `Hematoxylin`, `DAB` and `Residual` channels.""" + + @property + def conv_type(self) -> ConversionType: + """Returns conversion type associated with the color conversion. + + Returns: + Conversion type associated with the color conversion. + """ + return self.value[1] + + @property + def matrix(self) -> StainArray: + """Returns the real form of the color deconvolution matrix. + + Returns: + Deconvolution matrix (3x3) represented by the color conversion + as a numpy array. + """ + return np.stack(self.value[0]) + + @property + def inverse(self) -> "ColorConversion": + """Returns the inverse color conversion. + + Returns: + Inverse color conversion (i. e., RGB2HER is inverse to HER2RGB). + """ + match self: + case ColorConversion.RGB2HER: + return ColorConversion.HER2RGB + case ColorConversion.RGB2HDR: + return ColorConversion.HDR2RGB + case ColorConversion.HER2RGB: + return ColorConversion.RGB2HER + case ColorConversion.HDR2RGB: + return ColorConversion.RGB2HDR + + +@overload +def convert_color( + tile: RGBArray | Image, conversion: ColorConversion +) -> tuple[StainArray, ...]: ... + + +@overload +def convert_color(tile: StainArray, conversion: ColorConversion) -> RGBArray: ... + + +def convert_color( + tile: RGBArray | StainArray | Image, conversion: ColorConversion +) -> RGBArray | tuple[StainArray, ...]: + """Converts a tile into the specified color space. + + Based on the provided conversion enum, either color deconvolution + or stain channel combination is performed. + + Note: + Due to implementation details, it is **NOT GUARANTEED** that + `convert_tile(convert_tile(I, conv), conv.inverse) == I`. Difference between the + images can also vary depending on the used conversion. + + Args: + tile: Tile that should be converted. Can either be a RGB image or three stain + channels stacked along the last axis. Stain channels can be stacked using + the following code: + >>> stacked_stains = np.stack([c0, c1, c2], axis=-1) + + Here, `c[0-2]` are the individual stain channels. + + conversion: Desired color conversion. + + Returns: + Depending on the conversion, the result can either be a RGB image, + or a tuple of the separated stain channels. + """ + match conversion.conv_type: + case ConversionType.RGB2STAIN: + return tuple(np.moveaxis(separate_stains(tile, conversion.matrix), -1, 0)) + + case ConversionType.STAIN2RGB: + tile = np.asarray(tile, dtype=np.float64) + return (255 * combine_stains(tile, conversion.matrix)).astype(np.uint8) diff --git a/rationai/staining/estimate_stain_vectors.py b/rationai/staining/estimate_stain_vectors.py new file mode 100644 index 0000000..83f0540 --- /dev/null +++ b/rationai/staining/estimate_stain_vectors.py @@ -0,0 +1,63 @@ +import numpy as np +from PIL.Image import Image + +from rationai.staining.typing import StainArray, Tile +from rationai.staining.utils import normalize + + +def estimate_stain_vectors( + img: Tile, i0: int = 240, alpha: int = 1, beta: float = 0.15 +) -> StainArray: + """Detects two most dominant staining vectors in the image. + + Args: + img: Stained image with three RGB channels. + i0: Transmitted light intensity. Defaults to 240. + alpha: Percentile offset for robust estimation. Defaults to 1. + beta: Threshold for transparent pixels in the OD-space. Defaults to 0.15. + + Returns: + Array with two most dominant color vectors. + + References: + Adapted from: `https://github.com/schaugf/HEnorm_python` + + Paper: A method for normalizing histology slides for quantitative analysis, + M Macenko, M Niethammer, JS Marron, D Borland, JT Woosley, G Xiaojun, + C Schmitt, NE Thomas, IEEE ISBI, 2009. dx.doi.org/10.1109/ISBI.2009.5193250 + """ + if isinstance(img, Image): + img = np.asarray(img) + + img = img.reshape((-1, 3)) + + # Calculate the optical density + od = -np.log((img.astype(np.float64) + 1) / i0) # (H*W, 3) + + # remove transparent pixels + od_hat = od[~np.any(od < beta, axis=-1)] + + if od_hat.size <= 6: + # Not enough stained pixels remained, return empty vectors + return np.full(shape=(2, 3), fill_value=np.nan) + + # Compute eigenvectors + _, eigvecs = np.linalg.eigh(np.cov(od_hat.T)) + + # Project on the plane spanned by the eigenvectors + # corresponding to the two largest eigenvalues. + t_hat = od_hat.dot(eigvecs[:, 1:3]) + + phi = np.arctan2(t_hat[:, 1], t_hat[:, 0]) + + min_phi = np.percentile(phi, alpha) + max_phi = np.percentile(phi, 100 - alpha) + + v_min = eigvecs[:, 1:3].dot(np.array([(np.cos(min_phi), np.sin(min_phi))]).T) + v_max = eigvecs[:, 1:3].dot(np.array([(np.cos(max_phi), np.sin(max_phi))]).T) + + # Make hematoxylin first and eosin second (heuristic) + if v_min[0] > v_max[0]: + return np.array((normalize(v_min[:, 0]), normalize(v_max[:, 0]))) + + return np.array((normalize(v_max[:, 0]), normalize(v_min[:, 0]))) diff --git a/rationai/staining/typing.py b/rationai/staining/typing.py new file mode 100644 index 0000000..e57a567 --- /dev/null +++ b/rationai/staining/typing.py @@ -0,0 +1,36 @@ +from typing import TypeAlias + +from numpy import float64, uint8 +from numpy.typing import NDArray +from PIL.Image import Image + + +Tile: TypeAlias = NDArray[float64 | uint8] | Image +""" +Type definition for a single tile. +""" + +StainArray: TypeAlias = NDArray[float64] +""" +Type definition for an array of stain values. +""" + +StainChannels: TypeAlias = tuple[StainArray, StainArray, StainArray] +""" +Type definition for all three deconvoluted stain channels. +""" + +StainTuple: TypeAlias = tuple[float, float, float] +""" +Type definition for a tuple of stain values. +""" + +StainTupleMatrix: TypeAlias = tuple[StainTuple, StainTuple, StainTuple] +""" +Type definition for a stain matrix represented by a tuple of tuples. +""" + +RGBArray: TypeAlias = NDArray[uint8] +""" +Type definition for an array of RGB values. +""" diff --git a/rationai/staining/utils/__init__.py b/rationai/staining/utils/__init__.py new file mode 100644 index 0000000..ca302ed --- /dev/null +++ b/rationai/staining/utils/__init__.py @@ -0,0 +1,6 @@ +from rationai.staining.utils.inv_mat import inv_mat +from rationai.staining.utils.normalize import normalize +from rationai.staining.utils.residual import residual + + +__all__ = ["inv_mat", "normalize", "residual"] diff --git a/rationai/staining/utils/inv_mat.py b/rationai/staining/utils/inv_mat.py new file mode 100644 index 0000000..4ec3419 --- /dev/null +++ b/rationai/staining/utils/inv_mat.py @@ -0,0 +1,8 @@ +import numpy as np + +from rationai.staining.typing import StainTupleMatrix + + +def inv_mat(matrix: StainTupleMatrix) -> StainTupleMatrix: + mat = np.linalg.inv(np.stack(matrix)) + return tuple(tuple(row) for row in mat) # type: ignore [return-value] diff --git a/rationai/staining/utils/normalize.py b/rationai/staining/utils/normalize.py new file mode 100644 index 0000000..d0acb37 --- /dev/null +++ b/rationai/staining/utils/normalize.py @@ -0,0 +1,9 @@ +from numpy import float64 +from numpy.linalg import norm +from numpy.typing import NDArray + + +def normalize(x: NDArray[float64]) -> NDArray[float64]: + """Normalizes a given vector to unit length.""" + n = norm(x) + return x if n == 0 else x / n diff --git a/rationai/staining/utils/residual.py b/rationai/staining/utils/residual.py new file mode 100644 index 0000000..a031289 --- /dev/null +++ b/rationai/staining/utils/residual.py @@ -0,0 +1,12 @@ +import numpy as np +from numpy import float64 + +from rationai.staining.typing import StainTuple +from rationai.staining.utils.normalize import normalize + + +def residual(c0: StainTuple, c1: StainTuple) -> StainTuple: + c0_arr = np.array(c0, dtype=float64) + c1_arr = np.array(c1, dtype=float64) + + return tuple(np.round(normalize(np.cross(c0_arr, c1_arr)), decimals=3)) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..d560f2e --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,42 @@ +import numpy as np +import pytest +from numpy.typing import NDArray +from PIL import Image + +from rationai.staining.typing import RGBArray + + +@pytest.fixture +def white() -> RGBArray: + """Returns an array with all-white RBG image of size (512, 512).""" + return np.full(shape=(512, 512, 3), dtype=np.uint8, fill_value=255) + + +@pytest.fixture +def black() -> RGBArray: + """Returns an array with all-black RBG image of size (512, 512).""" + return np.full(shape=(512, 512, 3), dtype=np.uint8, fill_value=0) + + +@pytest.fixture +def sample1_original() -> RGBArray: + """Returns original of the sample1 image.""" + return np.asarray(Image.open("tests/data/sample1/original.jpg")) + + +@pytest.fixture +def sample1_hematoxylin() -> NDArray[np.uint8]: + """Returns hematoxylin channel of the sample1 image (created by QuPath).""" + return np.asarray(Image.open("tests/data/sample1/hematoxylin.png")) + + +@pytest.fixture +def sample1_eosin() -> NDArray[np.uint8]: + """Returns eosin channel of the sample1 image (created by QuPath).""" + return np.asarray(Image.open("tests/data/sample1/eosin.png")) + + +@pytest.fixture +def sample1_residual() -> NDArray[np.uint8]: + """Returns residual channel of the sample1 image (created by QuPath).""" + return np.asarray(Image.open("tests/data/sample1/residual.png")) diff --git a/tests/data/generated/h_dab.jpg b/tests/data/generated/h_dab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4ceaaf9daaff92df778098148eebda50edcd1dc2 GIT binary patch literal 43338 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 ZMrI7Ph{oem}pYi;f_&@KKF>C+; literal 0 HcmV?d00001 diff --git a/tests/data/generated/h_e.jpg b/tests/data/generated/h_e.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d3552c2f1dc4367053bb581629f992bc43dd00e0 GIT binary patch literal 42565 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 literal 0 HcmV?d00001 diff --git a/tests/data/sample1/eosin.png b/tests/data/sample1/eosin.png new file mode 100644 index 0000000000000000000000000000000000000000..dbbc43e1f89585ce9131b62cd408bfda68fb7c76 GIT binary patch literal 183161 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

u=Q|CJeHjO9#3ae8&I170Leij+2Yt_Z60Pl z8Rn*`Qv~$BeW*oqyL*vgW~Lng>CR>NAY+NtI+K_=MbuPVNnKjxlks5~`RMM+45}&h zh+tb~G$b^sGnXZrw}hOS-&P*KX{-J2b7Y0PlmU4ttW%xe%*8w;XF+}bEY(i5h~9=4 zra|2;k#k$xkCN>^in%n7L8zp zsAZ=mX`O66Uu-n@?ug!XXhnP6?{Z>uwW>+sJ@OO-rzocF{(zFrh9Sda+VI%N>|#0f zg^8;ZmC%xq!Ayzy*hRKmtBXsRnStoDC(}Hl6@7X2Z%?1Rv$_4e4+(M{Ic>2>es*;{ zlx;gswvoo}FbPLW?49z^T}z^Kk=>}nw%w*DHlH5*^Bvmlqv`g*3r@!&*0$xFu4=4f zPFU|S1>@`^Y+ufs`Ca5Ce_eKbTTQw*zRJJ%1pWWdVl-(`Bm>%BPeE;!`=Cf zkX^qXq(IbEOz6FTF}83AI|PLlX6#e7mx0NexAr#bD zT#IVZMTDrQqcnCS#5|nIh+(i!$;!2u?+`Y?7BMYJcx=NpZl*Zx_H$LcZtKTex2icn*Y!L)wQ8JPP!idY>TW1*`*Sz6T%`7Dg_gEZBmAzA~1FJ@wNzS57FZ0Fs zeju-&jb34J-y~v4$ET=wx9#e^#d}RzU6V$Hh_Eq8yz!QxviI!Mw0nR5>e$BGmWxg8 z`7rg=Dz7FW09DF5^*=vF5>UJmGW;i=tGDqx2B9PZ9bn*hcjY?6>!LDN`s(le23F}D zF=6lZT>1iQ>F|VI~x>Jz3&h2CuPw#@VwvW9oNesfIC}L6_b`tfUSJwl-@~Gq8&Y*rwBl z453IkIw2C00=6CI?i6+pL3gS}HW+#c%eBmlUf;U@;Q2=<5YRvv-GfBAcs@L|zL_PD zBPoIv(5)dNbU#T-d1>yVB0=WpP1Lm1?(SyU7)~=6224cUEem+}{6C&P@BU8m!_kw( zF3F`lgx(M3dV6^I*?yXvlWk+l9+uXZrMJ}|mkzX4VyfHG+9D+ycKb^V7j+TywwV>~ z5aZg)5G4o-9ioEpHNW2`^0yU2MHj3>?EKven-DqEkyaw{?|w!m$nXXRd+lGWB&MXi zfxgkbyYtPuE~2uY@dJ|(s~fPNC0qmEU7W3_0ba87ZmMKxs2~L*+$BdqI_+2^nId&s z9tPH05-6MN@_1rzwe4@0-LvuUb}hUInkp%3DZz!LBj+RpLIEJCMwmiP)di}Wr7f|! z-hYOGsde}6!Em)i@o?{tibJ>0_@jAwycyOC@&k&d!u5@H0Z>Qrgs2px&ElEX%SmXHgC6 zpslG{Kvglwy+i9@SE=c6akr-F7mHXwc55M(Gni6aG_B-FQ?ZCZR-amxf)!dSuG!$- zYYSBf0EL0RvQ$Jw(Ks0U?cdDLaCp7+B|vBszY~mY+|R1uuGyoufuS5p0GSc}g%ZRUFYMD#TCP0tXwCfFA6K9`C5mVI&fu@{R z*dN%VGncKmjFvZJ^#A}y(48hwbvnZ+glcaz6L=L^*Q9KruH(oM9Jkxk>EhYJ17;>- zB7$h_wUbC`NE%dOI2F`kQYb`i&l&>K5o-OWFRh`wi9yT8mZ^&hQbOL~uqeGv|D|oO zkEiVlZi5F!DNJx3hHw)}nGbD~ih6U}dF~ZuXQ!o8Ns2*5Mc_h;CR-07Y7t@U+6bt& zW-52a_UUxDJ+7!&+&`qhL74VpcjXm1a ze(<8<28bd&TBs}|f1F@g<=I_VPgs_}c21fMgtSw9k z=%BGOeEW};@R$mkbebJ*ZP$a6nNewgNP zq-Kx^qBmc^d{HUgr5~|#9nb;s7MVWJ(#HDH<3H3v z93cYBSzGU1AZA0cgXKiaF}Jt6d*5aRMQNtvw46Owez(x`0BfBl{62{cKvY)B`mdD) zt37Y(M`u1gxI+b$d3Kw%lrTS<;V983*IDh4~oFqDQ#wv zwwqhdrqWXZBzjp|*=W>^)}|?njlcN8-G6?sj;nx0nA6<}!ZO^wi>5~t0e;YgJcty9+pLA8+LCmkggL9%|l@5#{mMz5D?nO<~vLWMaQ``o38 zD2aOu&#;;t&*f|3`>)|r$PLwA5`1atUl*=F$2T`sbn zhMd?$W4QbL*~RIjf3v)2ozGt`%3dSuUcIT&_q{nRVzZ7X=o@L3Jl<^!$Nf$}J@jSw zG(8@1KO7DhbLl#2ts$4`)gj@CtCJ1oiQSFbJ4|&~;6e|W3WEt?@DCZJo*&3R@b~}N z*ZU`4hrjLRzUuqXj;tLy)e132iArn7F=z-!Y4~kd`|9|Tm%P?Vzc(NGt6v~QK1Dnn9Rjf>GS;==`p1I$hnpwE2x48(ynaagH zwMO>nWSeVOs5c6hisq+J?)JwCmP`vZH1#Drg@iPUSkbCDHz3wdx~uouYG}fG2Jt*U z4%_}PW}|6XSIgA2ZuTO$aD)o;L9s|&IGS9)un%9_syP}pZSvyz@<>6zS$dCZ5VUSH5|&6`$v>o*)n?Bq`bJ8-xdU z3Td@3DkAWz`LZK@I=}Tq7QQJpSIL^TE*ig@$rMn0r3a#%xdSR9 z1Tj99mpqI6Q3VtrAF;cfdYPAqY&wKWG?cWj%Mz-LwLy(AMR!$r&~Q5budkzup#}9c zWNm9UB)z(b1zDS}_!9{V5E1Hq(zXIi2{7jBi+vW*-oA@{` z!*VPvMOQv2WBU;A%$u0@`#l~ywe?O*X`La6ti?&-OE>Qt`efs%OIU;+#Dwv zx@}7AO=K!Vt&?PtY{=RBYWlT8M9$r~xA9Fv6bM*;gM|&O2IC~D7JqOb@mo*iv?lUd z<2{5>fakd_aHjl&XNOjZB^5PIts^Cg6BJB|+9PqP&{fkKDWM`5Vqgo)Q9WgYo=oXX z_3=2nYGxO@OI9Xh_fUPVN8!LaH|i<2TGQ;Yn3doy3iZ5P_p<6ugao>q?uc2SAe+j)2A zV=_7{RY2I9AlDBwCAoJc06mK&-nUN8;mFsuXCAvm7DGr|B4v*R0PFw+cq=gQje`n` z4deVqvYUZ#|K9^*ET@j5y}2OoCdYcULQ|gJ;fK2 zQ=*D6A^@t3si+kuf{dtV^OcLH7Ur)-Et&MCPUD!fxUOwHsEID8bX;zEtZnmWAMN+M z;>)sCC4e~XfAGQUn%=ojgVWsxdh2b0T9R{D-+kEGPmkMPof83V>jZ_B2~}lRual`t6^Q*Zm2J zZ@K|IuRv?8Y0NjHE76oYAS^@^LQC|ZDiPpu@?vL*Q!1zm1;+LuDWL=1H3tzv_K8r9 z7TVOza!C;Oh~{%C;?0#qW-yp@Zk2iL3}FO5+#l0Gz!MoBcAjh;}xoqh(W7 zMRt!cyczK2SjEk3#ffSbk@YP>K<|~8!xHzGTNW;9s+-4{pl0#rYi8>_E0mt8ud4-h z&k%@3T>hK*ht~=~O~I745~_70fSPVES>p8WQj+vZhP-LbN}^5z2o!zAYrZ`zf5RXF zOK9gr21OKtXiy;RJDA7-gs~E)SAg}e=JA_MMqu?pXcUQPbI#g2HFa@ll8y{IY;Bo| zs#79FnN}y&UR7J9Tt}~gmD=p#L9tv?&PnL1rgfvM*XUJ|r3qM1$&Gn9oaJ*Kq7Flq zA)Q$yiV%p{89PmIJ!YPC=;_Ju>8HvLNriJ%MLLTOk|pmi+LOObKM8RAKm6kF2iCc6 zxSc{sfh4~>Z6c1(O{^q|q#7cWDnUuAC^36CWf0Jnw;){ot-MMq=daMImH>jgVeH=T zsy$iWn-7l+C}|4`f-ClWl{^3-s1T@{POhq<`sD7DMejpNvE&Gr+#qF#6GLG8l$Uq= z1KMC7YDrs&f;r{hx>HuYsqdVI=65*=k-DrCSdsN$Mjli&zJ&?>x1Pul0fK8fthAuO zuZc>WYm2qAmFmIhb)HMM9tsd*CJ`H5ut6n6L{z(rhpMKCTzrl+X!VZc)5@R;wDu5D zNqHzaCsS8TCQ{m5k#jEUok<-_jouj^q5w>?C5>DtbOu=fhKg9kS=Hw348@U;A3aSw zMb|Xi{>YETdcK%jI@!>G09n`6Izo-Q%V@OtdWCv%1Lrj@H>+Ysv& z?A)^mfv~p~iC|WIcl@+$@nD3SA(+Nln0MQoV@@>&_xPZ_tf#@l@{o88L3b_Va_s%g zetk=#_~s#?AnL4Ns>~u7vW%+nEik;l^+e|RZR&Z{wo2oDc}QM|NPtrkLQ*nQxT7{J z8x5C`v4m}%u57D*a=2)((nE=etKoRewKVMFF=y8#YUmB7X%MPqGk~QF-IG=!T=Qtq zp>?2ed0eb7nch?OWw#{p>}2mWa}V!jO!V=l7dj$kHYOzsbbohmd)_`BmTQ?)+zur! z?Xec?TJC;${c88{|0?zl^X>oLON!XzacNaR(OyfwqMwGeT)*?0yJo{S-Jh1UJ&GpA zvWNvlTJ@6R)YU3PO%a|`cvprd=^S^5(~EX`x@~)~eEhO}{xo~5AKzn2aoTR2W-8IV zPgt!%&Ijfd!K0#GAOc_Nd@|G*|EG`cPiZ%wF2~{1yCnll|iGQw&WrnRY9rBFqh1PSI^>>Un z{N*?C?eECn^ow_u9gxRDc8DlUBxzebafvX=fap~|&E7eiiHgvp zM+5?9V5nJ2Ni}IB0!4dgij+!8y-ih0p;*zBl@U%$($!R@ujg;52%~x#3SUgOlW4YG zKHX0xH=~&(n-X_PldGj{=t~|fn0ef^hf}ENPCcBxC$>{N%q!arqQi7^O8fosx?H5C zjr-4%)t1c5>YRvvPPxY+vvo~{T>W&GXdP-znRC9pe0H~6%7yz>!+@-)9ofQpHQ#I<%I1=@jw@=*0YhW&t-rZGa&7zBk=w@@8{JWk<-3 zNpRDWa)QS?=k_FFqfd({A|OjH2DBL8JKWhOl_#m2FCy7iRN8jCGbZV=O=+G`qTnQ3 zEPNSDMT$LI(1X63ow+dtgg#un-(UOo)IWQ=F>K09r{#gYtY&ybcmTon#psR{M#$3K zHJP!8co~K`E^PA@OV?h8-EgZ{-#5%-b`RLL(Mg!C!)d-r<1g5AP!$N{`dQq~D+|Re zZJxlxJeT|S{HJ_B=8N0Mo6xJ|NMokw>!bG|#THYsBxuWNo0{9#SF1}sbuBoc1z`L)b z5P{e_GIa^_PcM2R-@#>U340>&c+c}N% zVQ=ePXe^^Q?aPw)^|0tB_xXgD!Gv~0d2{KG3$vA6%xzEK0l0?vrlce+m(kD zuA1B0Pa{_$g%GBcR86!6RaM!8G&Pt<^SLj>EtVWJ_uCqxGWyNwv#ng}LK$RP&c4k= zB~;1iUp_JdHH~D9aKE~OJk-r|m0D9y<6r#4q{GGLpikOtbRK26W>PTh!JbDoG& zlBJZA3oU;aw{k{D_vF?v~|Nddr5#nxVW=R4~MAcY^o47O=lk!x<_X= z(pweF?#0X%#IP(nWcK4PyKMUsA8qzqm))})P|VC`*)&><)>9u)mo&HJk2?5j`RorO zL8pY*yh+fqoJ>{_d*!_vy;^ohUo{Nebz7E0<6doyiPhC9w696;1kijoCD+)m@g{&qTCM(G|nYP3m_|v+KJWt0mAs zp&$MS#-D6QmN)xoXOAE&HJUpW(V{vgUE2W`I-poIjj0l>hiTtCBK3fXA_x_VMkyAZ zG!X_}7Km93F=#4DuxWFbJPc+CQAb%i#*MTGu*kB^qmY)IO?LZDzkSG`>!58p{KcoQ zp8tp4-~aUmA~am*<37^3U_2i2baNMGX;|(mG^tSf!Ns&MupEo~PK6fM}vE4YpT95Kb{2 zzpwYFlUupCXw3$U88z&|E>V}^Z61HaP>~4l8h?!K7=OYY86XkRqhfYOJdT-jl@jRi z#kGl&P&wp!x4n$}eU{$MIL|)4ig?IQS&4>J4Kdm7aad@p2O<&Gwz9ZEL{%6@YRXwm zsj5)1oG!NY6jaQ#eGhkPFow&ka#ZG8WMOW9_xvyGe>vibhlhwl9s>gpMbj82*=!Hm zZj>cyKt4`vv3N{OS`Mj9>z!L>&HIMpI+=who4O?r!p273C+p-u(MMihQ{zw9ua;qACY!-NecGrb~YE1CHKejtSlEL?q_Idfj?+AK(5Q`TXzr zQjJ6)K+TzrmMRbwQ&&I|{6Wof0d5r@x#Wi4p>kF{pxYr`Tg0$u->^<_QAPFa#%7~+ zAD2_v^t%`T)A2v!$w`|;Z=uPv)^Op*qqz#ZBoUlixO%?2* zOuJ|Ca(BI}^iSW}Z0ftO?_Z9$e0mYn`^5(vm0Wa_kA&s{r^$-U(K>CS$Y__gu91IwdIjlmh5gc8UO(TLvU;`W;0JS z^USw-Z= zcVuL&@FhMm6(tYHM_@<2K{F(sU~Gtx-#-8F1}3aMn;mbKQ^h!e;+bM7OjHHl!jgX$ z{BeY8zQwE`)r%1cEdvrAX|ix+wY_Z?A5Yf96+zA%z8y$T2Y;I**6h-~aILuXh)cyn+EcVl~T>L9-rBXblk1OkffP zX?tVGfemujOeonoKPzKaMMAZRfRNgKY1-}cV#YCzJoITC0o01KlQNYVQ-%>WU^|Ao zb`A%dqoWj&5RuffG)y@~QC~inyPM+bRNZj9PJUfheI^erqM8DxhzUK60OY_dA*hLp zkf|U$G6ItX=#h}}5J8+nWG?a!W>(Mk2|7C@7IZ`k07TO@HvP2+#$jgXFHo~(sJ95-f`20cyl%zOEg!)UA@2a)j{jd6enCM z0K(seE!5A3_CyR(Ff~v+>gF2&kpVDFQ0BK6yeR@sQgIW+9~eOi0cFAt!#6O)pIr)u zG%3fMA^&RI+2fQxNLD3eJzA?EqZ+bnJgHe4Z91f10I-^$C0r`WIZp`4z;#cvyU*JN zw_NsW#Do*3iP`I<(u<&mh$ac98z4J1kxAv>jL?9XoL8Cd@ye)Xs+#LMXY>wX7{{UG zHlu0ut{t+@%M|+D!AP4iw~=yITVMz_L={0mKq{Qm!4zly9M@R&14Enkojflw4_$}I z2nxhIHTH!ihg`6ZDX564h|fu!C(LY`r%RSGMc`;8R))5_*BQAkifp!h4@{JEd101i~x5Wo!GQSxTOmE&8BB0KWnC&ec) zJUX}tncC!~Frl8|ms`7#ni&BQDuA(jxL|)F5GS z{KD(qkqMu>pyhNHOOv^A+jBtSC_#|di|L+6oOeoi>&5b6X)oJF+8+m5V2Lm-? zRx=7&GQ>C1LxwG-aIvtCBu3-f9gxhxIZ^PzOLhbl0L25cVR*Qc9((cYb%Zs+c9k6{cVa!mdHPOcw3{`qFw0j^-l z6A*=_07gOq0wA-ASot;&o%AWcg{Cq!lZnTIZ*gzGB$AI}XVzfuMIR#Qn?QW{emZKi zkARL*C;kH>DwmY0Y0M}Jpkw>x+5rTH2Jn`Uj1R29Niyf{I&v3&cY*vscT#2$^)9A7 zwNoF~I^vqM}V4hqIA5|nSC^v@2qZk5XU)37DF$hU=%_(5_=)PIBZFG%M;lQ`_g>F!QxP!t?wQv^^U08`Znt~k+6DnbP?P=Poyh_9UO3=o+x0eXA@fC55MI#Xnb zMgW@V{pxy`$60w5Q<~r2nvTz3%E?_#+f{QrpC9Jjj}Tm_;ry_6{`>p+{SAkT&-Q{Y z6zHM}@KIp>Kau+VA74MaB@?--_L^^13ai7JMqtNB&M{6Z(?yAy zNdb$ZH4a`(W#4vtR|P-In!tn^-9pw9P< zahNMKh)-uqcYO>CZ*fdxj$U#WF#un(2(gKndJ_>*05hOK4geL^oKK_EN&j#p6P%%; zfhKd-3&JElq);}6tS3DJ8U;KbVIhD3Rl%xA5XqE+#rD?@xU>TU80

)jb=1T>tLn^BV_GpN2vAp$^WhD0yd@(FB!3iooW*1}Aey_TI8$ zw|w~Kb#%VWF7BbB5PI#|CIjyo+zj1+{pRC;_wD=Ndi{o{o57zgs?R58*M%1F{Q56? zXJCkcSSk?h%RGESxeE3C_7R2DIEY$Nj)jGqlQQL|8zaCYc+)$desMQ7F(?2Dy(1$Z zsd5f7mDGUA2%?l@tZcQ1E+92ZjbS}gDGDOqE26{K+5baix#F>*a8?Z3V0MinT;jdTkj=8v?AyQjT{va6(mGtJ6MH> zEE#~oQYzpOVIIw+!NOTK@9eM(63#O$%CqqPdAS+oxP_dASrgulPM6No7yjH%O_jY< zB0@1+MHLK~k!;#!mJ-EzBCh-MQ!7UnWFAGpg$^_aX91iy%ZJ1=6+4LhnZcywB8qAS zfw+3RWn*!AZ|4MH^i!LJiW=z@SK{cN<}c*0nkcHA7vMIf78IRuKiXp6m!7&^XtdDom&I?fEAJU4an1t5gcl&T{wLhKiv zP8ll|A6>N>Num=#nE*4Qfq{?YqHD8?phJ`N7I;3*S=ZZbRqyh8Imh(p%iB=m#mnJb zf4_hJo)idJVVRY#-0u2>kH=93e3O28eIx3xOOC;}$=~!vQw-U$um0fy8B`Sk%xli* zJvSu@9PZ3STFRk63^YSc<6N0@8qGVKODx`LGCDZ6AQP4BJOlU|=TeA6V1%72Ix?#@ ztAV1XREP*5C-79l6B{>44VIYwEk^9s8Ihtb!B^$6mr>xT_2ROogBb zvI_|b!Awv^8MIWW!#3ABMIm2%Civ~gf3`i|Lk31=~=1+&fX2YIO|H9+;Mg19<6sja$(Vy>-aM2sB-@8SDhQ;?dO^Kc(q>l zpKX3R&7dVR0H7fv8!frO(N18@zAz{va!4Q!Gn)_5mS_0d*L5X8I=}v8yV}t&EOyXy zVOrmZ-Dbvca(4XewU!)BLzr~|bDg2~YQW2SCURcXN2*74!krtF0U{_66{vHyefM8n z{;Tj{SR4)c6))5FbGJ;V?pE~;V&$u})oQWR{aN$c3Azd-|1yw~@Yl1-Xz+H#{cR2% zIagKTD+A{PPYxOqd$E9Cw`BWT|HdiR=C(_oHJ4FP}HFja+)fa6NnT67=6R&>M%S=w?xHT zC;U;c-cz`}_rbrfLkTWL4z$C#oN2MS&kO8XuFZYYhurwtm5M;kNS!@U1l>p`| z7S01w$$`WnR+Ma95Bsj(P|2n*-f+vn<@L*avP0+DjB*lk$UM7dA^pr0pqN=nL||n* zKnUp8lBOiPhwBdk&#uFE93QWn?c%qOx4pkNz;L?%G2G?){AjOd`%&VbrT6V-Crp8g zEic>k?c;r78+;g^OBO_~(jw=AC`~`w`aOTCuepA3{@IjID|;t@-_BlU9-PgU86v9H z11!BcJBq%l^u@C?aJerAjdS1H@3fW*=K{$aL=j*2^_>0L#e6I6?LUYA$9Xi8T~lqA zT@1`8)%UJS^#9`7hiw|Z8Tz3K_y6>R*XeAuZmj$sS7@U7$@cnUMpw3K{L5LYDu?8Z zFU1Lw7GTO@ZX`C4S@zCQzA`}ml`=y{fG-`?#DiEifr$a2YEeYyYotSNF)1iYP6jRz z+E}cVIhvtEd`qVzn0S+HsD_}~RJ0fvB7va+u#_SK2&#mpsG#HJt4*!!U3=8v&1@VChOaG;Q7tN^`AYEr^i2kaPLL9-qfi)yt~+L zPI%&buVO7H$5Ex^T=ds4#$QrW42aRA7sUdm`j`b`k2&jHw6h*v8<*Gl=GW(i1;!A zB(aQvIDnOTB{S7a9-^uZCAOSRr=pO=OpVYG&5SXTLv-o(f38CfHcd4!q9GIm6STt0 z%@J-lQ5hK!6M~J9SqeX=U{o3>1J-G_iuxf}kN9Zl`K(`V`;+Z|@%*P{-M8;O-_$c) zUHtCL>D&C;(ctTwSxd>H`pbflzXdV~(G;^wSSK_w_KvIXm;dPJFXz`K@Xr7Niy2f44!SUe=Hs-=s z0uiaHVG+sUWSwV003;sxeEmo5&;GlUle3#CaP%8|;7Vc#qKD?W0fMPmj0v$QYLP;g_oWnr=mZl(`mP?uM-lg0nm8~ zx#0H#GDk#lN9VT?HM^RunG1_olA0}MGT<%6v!*&!cU*ov#EB(v5DgoH$9 z09gc-&GZn1oudmrAfdWqGBd`3c5a#7=$mTyq^~y!L1=YC<402)?Xr|Vz)#xI$Za04 zU-Pzu?u7gO&}S-XgS&Xpc7K@?^UHCL0`uP%>F0;VA4*IXA4?|X}5 zKm^c?nVokIArdl@+IX<$;Hf|nvlvVYz(J!5gyi08y$?NWvbO{~kb@-g7i|SJ1OYO0 z+y>R!&*-c1+V6JF;wa6zxCON~Bk>H)Vri3`?)0?6=Xah+RnQ@|XRAp-fJ4Prf4+d{ zV>JXM!Fh?)4=hylk2KDhbCq%f~u-i zbr?%2i2*9~hDy6|RcCMlwV%TIOo&K`9qdg+6gd^rIQCmUd+g`!0zu4>umF=cht32T zp-dU-#;2-yCPE)L+fN>E+Uu}hw_f?SUoJU0*q3B%zzhV4$T3MFE-|&WssJ(}TF!+C zOo{`nz{|v=y8Q{AzuY(Wlrz@f`Z#X$Z*Q+sVE~D99+p+LXv@=O@NN68TVoXk zL^xP}IDnD~DTE#u+JA=A>^PWqtt7@cOjsj(12YmOMv;mwyS9a)K3nfz%FjGVp0w%!$Yvk*bJ8n{TLD)ORDW2%<*-@*$x@sL2_E znBP>*JlC#p*V0o(&j`xW8#|XH4HKPRTtG8kO^&Dal5yco*?|Ipskn4CM`IvHGYG1t zWFtA@Lcsws#Es4Xy4Dp6MG<(mmYX>d=pd!CK6e1ENpG znJ9{;IfW)jVesuV#{ylg!t>Xj{Ai=O8Ks$l>bpH`fB>1mgh-1y&t?u{#+oJ0spyJb z083c}ijqTE4d_4}tsWS}MH<_tNS=Qt&ivio@4HLQ)UJ+}cxUzTltKan4i%J#FKOEL zhwG3T1YgyG3EF8Y0-!w9M|`sxr~)w4eTa%FSF1IQ1=&=qigIzjm}oRl@MbrU;PL_w zf*Ara*O;G~Ow5N-N=c#sZ9tO0;G9vOSv#80)MxU<>l(9u{nOl*at9Cc@;Giq-s0H)rW5C{;KCqui;6qiI|2ho}&`|U+&xK|NL|E+La~Dhvz~Ih1ErKqQGX=y#%%G}q-fOt3# z!eM2s#6VCH4FK7Q43I1{AUT`@imQT8jnBJn@cZ+)*e~yEnxR=#>}^zS;qyG3fpaj= z&JoO1fN8nPJvDEd9x2?dGg6*W@BT?D1Y%`8Thw#%nm75$^6sT_pfi1CoK1^B%(a<< zptPF|lQo=GGJ9lGQ9#1>Yx|#!Ud6c`$`Tl~9op1xTC~{~`K6oLLna9^nWu5A5rI$& z<>>FP)3)J5;x>D)Y9)2129~C5)zY!A3RiWRlcq=29l7tE{*Qz=0&eF0lY8?UYwyfJ zL4esbi=t+68cQX^eiq+3$Bt2)m$y&8RPB}*oz0*>c=e7Kms~A-@9(Nf!vx=*tNC^s zjc|1y=iL;I7!KZIM}N|3yLx)i-I=wa3eJ+O)k+c2iB8Y9cUz3)$t3RAWAsVu^{MP5 zF`4=fG*igN9!$vDHl92fJ_&>X%nWF-T+{qa!3>GeBm){|R+H3ms8ca)`nhdp``&-C ztr0W$@ztc{Z~905(QfsBdiP)cE2w!3eE&AQ&{S57>3X+)0H1sYXh6S)EdF&>9i3G3 zxP;zdsAwwQv!-8%l)s<)yZ&$grX1K`{`+6~{P-WL&I=$C;urR(f9abIh;JX||H1nS z4&x`Gt5i_4%$W#~l&gjXdBhOe?EUAUimvk4wG_|w+HY^t@<{rKq2VI%dUc;Jdp=A7 ziHNvB3P}0u-1Z+?=H&p5IbGO14b#Q9e*4E)PLuP5W(aYL%NNJnhx5D5>#GD}O#H!< z7k`nDCzSg)$Jr$0>MSxZk zp@}He9-=T5XUN`r-qgN~TDOf}9no!qyoV&EjCiZ9V{2m8^7A+ z8+!1xijxBnJNljPyczbJ>wJ8=nuqF=?)s307Yo+9*|fSlau_3!SsMnFQ-!weqOs@YuA{MIu+-7WEB1v4n(TQ}(XI1Uia<{gQ%oRt>K z-X+WE5LE%ewDJx`O#ST2U~~ehNL^*WfdZ{>=%?4}l{_1YBC_Mx?LYnTEYoJHIvpdp zwS9b5S6gN`vN>&~*1}Q!_}18D-pZpcHATbuhJ3Ob?n~ zGxFYnWL)3xcCR)fi{M4$_R+f-TUy+)geqNcP#c|@`Y>%r6)|N`Td8BsE-*@hbo23M z!Xi*0n0P=^(;{kUhU~TKs$eQI5J~&?iqZHn^$8$Ri6LzAN_oWh)tXzqw^T30x2@b|0}QGY+Ouz}#qmiKogm&5pZeo}_R9eLG!a24-SV-8Lx}IVNCfHgz=bpiIxsKDi70s#QFg=Bs1Kkrwa&ng8GYAK&|(|GVfx z-_y8~-KRV}0AHdG_3Zbtu7GbZv^fFDXLlnwAF6)J;33Zt%@_=_7$E{UnvTyte|~T2 zXXR?q@mzfDEt-l^Ro9K?1Y{zPP|;(4o6hXAB~J+K5uzC$41<8f*{SY}lVp-lmf!hv zFI^j6RZz-2<-dF&|E=pUfozhC566q|{BY0h*{Jd46ZqCAUpXNEy#(R>mHPF968o#X zH2?q*peX=Y5zmUC2VEBw@(n|>f3N5BI0Yw%J3NfeNpG1>WHJ>ZA%|vZ;5h>YUl2^e zR0=Wy8Q7l2!q%Avw^+S_cdo|4O2(z*5}jrsFf=JsjZb%7wLMNIxftfxO%o=raAvso z(zpOPa%PE?;BCxZsMpK645VDOds75LBy_BX=*uWz^WdzQ5ildDArm1Yf|^!NmCI(0 z9g&s!Xj7W6pZ;mTJGvOAk&n7(3bj_d*AnsUVLgA8M$etN0z{<90_o*)suH`|g@|a# z1Pr)vj**-*FcBkiSG{)2Y15jC7+CQzbIR18%~BqYS5jGh!k3~z7R}d3FDtkG;Nize zJ8ozSe^@I77Zlf&c>ri`E|BckWwDA_rW*86rG^Fkhr--8EGZX3_f{Tcz_THe zBLk;14w%T1Fan84Se`81|NL(Mv|dc*LhvYrl;-B^Zu+#*GSBH?#Qy8nB#KqCZ=573(O=@2}<;zw6tt9FYIM>(Jdc_*Lc|;ja^?J3~bSFi|Q8r_{FtpzK&d z^?rT5;_>tq5~wNG06}kQweCkCB(y^4@=z$D_ns8+&{_B1;TL)_&sjrP>&lgRKSl{o zNY0&Y&^~Hp8k{oL${sY^ur1wup=hPrD{Y3AsIRVLo}`4boOVyeR_&W zzFQy7ju;KBVCAa7)<+|H>(O15-Bi>>5R(hhM=B(oim0MyLoUAD0xfbZ(+fL)Wj9A} zPERGLxzytf$iGOS`*I2Lm%PpjU^!3pt)JgE>$^J=-W?tNaPgG`@-Oqr|Nquu8t7L) z+m}6&@vYA`DL@h8gJT1+LlZ=kv zqKb~eL;xXVWy9N}Wv#YP_Gu9xL`9S;(lpfoqGcEqdVOHSI*SpLsdavobvqXa9B2YY zA~XZjLVTdxEo}$y&*r;exi&Q*LIW+NVpdM7&D8`Q9qiZ-W|>F?s)&R@wi_1r*6%9F z7`ba!ZZ22#lXvp?`i>jN;KwRSKVPi#yj8hrx_9xm7g|&Xq6jPAI;X>HCe%{l@}a(dkyt%KQ;zcPc$=hZpe&!Rj^5PO_jO$_ zv`+|zj_1q%?s)mm|FC2;Q#3`Yo~++&0HLEeS^L3Bp4{=e9=6)dQ8)k>E5%bGZ$?m(BoiYNGXNms z+V86oGDlM2LsI83L%IL*{SQ9-T&E99-sazne9oUu*^KH*(9xF%BLDJw{1rSfJ18-A zr{5cFf8({9dHPvMUpXNEFHnECJ>j7E12aTX3Wqovb_Ax1s?9XJhACu3LnKZ}g%H!w zkLn4L4}3ELktMCU5bGCGlwyRw-3Y1QjCGQ^FDgDDmO^e$P>`*l3YrVW*l{wNGExzv z*h1oEmr85%;P=H7J4P@@Q&dBO0%it(*lN7driR0ex}b~9 zbZ+q?{Wx8mjt!VIzR3!ufPP;@6E60s16K=iBa@ z0_nPty6b%7bNTFVgS0{PQlyd9qq(>ip*NbEQf% z8xp(f{=QIzp;|x)(44)DQq&AkBnn0?nhP=JnVhAl(5b82V7a(STW~cjfAU%V`16~p zDaW_K@6nI%FRI~YqAPgUo~2b=<-2^;)d`#9lY*0b*!#Wvv~71P`fTN$Jt%wJoM4CH(EL|LFYT zPk=tC^=e)9+u0QV#v}C?^~GiS7e)wm<-|g$KM5E2<89fjIsa$3i7{6!Wy)P8ad>Yo4Q7%PL)E|b$Rla!RSB_eZNyhk3=vJ@* zs}Zn%^o@J|!)99C{IPS-rdS%6+Lo-Ivx_tJ6_iT8F{N9f8Z~Q`)Oj$A$!`az3#=q8 zE{Az7My%5~Exl36UQ|S@$`j-$ju99@m0hMhm73MEos6pOAAI^8LI7nCi39V4{rdc8 zx95w>UtRp^@^t^`!;7nT*B=3DE3;wxVx9kT@8%cXX(O`29uL;|rPy+7gp2C<>I3@p zTzXM3K6~p{twab4X;+WSB9Ix46H}|JnWj{^`Bb$s;0r?+wvJMWIw(4JqR^+2-SU@I(Y=mWyG#x_^3AS2CrX zj{uPvjLpaa6hU+d}9sk2CE=<(D1yZk?8_sKW@ z$%_{~hLBH>ZuiH{o*NItey`)=-m2S;%#Kk-od-jQ^7$nbr1op?fBt-bqY6N%MN$b2 z8mqP~lrv(elK~K#NXT;WFulm^nzlj7faqK*7cbf6EnP^mKm|LfyXCP~vb<_u&$XU^ zznwQXb^Gv=iRf=ZKe;T3Y zRc|w>5Wo}=`S5c?A~FE1I>)Ypto~#h6$lhTkxk_=x(qU9GoiOfCPW}2#w?o4p)Cvs zNH%MMFyh4{+?T$(z|6xTYQq4`S(PS?4dX6~JsM^j*QxpM)jcZxa#BN86*E9&5ACp1 zA;mao2Rl4*045?@5t8S$-A)Qc6oiS03@xJ&p+_M!sG6LaCov#7nzWlkZ2)E?RBoPp zJ#0?P`fgnD;~j4-%2KIhTAVEGO%fvSyqB!#91Ial0n<0+oDdKI5}*kavng^&hyY?_ z3V;Zs^Mvf(fyf3_W>5h<{>lCOKRo{KpEgXDtE{liA{3zZwvQUn-rGDk?W?e(+ew=7 zd3#EwtY3l&q63)y-3wm6`)ob`+s~)fl-fVqK0l{ng;1tc_?U(TzxaRNT(#^2YLU{= zlvF2-E6i%}gWKEe93s-eOTS%kj8+O01*&vHHDnK1fgxj=RhdvNXCv=?F8^m_S1mvn zyW%Z#C(a@@96$c{vzLQ>_h0+>``8p#m|8Y++@ zLq%0HNzW&7p0vC*BtSw_k*v`GOu?AI07{vUU__QkSk{lz(=9tPAO@$YwKWfWmQ8h* zo`paBw{M4oK|`zISLaxPKbbN znr6V_$Xo%|dfoQ3M`Lb=)=P>oZLuj3GDkGvIM?aOC0z35*YZ_?qi>cU1#hxZ?sP6A zAGRxIl#;|;6?mex1Ot+Ed)lPHv1w=KN6ELM9gMOEVrE?}(4IZnk6 z?m7%gp@OWVRm0D-u@&URpn^o+LvWCL@1R1+rC2n%);kOF{!i9R2>)X^4uKvW+nfC~ zCHXa8KEJpN8-j?@OIietLZdZpsZ(67ho1TT!EM|NEQf18IzIh;_y-sn^S@NlfpJEU zVnztaO$$kQM(&y-;2{-OELT}c6;aff2ni4j(8>tRo{D_|WI1S|)tIdaF)^wV$b&Su z^6dJIn_SCq+n+E3FiSPWZYDx&xU@})sDxz_*MF<}bh}#4oroAH6d+XRNYFD#iqLp= zl|=v`VgpknDtSh5Yz0^l$cdFak`rKSXC__W<54VToT~NdOG(oQSxa?2QT79QmI>Z1 z_2umO!KANNs&4oM~l5<*oHVTz@-;5b^O`mTun@EMUW}V>C+GI&3DqWWj+>fXh}im?3#?ofss(nk*nSQ_Q5~p zpWGY`MFISqkJbqoi~6R^ITiJF>YDYI$ITnw z$EuTm+po|vgxhL!zL>-LSJ&$2KX##kAv1O;*&J!)rZpqy6c&%DR>8X!7X4zx6y0a?4+-nq7|$A;iKue*q($b?~Xi~Tg0whBy_ zy^lYnCu4nfdGyJ2@}y6mz|>4s(Ztldu53p)PpTmxRW{V7BBHj8v5+AZV5eCM7QoC_ zKoCI?YjCRTRX@ZW8`xLxg{MjRA;+F~a+KD`&vx3L)lb5Umx14`>c8;IwYcXW*IczL zxouS~<_uIFER4|5dlsR)94$~zfegURW;Jw7G#9`_zaAZlbBN$sMa7804s*-Q&cWz+ z+eP!EHG(psWU2(gOmo$OXGt%7eedh;@`H6{>*CwHyB9}CkDr-P(*;x7HILtmFaNw$ zQ=01gnt$5YXvryxAj&kgtUEttBM<{sbE>ZL9?Nw~aZD?4Sd{x}>225||MbMM9ecBOt={ zqe_-fTC_>0@$@Wx#4JdN;*K9)PZQUk1MEhxmq$(Vw8-~*h**z@>^4FpR8hb&w47t= z1E3@1h1Zfz0S@6-qJ_KzJJ_NSL2*VbLMVokZGN$VBB%KJ$lYae{yKcJU*EKgsahi& zozVE~CDvv8JvreI_^#SZ2dE%>x6TU?(ygc8& z*!O8X`|iohjP)W&30*qr=DeIi`H}8Hryu;*^!XXz9W{`XS+R{sI$0M@W}*NvjG!Qi zHTFV{rlXqTTuSx`Kv3p0Xx+8$Z=AWt##xV8OBRn6fuLA6rJx|HNRAQkhey=_kLDXF zepQlG1_hj0WBdLA{eK2Mg7WVA`FxuV3GvIPCVp{8HYM*Di`VV%`OV8n1GXp2Cm+5V zKCE@vkMBRYd*waV-SL#4+wJH5KLYt}nE`UB!e|Ic1htTf7-o~*=Q?{?)Z>T&+WpRm zO=?5UO024aDk#pGFdDr5C8Y?0suM9}5R=37#r}D&)^k2z?RP_6FWwL_DF7r|->XGx zWSQHg#K1AO)8~(Gr%hYCrU(!sGmeO8hUlH{r>ImBlJucUU`!RlRM@kE8o2;^NKzAq zLWX22I4VwYvS+!$aF3^ZuRfoxwjW?Sb%y2jt7rP#@@AWFA)W2wdTeZ%_OI{hl3Z=` zFrF4g_R7J~1dSbn0ae}djb}4a69YmpTNHDYV1d)zy@8 z;O=J+zqQS$8y^Ay64n)SZwO8Wutd3bsV{G~_1&;~bpORQuW)6@W5Rm5vR$mZC&T9U zu6FNz_upIa#%;YVjm~HVJeHysqQCbq+7EwHNht<|qi~?2mfK~&d~|ntU15}}X?q7* zbHv?t9p2D#T1hr56p)dS*q7|PdB?}SN@CA$J`69@V^<{4(oU)BGjarIO= zpTOd>)z6?mXbn}u7whgz)}zmYp=qkKt4nsP%8vc8FCgR1$sc_3e9@;(YL4$d>gK%U z;rx2@)k|ZvxBTvxeSyD5+Gc)g#a7RCDE{&4lbg1(lPAw_wzOy+N=(yS zu*JwF@)Ajb334tHWIS5EA=44S9Xx{pgH|vpDv$T>#_v2Gt5)oOH@XkEb2Z1xpse!> zewG$B$$NPH=ta!CMVT&!$$uE1tY7&@JG;!|qqyAT(VMug=Xn0;hx5tNY-jg2AHIIz z_MuC|EHIM>jrY7aE4f&EU_|HR-ED&c7>dF)sjII~n{l>NKMbLoGsX3M=i_uXp8d0b zcZ~_x*GKnnZn`?NOu0I)fB$>qQOwg$)?af!uyB6z^SB;<^8DoY=htIU>4uxvTeb7> zs^Pw^H*G1-O|z$?_On+DoKO}urh9OtbBbJ%g#d*bi&MJGxBHWaebSW&1@O3&hv(@z zyk^SM%s!B?Oz+(L(3U%>D3r`6xmWVuIg?gY3Q9pT^E~CWT2NvRFgS?PRo`g-c<6E` zk9X^jwmGK?zy#2JAqe@af)4`&0SL|%lAVNy^^0n`W9OW*#wNypgSksTou1g~vwno3 zE>l>az6>jQasMj^U%nsxbAtID4pa4QhmI1u!L1X4sA@}6EqpiXA!;R$O{+rg^cgxfJEp1Qoencih z&vx+qD~jGxZW!-K7^+&~>!I*q-fFN;nBqoD$Qe-e+HN61b z47sX+OiR>N&`1|+$s(mpwk)PZUOl?1sR*u-5I_})BtZhQLSmpb1WUR&I{7f1wbw1c zg7?>hU*un2eZTm4AR$j;%n7RM=*s`j=_mCEKe?S-OOf!LwywkJQQoaCkN4F?jzppC z-!DI(f9vSYZ#!lB%hVqD1>4!+3M%+8De z7)+&z)`mc4RzwcQy38uZhah?YtfE00sa>87C6w#_tRz5hcmLi0_WHA(QQwUTn${$^ zBpwkoCFdY*$_|NO|7=L$9I1`$9AHtX^3H2)GqDvUgwt8Q6wgdr6sU*+nkj-95YsxI zJosby#@Wksi%nREzPmT&8QS~RZJ&epNciBU99^&}Cjxy_A!mDlR;vBUMW7GkB3q>YC z_MUL&f>`lXesp`M8>RXU$$9!wt{YjM=T~!QU<8trGCGEw2P7!4sP4twNXlS>e2A)2 zBM#Lo?Pq|j$%j=9{hU;Z9RV4Ff`|fZ0rO(XL_x-41eT}kPxv%lI2p{xr0Bj3$olqx zcndBV)NS+6`wu^EPoEWT7c2sPSF**qFgiUoGPBRPO2h+*zTSaG9~g$;K6JWX_(s-(Jz8O2lXg#j$4B zaF3zi)W@5j_-BoiY7J*3-Jk$;>&U?y)COLmJyJb>mdb<2J{5Z}D@+ig# zS(t$WIFG==p{g2J)owqGSpx5cD#y+_oT~*++kL+;Ar#ov(9{lfDl!`q24tsDil`$Z zM1^cBfK^2-+40Y2Y;L~u%I)?F$y5C0_4ikS3Da}bQ z?>&9hKYd)Ey>cv*Ejz9^&3kfLj(+2T3pF}(E~67Lj)y6#~L#UI6S18JMSG&fap^q_XqI?(w-Ne zb^}D`lWUS?hB>6!DzrKfz(3N0?^0`e~Qcyla~ayo37YE`0ip-+A`()j6?cVS?OT zwD}fR@EZ?g!-L4LQ8PuLoT6n{CIYlV20mq~7~p6U=SEBcT@wI!Du{$0#IzVYS5y^| zXewEe2#e#Q06>V&OSUhf<_i$Iipyu61Qdaj<;w;C_TB!feCNY`sP`Od$_6|+E3-M6 z4vyN!Xb9+N5H(alhh{*IUF@Z_-Axt?1Yq4$^S&QkqXtN#g+N3N1YB@vcGGcp|D_(U zvP|3DruEg`V6A6Yq5$yf{8BsyA6(ts<pnds^dgQS4Usl>(L&u zTDS<+5FTD!UZ=_kWgaq(B|Bs?O@melAdmd*zGBM`R8dU0ibx=B$zrZV_CD_W=xQ4& zu5^F^RFCDY^9Kn8jcg6)o#` zH`DmJcn(liOsaEDRRaV115fCxwjdB@9nOw+m+S`yD}}rpfYTh@Qd5ZNObjfKTmgfM zYT*VEq!g(H5Q+ezYRaHz%&0|xb|?Ms|NHjnvNDW`_-|_B4v30~aQ}+monFY9S_U&K zKkl+F!zzCxd{1wml!!%{WmYfqunX|jO`7%+g2VAJ=P1YofF?K$FeO-r?N>NEDOzkr6 zC+`!3ib*-!Uuy_*z>8zOE5~x|cKtmpi)e;a#u?DO9JmMbRQVK@n>Py@?(i61-O=3! zGf|7%59u1nc?1ej`dZSuWs%CgWh&q+-YO%348I516U(6fhL3>a!%CvjB8>`j#%h#)`tN;=>!gFvtF%jnbTuGxvOmbMZFUI4? zn_cr84`d|-BVRcbWKu*#qPilhTpqFkFgsMm8#7xU%Z`wBKO}m0e>a#I26bXcn32## z1nH0x=Yq3hgb5jPF<%Y@gQ-I`Ed9N9D!aK>_w+2i{@36B{N`)VuWr}t84rREJ6hya zob#Z71SztKnVENlBt?nv5HGu>d&6emSrAF!(MAjNzFNgz)CGt!i24fVnVN>iNtre` z@5XxiXviK!qzs8zri5dw>Vj>@+ko1xBmSXwrRq`4@Y73SuJ`4gEkGYYEYklLl0bQ4z)jrlao z`n2?}Z^Ln%!DW%qLXx-BCRR$P*BHNM9D( zh5!I)PzoqCCl}!_s?*z_mkaPsP4jjP`|7dWbr;R2HNAUz&QFsR;KjpBE&hJ^Zx_~25VrwK`oa{y_i{ckyzfBF#egRQ37T zMxU`Ndu+{}e;(_(qXRXKJl1)vFWepr!D4>3j=`a?J_%oHGC;VSK$!84pUmzRdl zVaeotAkAe7E$*|oq<$6hEcJbTo*tj%=V^{g-l+hp`I_T<_uky;CIxN!_Z@V%s`c zp00OqjK+p7Td3$|*Uh`oW|6RJUT(sBA|=k?kh5Svh4mhruxNF+$A$LQ8AS7WUxN3q zO6UAs(CKLRpX^`nJdGu2okhV-$A&JT6k;@`5JD`@=ex~{a&j%sjzGki0WGHj_}+FP z4~k|Fx(BbfZ+21u9sf$!(--)gms74G)tHsQpWlDcP;qtHpRcu4yI0fk_Us$~tD&(bDdC%iowj{pw^t{jXJKfb1R5hD2|T9<2cTq*+bUA!q_oSrrG%bEA9T z=6omHsSbe2m`&AG_3hvVA`+p@h6_tHBLI_wbYOKM8v=mD&P=)XVWL2bZk{Fvhz4P* zmV~3=ANY7xBETZ4uPD#QgLU&KXYX9?e=B@aR-2V`NN5_^DMxhdREa}V0%gR!6+}}L zU=wqQrXXZUR^j5_Vt9S~u+0sWAp?>VA_N3P)e>db0K?)kjEiM|wpncNDs!R2A1Hk7 zbZp#yFz>C1lA;llL(n`8Ye$X+*gSxei8$7TT9iCf~j=dxJpxl3Pnki`Z(8%(Qp*Y84-T^qbF~O;yK`(~OQ+rF=6%ugH zEsXUEe|jEcds^-0O*yLid9@rYzPP*T&Zk=l)pGjm6igrzuL^Wzb^RL;WKeKEI7}2g zs}^Agxe#)6Q!FZ~hp4UMRoy%{g#H|-H~X$*@dXr-?>M*?^w|kr&>e^& z9nSD%Xo$cbGXjuL6(sM<1jM8U~5%*S9c?|t)@lPQX-f0*|KOU8FV&;xlU2M7+J

YJ~Xpw07%ZK^V{Qpxqfl`;DtF*OgZjj*Qdt+&WC$;$JjsU=aj0`#Z4)S z$l>Cu>e7hiHx|f$=}u@sWC90zpEU$4QcMz;0#*)DTL8cX{4ABR!#NrhzgV0~nWzXD zX*tC70xF`K8M{~jWmYs(Wjq*;y!~Mk=nU1ACbNA7MRIa}n8Ae#Td58mqtB;~U)0lqN!C;hjmSAggd)kIh87|#I}{)UW=G^P1F8{eac;l6 z%hkqmDuUn*84dJpz!9z=-CQ4?4&!QErXad5W9i)fZad$9@AjoLjM|_kC2>#;Sf)LS-m49r7aQugc6 zLE)wWDrMRwFZsPNwy(yzS`KyFmL052Qn51o^M`nSHDP0Y zXg!sNoWcwa2u!7vnTUd_ITBR>6cCrpeEO1gsEA;ydOZ6ymj!ORQ%Fu;a!q9j4#Rx4 zU*fR7^QZoH!`07E?&EEmbulG21JdGfU;OkN3*;{f(Nu~75vUn?-&JK6ks?-%QJpCf z068)RWL_9IWkXaujoGjKzGO21%|)QtA>UO*xB>E@z+eE1Xb7f9Sjh_Ne{A%Y+RFM#DTd-;B&U5WT~kv-)fj2W{`c zSakLnFl};GlNKTbbm#rF=9kf7VgfPE9tK_4m-`BeAR;R_I#Bbi^~-12`qj?W!HT(U zCh$#LM=mj*`fZD3%db;_p>NT`+Dh?kNN8%n9+5;n&+0Wp0q=u0T{|NC0Dauo zO%9ZcF``~`6^zK*EGCMW1cPP?3Baggi7o`TB8sHQ-i<7jw3r=?mVf1ueDI1>y8~$I zM_;c$DRvnrzCh^b-`siRUp$c! ztsJKB1Q3Y>7eG(~6*aON1Q7vQ5Q?K*jYK)tc#?0o<#cuba*#3>9YqaQ%?uep6$)FK z3$hsi=r1;2RWwCMgyu6<>OXKjk5d~ajt%S1v6pd{kifu1iJ-PsJux}fDFKiV*&Rt7 zlPLl?%g&d9`4)=~UN+vrxGy=E%vd4|nRHN4 zpkBFgs0>PMSHm4jVD>aTqp37q*x_Q2_29__0i;xy*P*G8VDyz0sViatSH&W#KB?ZaOLT$OCe{6Ock_kB$LIfaI%`u^5he+T8!XfR9P#i<&r+(*n4xGC@ z^jkEKHBS4%BEHRC2J$Fk1S|;*^)P*;dI)7!1w!L0z-F$*uQ*qS*iw5M*WETZZYu!c zyc<`a`Kj=13uGc!HTg*LgZFQL5chYXk4vsB7lo2d*#$?207!_OoD+3b?GDmYs~jO} z(MBPQp*2zc!r#Thq-uv&9^hfLj=*5A$;sGE^9oPKX4uRbT?ml7Jee=mYO~$-QnED+ z>MDO;zrf-?+gSXnBB1};#butxV{>sv9IHf_!9t9nL~Qi?X&oxeeAcZQIo z;Pq}FiI49+-AaQuEN0~M2rl@h4Wg1n6`JZgl3$io*iWgTWfXtEvi07`W63!efT}%f zWR4urRHl|8V&0f&r?V8}?WY;V;+0vXZF$N@VtBt|qfB5;A6)s1^y zGME67c?XL+ZhFtT3v+SZobUEGyfDf zg^10-va-f_vKoQcbOoEda8t7EfQVc@a=5qHtdk26fh!cLq&M+V5HjLWNvszb&n9hR zX=-9sC4vB?MIC5v?!RC>*`SVhb9c1SSt;iBqAwj?Wi|!IVs3x`oOjyw!gYDA_7;fH^)REId$}1gMo#O$iGZtfuJh{^=j@PWylq zM+L9oKs8jFu#BOu!NM?@8H2VlWyGQM|I=M^m zLH*ff{AfR|QcqKkPKZglQ}!vpL|75)82!r>93IA=LDZ2FBPix!`RSwI-pc7FAc0Cj zb!1fKF@>4o&BK$$UFZaO#z~P;RDc7CDoR1mqQQ`oYE0>Ch`N4V=Jh?>M|(=g<>LIa zC`Nvk#l^KpZkHI%ziv6*o5?vz31~4M-<=qgAyv*iD*<;t?)K3gwF!IaSqq6GlJ6bdi$?7T zh`u5ckx=t??@|ISB8rHB0%nBhqa8jI0T`J=aLD;p*im!u-F~D+7j<#sd9J1iKG-z~ zIuN2=YNoK>v6&f=NWVHK21mOLNCe_7T0p;m)m`;kF4W6Q3;~Pe1LXen{eI8+T?|75gB=7yQ zyxQGckL{6Av(i^r(4W)zq+Chi>@wkyFtr=Z!wpe$>jFVU~*yckUqYt zt9%5r(~(UEEMdCa`MPBU$;T2Swr*;Zm=q&G6LO1VPX(fK=%yQ_>A zt-W~F2C1k0PVVLsLse}pP=h(B2vNm(QXn&f5?Yk5Nu0MJRrp7VCLC~ln7&tos9em- zY|~tTR4PJHHDF>uAa>WQd5r2!R8fgYK-GCiGrV<h{;PMEWy=r5 zmWhZo<^FEl&5H!+MSvdk3G@NK_CI=Z zR6p8!WdxWC`i^NW!4HHnB+TAvP8NXMts zSbCNc8BE=Pz+F|1MrymvlNmYp!5Bb{}Y(ETt;8+D7P+dVb-{TKIjyywHQUtsLoND%uZHB_ID`(qhj z4}%$*V%ZJH6<@6GPUaNR9Id!$9BbpjGBbmTI#V4b*;o-QGN1q>a%D}s6 zB9L695tpi?)3K3$;l(+yXQ*RfMptzn!N*eG)Z&ieaczY91KE4ZP3J#n-WuGbPy*5NN7xk=x7KAOaT}H4MCHa z`0ORZ+NSpS0J<2nyF%l`XlXi(X~BL{&KMm)JG>(jA3r)4)2y`B413*}|$H9zD9GL(e4Ltg3v{lHiw|m~C;m=#H zqA*ntvFkmIAqA8|`xjgu{^(-!dcPgCAY&CP%lA5-0RB92s zOiWnEU2W4zgO=ZWT-@t)iaR~>ZhZdfTbH8ErjtXdKwyLxFD^|&1jHmI@78Th? zy=tP>A-$@nsa?U<#rAf^%tVWe{+kEBSk$L>HWrGD$@|4FcNIX382s52Cy#JC^-YKr z(|CT~e!U~l#ZR-=(u8ud{$d6D&|RO7B^U7$*<~0#IHcvYt#|0485%_*1A-KLKI}M= z>p1FnG)4dba5tC0fT3>%bG82B;t|l$-4WaY12KVHWoi(bP_tsigFrSxg{HH?L4`sB z3xUBMkPwU`>&)H(Wdu`Ijiid8A&>xSY1_lYX4tO3T-l)1HTNyI%AryAe&yTAsv#q2 z!C8|Fjh5~;u(`rv^8y_lY%MM!R#L>19W?Yi+uq(%sC>I&fQAR{>e zdYHuu5gjp~`VK?Daok+49&fIXC#Az_VWsK23>er{#M1NaMz^1Yp_)}OjCl%7$L(Qn zDKILF8ip>k5~#xJWz z0h06edU|;Zkhkfkdq;M^+hVAUDpbbf>*u$}HdoZ<*{3*mAtiU6cD@L5aP3c+B6;=K zkB@%Qi5YmUS^Z(rp0wv_)dx}4Z@Ed|_F2z6^75u0`arAx=@)6y=>v_Ytl(9fCW@J% zgr13~DMSP%1`dcsG#no;pTVwPY4W2S9=}WEvsH{40U*bI$~8dQ&2P*zP~gBYn?i99 zMbVLs?LcWlA&-kyt`6YlK#2nwAO-{l;9yc6*_=YKV%cDUxe%2=sUIGydzmnJLu2qt zU4OC7*61*$7j@cv7QcRPULXZTIqTkU4*VP+>E_YYwO}AX09UC*IU_c0wTMPWU|?z< z6aoUrh5-@cvUzcwlmLlPRU8a$;4-D4*dO#wAY!P8-p2ApcMAb@Ec&`$v!Vv@&%@^E+Ii!#!> zxjQb8if*>I@!9ou>%2YzfC+lp$YCUQH823Ji7{yie8I>4A%lO&nRUyxL82x3H_0476MZk6H!k=($T(H&!aF}+*-xcg#P(=*GFpT0|E0B{Fq zLUUD3*#PTZNv@7WNDhD$!Z71V3JC`vAysh(#0YNg4v$^hL4aFU z1F2-Qo`IPVOM$NAf&qX$8lsyU&U|)SDg$#D;3~W=jAV%Ds*Yq?s{z97NO?e>Cvl>Q zcSCS&8hAWTvAj;@tC2%@(M`v&vE7@Q>&AOI`SIEU0IG8W%FNu{$=iRSpPTwXKi;79zN%%`s`wSD#yw(E3))b zhW-8P?^SEpp+1CqJb3a<;GU8^_HXy&^OtXTe3hQ2It)RPNNu<-W$c&vt`{#RA>92| z|GA_VT+I;#(r)z`-+PGN#5jgf6eEzA43RAD z>#_2B3E~*geR4Hp;{EgC?q}gXj&WH|*U$dbXFq*_#QlvH9p>l)EJ}!SoZK4+OwD+% zF)J~eD?~9StfL8F+fIAT!XUw!I7}L^Zy}H)AekXE6SxyIAw|p>ymEu5f&_q}aRM&Q z(O}^xp^h9pi3Jw!!{u-N?B%ELPI7U#9)7hxVkaF>PkjXM{9p|e_fGQx9a-1#-g|6vvBB+KZS+0Ku$z!&5(BG$4 z^Wx(6`Fk?ynL)#1(r~)`ul|pTEG}i|xJXaW$L)Ih=bycJ`@S3g>wEU6X4?8M!`17r zUW`{yQymq_J&rN#mY2Z4_$Qw)Z{pKI3IkAQfYXVWu+p!V-SN3hO}Be%Uc4^hDXq(? zgG^3WrtgL&pSr47x4UMn>r+lKRe1Q(?yG;&{@GztQFgCn21Gc|NC1Hl!Oe}Q3U%m;=r3w+4sFwA?J0X&2GupK=CkSo&?O}H^jNmaQR8Fcz znH=`nKtqW0-4H1SKo=WTDX{58iWsO())*(>+{pe^6>!;l813?hze-1We)9{#i)nXy z)t-nD+}y1~{)PcSYJotlZ@}dK)Zl8RQvdLO)qWP<3@_qI1jGA%n`d!C#NdQPV84VE z`cO2fj)+dkWM`)9Y{YAPmvyjA<$HF9tUfOFvqK!o#OT-6alUEK^TRt0bb zLT7L{n?ac1ZZk*1Er7cKB04gX&)g|@H$@CgMl=&7c_uAD%YZ)JAD&qwr=YpryoZ3R zTGGX5yN4%%0t`?p8&L?V&&HHSx_NncoGzc^VPYT(sCrB^hHllmt74>p%#n%U;_>C< z_|a{yt`-winpu|w1a3gzg09U3%m6hd$ja&aSM{5*gTrEf`(%`^mX{Ar><+b!Ius_C zJL!ki!d)B9m;ezm#MDHh6rq$DQZ!8c;&613Top;j&=Af$6PC~fR8f@*A)t>|1So{& z(2i>5ad>>w2#cvk>qd&{5{!O#OQG=&c3UTv~{;1ZUrshbdv)3(Pj9AS95CLW|3ZUmG z;|Lr<91?&ChM;!-rrf}Z z*oYjFu=6RWm$F@b(OkS;exJ6!!053%9^NwfHzPzaw(ZMnzU*-_F4ehA~`pvM+Pau>_g< z)w%75X(pLg0Ki%K%+K~S2nb+^WXLS;io^j7VvuU%Xpwo|z8%~h-31=Y z8lPTYne4R<dlwu*$SNuvT0lOkd0p1_Krt6*vutEZv> z9yVpWzW?3FKYioYt$9}pbqK0vKoQgsO-2CO4VhMN4jXes0>F`}HZMPJ-o}W8$jxx% zn|ONs^i?y0#mm~pf>&l2`G@a*qF6n^m=g{WM7h!W`-?dAVZslUwIC6(1G~*csQDyj zgf37$+8>7QnzZ{J`SLa|3TC=kp59L>#b%teP8ymBiXkB)p`Au^W>#4x9q^j-fAWd^ zYbB7s>HYZ&J)dx$0nEDFp-2vQSUJm9T4Z*>Y93TWm zLgsyKGQrEo(@XneOe3y;{00Zp*u{=CDO3w3Be59}MIa_udwZ-1YJyq~ zJGTlf-bNh3yz!a=5FE)P)dC=8bO%I$sic-E%D{(g*iH>$ zxLp!gVrB+#Pk32@ltjgv_2qFdqa?-t2cKX3(=U(R<lOP z<@`^L$lV+q6Cs)=cW|7~#SVz`Y6}2F1^|c{&6zx?Qvd^>vZ@0CA`uWOqB}Z7K>~5Q zl~?7FWDNJwHvPjDt3(H07JzVktEWh$)y&CJ9HE3Pp>0qjDn;C^f zk2deP==8@Dob@gQ%;P+VOhm*S z3=o0Q73Xhy1d21_nh}gq0bM4R!7Pxw3(QTTxlBehIu8i(Ts;%I5qfLF>;S}p5-A`7 zGNKJWcQLCXfg$VS@@`lL=Lf>|`gk!Ngv&^)`!RIkfXh>2P$4GnDzFO}_X#o82w>Hx z|4VSfroqA?%rr#+;Mh!GwB3Fgwx@oTa;?$|s2UPuXd={t21J3N&Rslmnu*y;Exw() z1Vhq?fA;DBHO52Q9_T6zlcO;Y4M~UxT=cPIGbUFD7h&>RiMtZxBqMO(!yP5gbs8N4 znBxq$sQ}{W9s`q!TDy4NzRiG}=l6niJ(PgJTE>ff&?Xqr%l43loZ2b9{P_LxIfsB? zDuTAW_?qg^M(|75jTAN~3BFTM$URi@p?n^iX^G$DtK2#$!h#j8Ae zG;;t1h$E~zv`Cj@Vz@l~F}PvV7P%oS7tdb5JU);EH>ZE}2T#uqcMH_LvF$sa2Nm)2 zfJ-S_+gY~(8fKgAR81-nDG?x&tA~aTInYyhR{tcvxcK?&7eBrF^iPLpcnX(v-$Wlz zF@qEExLO22o!dzch(;YxPIMfltNi2uD4<*&T{A6n=7Z`182cQ-@?MPd`e zCPJx>^GU{30Hnmgp$Y{CgAB-ZJ3oaOxB{FF1Tf6~NUzFmlU0EbL==$Sp`@q-cTFHE zVvR4Pdec~DbHKnn5gM_M;j>i8;}PO;wUMiCkI$R_7gpC!xQU0cA>_s&w*n2DFt)*@ zvHgD8l(bZdY^;RDpc64+_P(A9JwZqG{HNRvM^4eb<${Z_w*WCB2BOL#5FpaAL-c7C zihw)!cduW+O`G>VPAQ(Q|GVc3?N9z}rH@MyAP02^uh2--s#w*{!8`;)cQp?!)J-`- zU$%{!Fg%{(G+F0|3Tb~4y(zqSOx@mE&`?$%@4n#a)77q`;_EM$&E5O)qna5{qq1%v zc-<}s@$tDf2{V-T`S1KcbVY9UEY?f z3oZ*h44%qyAO1f}g8jn_2S<0r2&&@5JlhJ-iHu-b2?z`bLDV^r8GxJdx1XP7i%~r- zI1dDXgtHI*9E2{V0wye`G^L1W=0rAk%iRpQ@A9E=TP;rNay;zi2nJcRLy7@XqNs`l zVun~}*B9r|y)RRd&9jyh3a zD-eee$(!Y+-g%N{IZeb4DTWTnlTUy6Q*3E}?4EIkbxEAPPg7u=ZMCpY8M-KhNbC;G z`(G}X1OO@?BZ`;@^#20>^v)t(Jw&Jl6a6rLsRvLhO}y8*JZ7YLcvtddb2ozs=`VYa z%yH~X&6@T0#jk$yDNpH(X>qm4PM^et>iTpljs&PNUVj-*^`eQSxujsm>}ZG#Ob*;8 zG&7YB&0``)4v1>#goNzwNCe=n=+nuOcCAj!>M7~F5u5SwJsv(;mEr1cy88b9YrVQJ z?Xq9RQB`dyBW-dHn@}j=hsW?Acpw0{A!I~X$C*}uM0FO6#iAStfgF*PVnd}Ue1Pe| zd`?C{Ab_|Ehe;90W*+4HE|U|P69O@~REp@T20%D}5*_1my&H{*6{6KW=7~tRRkGUM zn(wt)@5mew(QB8+Q-#_f=wV!5ym%azYd?)kL^gM2o-15bQ6%;h2;6~~(#1N{a%2Ju z^YPvQvAb;c`{2ju>g`&O90E8ZzFvMcva}(UOqbvE$KfO~H7dXf0y8I3FhdI9m|Q6t zsyYVXXsRhLMip$}n1Eu8jMY807kK{;Zf@G*sjC5 zfyit;h_;Cgu#sxhA`FRhB2WumJQ-`J|YsjQvg5_BQmQokewxXaqdwNht$;Ahz8aq z4wD8-)4nQ#?&5o;cq(c@Za9NnD6QyzY)BdtZ2P@fHB(CASVu%&;IIreKsZ3^lvlEY&=3+~sY=YV z^J@ZOWJ4Duk5R>_wZ>6I0|JF6k*Bd7ToIe5BWtW^KyOTG`2a6Hi+_6Bjke-#GVW5a zod7a3qF~aJb67~WCPIn()KpbBaD~vc;|#8&!%*Y|5`!D{5$or#U;p_3ZZ{aeE}PZc z!=~n3r=e0n0-NpV&&|pCN0fQ|gsjIl`Iwh?&E~GWcxA`h6s?ctt+rgIO;f4i zD(X!_2c=NaS~VV_)RK~cn{gBGtHnmUO|v`dg7gV0*C)lMFwCG1D;3Z7T%}*`Mk$h7J4`(S#)PI7qhnyN zz<|V{;DF33PDBhLgsGiIv(3kU0vu8z@8R^`l#=Cb$*5FWjX9IO(8B~s&BgWGQwbQ8 zm5WcupUkfD?(UeHYNaPIBgWu`QLJM(2RBKM7E++kp7Pz++7P^YN;2NwZQdmR@j+LZ zuW52D<1`6{vo8ER%mpz1FgBcVJuq+?^U(8~vR{9^J>;LAHnD`J)Qgt7tE)|1$f0@+ z$8N`^ZM};ENCYN`Za~531!4pzuwlwgX9bDX04V_XGPoP~j5%;5Gay&(J)mKL`tuFb zFAV*J^!PM{``A4*zuiBpLV+M(AVIX_{ zWCae@$spF4nYeAiJ+-V>v&Q9WDo=?4;F{_Qk_^f$0tpNei5$hv5s8ojIi;WktfpX` z-_0hck2#s{uIaUDkU92tgj&gknFLh6itc&8%3_w z5&?n0 z_4n=K{{3V%E6vNXBN7F41OWO_SK)jVN(?Bwa6LtsEwS0l^_+>nwI6PTI+ zf+DjQ3MB-&FN?fa+%8{UoE{r^bI~s;(BTilvuAp*X>oI+{@EDAm;27ee z5Su^}B2m|bs?MsGno^V4T)Q*sJ3|ayfiapg8Rkl5;mPpws5h4famj+V8xN4s zkm1!1hwkyZwLXui7HOic9HDOy5`rrf0GGCJjvu9WTgB8yHA4p2!ZM^F@z^&_`N zp$E6ykVac~H_OFe)MdUt-hO!jdM(mv*CiI_#4=1co3)1EE+O%>x3)%|@=>lOkURIN z05Q5E<_-T$>Yr4PC?1~v0Yk!Y>R|jgUHW1|i>3|^#Grtn z^3lczv{CxN)6+353lbsB$krM{W*Ieh+w!ow_M;xl`hvYBlm%6cW%m@r$A8jZLnLAj zOu(jY%Au|_6IgQKsK`bX7)`xT;9ByqE`kv`klVb#dYxjh>{Ptb+G}4~@X-&4pMryf z2(PcgX$nu5C@0EcL(=IX`G9l_CERaMa) z0m+dF83@b_&8TTr@(C8*Dv#<$joORw6>hc$J|A-(0L@eZ9o1Zr5RkDrn5r2861e(@ zsj=P4>cVn7h0Ute@ubeo#OAFxm7RVFkFMrE6{Ogy;pXyiT5a@L5vjZz(_yvZ?V!Wu z0<3n+V?%H{CgR|_ftwTvy_Iyt7H(c_2l7(mg*~3EBLSEZ zP)dZ9x+d4FkH>G;pSF*W>G}F_3=TRYeCFM43K*EJ*3IjuFCJbm`h*@3ajN5K7*D0P zT-^Jm10ZpTf&kzSeJAcBV2*?VL`{hZfv3rsTic>LFBhrgNf1N;2#karz(5TEjnDz= z`B^+t9Pc3)9|3|A{zRHhJ6V)aj*=X{OXR;2XBY?A+`pQ;&JIw`)WPPn6evz^Dr&Qt zssee43=W3G0M6kWbUbLc0)qsD6KUJT&CMw1ffbtrs0p|Wx>*f`4#?=P;O<6@u41$P zA2_~;O*+<#rPayRDTjbSUSe0er^cc6#O8vVHG6e1K=AIf#pmAkwy)#y;($%VhIwo{ zsNG7|8+*HD?5~L7P!<=5(sxUQffpCyc3b!Nn~&c9aam4;=$cCaiX05gDln)W(juic zvT{9Iixo=NP%S3~0CI0!wK53zLv%qJv zB?Uk;WOfyq3UCv++N60#!n%^E6S&66=4v6cLr7pHBfYwKd-1(rPB9QRql{B%iP2|F zd`m7BTK=&k#yD=jzot@Cl7oqu6P<^KPzEI=*El_#V$;SY?1lSgA^Sl)(dl@-!Vda4 zgKIdHS*{UkRYeNX#0+)HiWF05!rnvM=;3G$TUuN;UrrOW(M6p>Y*w^@`Jg>7IOm75 zMm-%vcQKYi!#(D{TlM4pPOr+-p25GfRs9fuMcoi)DY{?3GXNqIf}Anbc6Lp+naw;) zV*_{y5ycHWwp|*ij-|bDKNf~3j+=l1(Saa103tcKRmGXlM&@DwCV*rPZmQyZW(B3J zX?uV+4T8}WIiLuz0}FfO@_8CF0Ql;nJ=}YU*-{G)PU+(ExR)jYl|d^}*yqin)zgS( z9@}(v1!IN&MR?M_YT+<0+jsBd1pO!cE2QnRsYR`X6)}>7ms*t&0IWi(7;of==)jF8 zpa==n5Zo*R7M(0O2PPwKvqWQ=Kg+kk3Ua#*L zhp(0|^z;A;il&uo&ef34%}RuM9tCvw82XD?$8u_yz2`K_Cfz-bkIR=`Yh2Fjvnvpo z1CCfHW@11CGAVop-yc)caz5>Q)iTy2ZpC6?3Zx3IPD&2I^X&YC_B8@R!ywS#T)#Q0 z4=42)J0ABEk+g;u{?n&1{#}E<&1nBi$&EhLpk%XHYc50G#h%|E#({Ha zA2K!LE^c1`Eb&A5EN#Dc{G$EjE&P_edyv#E06_swU8{nti^m3Gae4EYm$g7}rKo^v z<{W|>wQ)RU2g3lW3R4y5fX41XL{7f=*uHr5_QWk%(8iU50S0hz127;mjI9u&xjLEy z2a2;FyIC@KB!FTb2@#42cRCE18ZXWeQ_Pdx>(4PFG@2tJqDoc3xizVfx<1ADRBES;UeA)EfKF!MPGRV(_@hY&Q9{8_*%7YEA%%t|AC%<`A%s z7$VmyOq_h-;5r~vDmuCG%;9RVYgXCgLL5eSMfj|0)|+(}13z~F|=UWQ^&D#nv< z$vno##wX~ge3!`Q_!gn{fk5(ap)2R{1h^W4gM*uT1Lwo@nI!He$V`A$!Zew?IHNkT zl|2f1d@&AsKP?5#a0YtK>}8)943`>W0xxa`;5E35I5UGHvYSxwVscllU!<;6P>6_O zF%_T{#jse^BHXS0Zn8i!w01w(Bw;++$*(WKmxvCpPm?vlcA0{~ z<;#zsTs5rYm*ppm=T9SDFvYWStEsR_B6Ja>^+|}iSv)?Sh>*I9T{~8+RV>BC-~>#n zN{ECev$Jd<3hqcuNJf|zHF`vk01}*|n*+P4y15{c18_tu3Z@QB7(&zeWL;D8O3{(f z=L!jfa$H`Fl2g-G;{YSp;g^W(X(N5A#| zD$D*?eU7n>0njQ0tHCKCh4vr4zt81V>rsqDAHqVf7TXENQxQwRpi+ebSpahfGYAbZ zAu<9WGeM6JpdC#~YRi*30CEIC(=$fNRh=by9V>x45Cbs4tjcdm$cTA17eEYwF`@&d zh(w92)J(;%+v3hH&`S&oz-=T#m#W#BLuz@yKj=cn966M1-L)_#v_bvc>LdpO52@z~ z7ZCf8@$}%%ueW^Ie*RD~Oz+JaNrD)Z2#H9w_>5v_rU)SFPGTx%$Wv@OH!aiHT*Z9} z>3-l0}ux?N#Klb-!;4bzX<%c=|zNPo;E^( zz=!~|EFwDL>{zB58o=1No2o}#uuaBjcz3xd(H~nxB1QS!oSN-8 zu|vxd4HM^(C)H^BOMJO}lIRx0vWvlg_{r^`)O-T@J@}WW*YEaL^4KjltGB4?;F<+u zqQz=Fozy7=TVSD%iaU~3$R@>egTQqZj9^6tMBSQ1hHipH=%}4>kfW)FVlW*w1xHhL03N!=rtBdGB;tVciV;JWIv$53udE1r9XpkqO}4G?b5GVR zhvqs@(lmx>WduMXIo39g&lcNT#;`ixR*2<&6FF$Et{;AUL?(}^MwUqz?UJF4zIoOT zckd33mzs@ZJ5*()K#WWXDo|F97Zf!zbqGu#X5xrs#Tl%o^z!@utEbqjIT5Hst`A=xjJzyO60(sNVOZ-~{4)Vy_k$B*CeqRl9_?8QwnDKm-m%E2>MRA@TP)3GpHzeXI9g?wZ~wp<}KQ+NhbHyQ*6$K;NnA~sU67|Ss=!!9)C zvpflc>KG#C9NHeskY}19M@G0RO*!0jU%Z0b+OF2e$xXzOtc^9RTOT3=0&dYAtU^WWQQcR&0uzx=|V6u=>N4PU?%A+w8>%AvEuF=-f_hx^ zC_@X_wTo*=UE4NIcz#2jIpQ|J(CF%Ilin^iJZv+0;UQeYxR zZ*HF1yLUqgDG~x!{1!86CSt82xngv8M5~n@C_M&)auX`(Pddf(5IHF)$zpHCJ>51NX1LH=O?Q z%U@w-U_KKb01%PbmF5!<0%41Gdg}@S(NuCi(zE}?`v3MnecZj`jNIKP0GEQXwQ1C* zlb`?KK|a0wYORpE(_xBdDK#kFq7OP{mhL9Kzk4d}_3I!{b^C}R`t)EIWMhtt`E=y~ zOpuJuFWdx;LI}1R$10FQE*LB}f}7QJ`@ST|Cu~}tMVHN7=Z6Mn;Z{y$>gEpYPE3gO zZ6dq51E7(re>X?|`^OBz{&qtR$bns)O+#GvX(z^s+@l&s1XzoB6QC3T05>RN-)f5h zz_(5E=;pKM*9`HFF`zln2P7~#5L%f6%Lxf(2Br`dbPwi2w7jnSd?X%-siRDU07Pm? zR=vFe#wl~Zz*Rqv#zWJG^#wGWy`Bm@?E5qDduS4~Iblp8(sX|ya-+n13IQQ_up%Dx z&;WrcH6pZ*qTS?frqxgY#e##IE41C^0knpgXPk$soYj%c(8ayBHK%9#lqX6ZBXL_Q zA|Viyqt@9Q)6~{ez3Oh?$3v{>Qsu+fN6ZKYZit9P*jjAH8jS!bS zyJKt(9kdWV+#eP=49CXT&p!WUGyM?y_Wlw2lY@g3g%~_5v>q3IpX(?SE_piCa#Wq5 zoDvYKw~OQXS9B2I=z#O?s!A9l0~|ecF5>CrUL%+8_Gc5v`o!H$^jfV)1R(Q;o7)H2 zzav%$WFpns;urW#dew7n7~ND=ziW2=eM9~H)Bpg?#3m%-SgJY4HXR~$o#)C%A-LEo z9|vhGPKbnVDh@#ZRw94U5kW_HP#DjS;|AK_tUoQUw=fgB)Z7hF-9(KkX#uWHn@fmHP)h>Ic8vFW_#`+_hJGcQcg;hxHHm-QI0Fb?;6;C|k(!=`*aIK!_&?V@9g2wtP;*%CzG2K0SX0D6K??A)FA>8&#O2f z0J6`-FhM{<`c9z!?;GdN>IXm%M6;rWu&Vn6H2}O)wQ(&F~f&nn82b!B*2ncEj z@)(ymrC#}PI$7HYm!JK4hAjFNVYvN2l#CU%bWvPEyqh zAQObdM8rrusRG8tWqDu!%gdjF1CbXl=jj~)Aox6kHvq&5@*!}Dil&ML(2ftU{`9ka zXu4xftNWw^=#}1Fz}vWzQ-A6&PTQsrQYs{>27t&hvWS``em~TU`qjNAo8DD>_Ih#m zaOkms8};jQoEGi??nV)L6~Nsc8Nl3~7-80i(R{Mbe2tUyf}5(% zq+)~$&b3rn5;_u|(fsZ+&>ESxpb`MYM<-#c)Yl=xQaCn%VT&G^_!!@^}Kd90y& zwQ+(%Nb7W}^ImM`=tjif8rU1anHrAsQhU~s3WNlPPH>jNH>W@{6ii5qt{aL&fU2?S zqYfz3Vo6xX5)2~=G=K;Oh{{%lQQFHF)4TS{LNkMZF(9hlzCugil)X4V$S^{F=?Ai>yy!0J#f}q zFcX`Ffj|24!1=*8z>QQLq%o(YsNiOf0maM-W3w5`oo;Gv2;GP*_&f!w`lz^3k}MKAtr z-21fP{7r3s_&HFMpyX>ncQfM;_+MAj>SVx37`UFry?9o1!87=5Zmko4we*E64AkFmMbv+pd;dr z0dmf3tl9-0O+#?7Lldlw*#bd5RfklNT`4M}qXQ~gwcxUR_Uhpsw6uqmRxfm1P3`9N z<+w~qtuamFNH*UQ3EZH1izA+EnW9@vjCfWl47&vWD>x6M}S1Y0y zv5ae)GUI-SArVfIiZW)8pul7uK&UzP)*f$Z<><+Q@g+JRo^`G~x49&$+U7g7>`6ubNK;3)4qIy5Bo*V&T zlFMDQu^K6I-s5_02|Vyr#mn-reHm@ya9YQwkE)2Yt6>)~h&ac74E9xCR8KT!2Or8c zygZKY+8OWW(F6%Z6LCuHrc#X%0GM4JIU^AOm=G}mcme=b`L1jI8w__h2qs1tl5^}^ z*=4S1t`z)w>8G7Aql!zZ@mmwte|MM(n)^I&MwO zWsoD=l+AJ9wjf@sAOMC$2tWZDPLr6s!oWQkrO;HtTH)nG>Y@76{-ij1=)l!ObSae) zs{uBo0$Tj5+NcFKCjwLB0b37l1?$8VNE-vHBDoi_PIL{n%FFuYHUEmzyZe9&7jvef58D%d7&^XFTvbH z^XpoGfT)HNYJaT=Fr?H7lqoNc-0?S2PQV*Vqi{c3)s3J9elMNh0oi(xC zvj@v@@w9f z^NYLYt)>R6faz?MjWed)c|Ae}iX6)U;Of(90yDJ04rmTY0$QBW(G3yZ8zfHsq8;lv zk~laJfPrUZCJf&t^4~T79f{{)4r~asjcPqXcd;I(v8aX6<$HiO3(fx8$-rkJh`;TI z21bM^GvOXSn8a}~1R@kitbzfEiNQ)dm*l44#E8Y9Du7Kz2^k<7lH}Xm4?j8TMO&as z`)M58_rzd20`AAhy{x-ssFTH@EaTH))f}`UCvtY-gjGT`r4ST=2}Gyr2&%B$BpIB{ zyG^fg8kfP`Ii@vL1v3C}%~piLsx>$(Pa=4-T-x69(YfEO?;fuLxq1j=WY-clYLN;x zS&$Hc1DPn8JGs%^(9_8PWV_Qq9T(+xb@OQUWB*!mh;@qAogQ=3m(Y~mv~KhAqHdo? zcCSv6#N`m{bh?#~Uq0T|%;x4QavR!4Q>$g5Mcl*9saBar!NbtL&}oWn=2q%(MFeIh z!7Lpf`;wN!saY&5%mg4N(@_%Z=($eX zL7TNBjmuZ}kArAfSM;m~7)+fbA&?rNW3Aa`Sbg%%Ff^NP+^w6ar@BrgmJRUDg^O##l-I#eJ60O(Xi zee%Qnzd@KI6VfcZ4BsX4-!=Zm9dzb5g1~G6V#G4J%du2Uaj|$3G4-$jan~xKK0^-l zZ@S)x`}qfo)toeTM(;7Ws)H6MBtmi`Gj4!DVIGc|x_Qk3Lp(U81 zMygs(-e5vbwI(UW1EE9H`yf$4)d(p8O0{hl`dqfv+N_nvYScbUcg1VKcH&EWFmY=T zOwjDiA(&5#47@N=Zcg`leN~p@h_D-ou)q54ZypK_u=G_~jbHxHA0G9oi``WD`qOe^ zK?(tN*D{vrBx57i_~YKqfj9)l^>qJkx{a!-k7-3T>$}8tH|~RvhyCS`f>VDG7G{l$y@iVjYc4&pf^p?VoU}f#@_Bmhzy1SA+>gpjwP;-jSZDx zqz0aNy@XMV#u&h`UFSm$1w@>fUQDMFc(;E}A@4^9n)YPEq5t$oPA6Iw@^E7(7}P=l z_2`CX=e9qBlg6g(tUK_<;<}vDSZE;%h#VH2r>0T;MgQ=lx_bG`UtVzkRQle^Denm! zIS{NlZ;wFNVZD385T3oC&5}H9*Q; z$qO|4^z-ucwuM?D1c%VN0XUr(ZUlr{lv1fDZ25QoXJ5Z#0GQR^RB{OrU}iuS2MUBf zsUlGm3;+Wm7IZZS&xlOS|Ka(_|Gx1z@tJ>9@Bh{KJAWT%a>KWu4_dJA&_eWT7~E&b zVCF!G2wsYqtA@WM3idb0x5zOEL?l?9L1jkdh8*Uan;29L!5wN7uQ4I*i5v zZwMp{^3cL4k?O}6@@C&~Zkvc4bb3Gv5lxxF+g?v`2FxhM6s#6Ozr2nN)5rf39`?Qc z_TBCG*T-L6OxL%t?vKMqvi$jUUD~VmPP$wXPTkjC+kN`0wExHN7k=A*l<&H{Ip}T@ zQeR(-$>P(iH$Mrd8}W3wS?xxGNyG2ny|3(-KYVy{Kehdl%1yXS-K|)B`Kmm5Uqp^m zyLr%6w`vYTMG&1BJIbE0GVd4D-3IFP)V<8Ro*+;;4wjpS5DCWTi)lp5d|32Px(>Hp zivUtnBRn0vZZ-_nBd0a-NNhwx?%V|F{0q(>nEiB*)W-5%#fXtq_7U*yGgaA$iAnJxO zhINYpDwA^8R(&u})6{rL)een}%@zdo~U9YjU3ws`bgKh zd%8#g0Yd<02vHq2n8Sv2#a-V;*6$MeHyq|jrs_$Ek%{JU2|z#uQ&Esv`^)~;EB)n| zcV@#gFBK7Hq=%{^(OE-BN)>ZJ`s-W0ftwpRt^01^0E!XR0ZZNO#uv}!5ddHo2#t%V z#l3&gKfTS1$G=D`toQ5LaLifKDiDpPfdE4s0l~~ntX($KOv2=dj!a}?N=QtIu#brp z%zGD0o6cQ|m>Dz>7MPWasyiT6A_78;$g5f{948cV@!||fCJi$o5ssPr)=SPrXy%B- z;0`GLasdru8z)1{_csnl?hg7@S={WzeyXqFeP=(ttb18+JM0W1nQ6G#{8=|Ft{-<7 z-#^~%U$w-Oh3r!|=w=yD({v$GPOH*+!V{*=uXviVMN|b;fYi0!-cyI(ZcM9a2oXFblXlY`4kZB4w3r^#ayG(Sw;-l zy;Q|WDvCs4MF7s)Lw_ZLAvlJR#;;3i-GIo=iR5sqi<|!8te@>ISFOwLx<&(zSJj#0UxjQkH7q z4i?y4>oip-C&cL490MIUpQQUYIhkMxqEI}|rV>PqfOP$I99caG5W50H1a<@DwCJp5 zT`u;fd3t#4kP>WvI$fXs&2jzXKaPu9SN6?V>&=gT`UGLDq&1v`e)ag@#orzF%P{@w zY4LI1J0b_Ix}n`u<0DSxGTbe?_*gqkvfGDdbG>_5U;v2Gq{<|U1rWU!2wp>KkcMN^ z-UZAs%>XQ7nlz$A#8YXLP2JPU6UKgVKV`>;Vrd)K)WFxp*b7A4EEY}PVW2=1Km!FP zFoFiXnM$+TdgM~S1BCphgFwL{FuDSvV}hB>cIKU%VE|M6JLfULEbo~=?8q3H&^=cr zCy{y3Y|1n3_^d0OG2}e!{SugAGcd{2Sf)qPHpl?c6j5DW8-)&%|HH9 z252Zc==}xZs*K%84C+FFsA}eo+taY@Og%JR0wn-96|KMlRLXj?26vkF%Z{2l92-P3 z6@cUiB{`vC049uc;h@LHW7lEh#R*J+9mv(7ss#k_KmO>qpY6ZegH&uHb0}bD6ynvY zWyc1gAr8=m@oKoDr{$2I-yP_8e(=Zei&cAg^?Q$=Hsnu^K_gi7c%QBwkL4S={OX;3 zM0Gld5k-P49wlw)_;9Rd0(g8J7nCQz*nf8U^YLb2Hnr2RRhyzKPz;WYP?RZ{9mlww zj0ud8aOM)bnj)z;AUI(?;+j`DvQC&#Yk!e;H5`Z1_Bf0&#c32B{CbZZnL!PZP{g8n zf)Q`}LmljtzuS?2(?M$Jh*3A9c(yUPSHG%ms3KK^xV?k|U z(9Wb~H%I1-h#+GAH1#1dimR!blb~9KurOByv;Q^f?YjqWEE~ocB7=!F-Qt2FVC+|K zD@21u{0!dyqy1gP1$MEauO9y=^wro&+F;T@FNqK6Owc$!$NL5SIm_42FLTnzCqpKn z0R7$c>Jz@JT24>xvoP+d$8n5s^=bcpA2A`T>vlT<2t=^Z1q+G9SOrK8Mr7iqs5`le zp#iBmn_ey6m&@S$kvI@hw<&ay2raIk+!6F@=`r>rHLgvi`fEgu#6)x*9k$Q;1@8eZw$ zxR@ASiPR{l2nTOVxH>)Mvk?Vk_F3W)HpwOX_E+KjcjD>0#3Y#PRNA$6iXwn0m5 zUcKwPdz|3%_&CNrUA=nwwQZiTRW0|QOw>vZ2yn`;PY><#;bvd{o8>RI%`T@HK%MYi z^U><*VXqgp^^1?J$g;^3wJk30zKH3tbTES9zzhPxq48u82!n|?al}B@neb5%2x=vl zE~p_Yx7Vi~dDLdbQ)+lu+@0E{H|fJcBjn=!X4u_7|8)94+|foWvUnnQ12;#jXeS8! zhk>Aa;O`RoHy;SDGH-Y>WHU2BFcm{kY1~DTgZ%B+`D<4N1f+BSI>}iKXfCA@fB@0Y zk_1S9t#&`FnKrtr#a89%+G0>O z#FS2t&8mIW`)+Yb?*U>g6xsBjdq1_8M|LL?X%Gb2JwR(p$Z0a}KnByXAH!k-1qZ2w z%55#FSr`lfWK-=`+|9~+q%jIMI(eBG!?oLpi!C}o3-6u>l+r90i}c|9 z+3!#5!L`_XDLvMQTpF{YG00#|6VQMpD;!IJ+#sq3#P9r(|3ifWBc+sPWm`A*4_?c^ z*}xf&?eOdW{=5IZiy;MS2z}m9r2vWoh7ieQN|BbE)w6dYfKf=fRHMW^DM7}jP^nK_ z$qAJ=Yka?NLJT?gYjrIXgc8)u-K@q{EYpqx(%eS_azH}I09I@5h8$^;4=s_5s75MI zKmVsKzacIW1|{&)YUfAuxIe?gs#b9wBZmf>{! z`0Vp%pT%E2TDal&-*~&)T)*3~6F2Lw5?%LASsjNL-|L?y4Q&FDt2e9W^x{R_{89VK z?J+(qRA}7R^$y50^ZG4H#-^cN+czk5p6VgJd%Zdwn>coJ-D5$ZVXGJnE!RonqTS`> zvhc}Plm~qrPPw5_xHkH1$ZgROgO@I`iB6{kHa&`tjH}IllEhF7w;>$O|KIHWXOFE} zmL7;Lv(0Oc342}o$}(Nm-E2-%v=U}W4G0JjFoM2G&_B~p5Jv8+hBM@VLpGb!zI;|@ zW#-N6!XNjVZPr@)5I2kLCX3ZoERx+-_W^E1oO|B$?!ZB;v(0)85i(X0^UV0VLGp&8 z`OC(an^Q$ZzF$v+RVlB{()5?*kbV0K}cc#iCtpr+dnlayMr2qLI-dAIa6 zmzfz2om0YlUrH4*j7`e|Zeig7_nPT!M(mt3A~U_uVgvvS;#(NfeIz28ygnbOV(i!q z%rR>9{G0#q|NhUvvKYEsk=%wlKe$_`xVQ{mzM^^2h8PGq)$<2W4-EOvZumOe(K*d4 zfBEuu(syrDO&Xda{cs@t<`2T#x~(nltywNWJsAW}dEb`me8bY8taYy@jZ{%pIDTuo zNsHGGP@q6bz$9Z)swN6~-Cu83Se5~miAtA}pw44c=k5H~&`M(=u%?50E!2oQDl;%j z32j@A!OWn{rXt{*z}3__Qn~+-d{fB3bljWR0-y;>tuvBU1Gx{L$A6bw{qq*~Poj2S z|8UR6gx8Ky|G^pA?qk7BK}?9ys;B{o03Z`Ps0OY(w(Fz=bf^N(!C1u*(HsR%VR2(Z zv&Iytgz|Z&m6u9U=U0Nkp_MFR?8($91S{req3^B)>c{krZhuO< z?WU|eA5wGn*zIn%ATIh^fVt|ueK!&^o*kafPu$Kc>Aka>=$#-jlFeX&Kvd9 zFB=4}OA1U4YXV1NV3hz3@s~Fve>oHDPs;cH`%gU%w|lXMA)#84LIh%l;>n{!Wk*sV z#)n74POZj1j~Sw~Y^nyPgeFR;$hG=qJ(_k{M_dK0Dh6baQ1hH}RRd5^+nqgXZ&PlH z8JI~WQ&4c0ocAKxMzL{g&iY!^z^qeK1hD{86$$feBZXRNsw220rg*>OzfXuUViP4n za*QSa(RbkNj+;pibkgoNl-Ao!@x%S035-n(usEcu`yb!jqN{?-_im>%oHo^}9Gxt# zhgVx#c9R*tV{v==@GD>3miNLJhj&1R@Z_DV?{x|{gO0mZ1@8%Lyi2t*$pnCbm~PVD z$yaJtt%ha_#&T`Zr%ux_gZFNZ3(1qu;#{>z(@ao`x^(p6i?|sk?}CVU_d@&YO=%k? zBO^3ea?;}k7ZXuc^F;(EmJ%Z7TvhM$liw8bFB|u^dH6a70JIvZ5uhO{(7)@_^^4BP zUk1zRYZCTr2O#@th5VD1HzI3mO%05qO z=p3VpfGQ}f-BVi-%?L3Bou}%Q(4d-Q(R=?b*IrjwJwIcOCQn{ zx1XN3=kt)l`6Ie9-6@5BrKcoH2xyjQIT*x7+{vZ+!aCj!eXm@bXIl-NLO*8o%nA{un52dSN|9(FBcP;H^yJLrR>>tPZ# z@71y9!q}(lvRJ$Ebe=0AY8I*mMORWYh0w)GDPT^Mp>xDEsi+ZgRr0S71_2BqG*XNq zdnOeXR8>PmVg!?FY_ajC%+efg-YxC*j_pP#)AWL9e{%~c%C>!V@y+cfVCa3uJP_MF z*9QZ~TG{}EK)*`9?9}u8hxma#ljpkt8(IHv;vY8O{r39ZueI|)IPtpdI#;v^w-2V| z%*=T(tF`I^Bz+disv482LLp~Rz&sUm%XS0kg2$Q_orQSdP*O&b&^_Oi3&}YI11aBI zymR>eWo{Z1HP^SJCL_SuQAt(7igRQ}f?Avvk&5Whhc|uXUpCNQ3zJ`ONAKq+008_; z*a-Z>WB$4C{~-{7njzhHpNV6js%GYayB4QOrgmA1b2)fl$cg+kcQ=aGR8` zpIwgt)SbM;ucjhatX=Jg>`2*-#7GV`?Wiq#$MEH6<=g}t2QLOzDphqJl&}JzrQGth zQU!**ef*s0C{0HUieTl*tEzD~HWdKCuZ~}ACL@RFVk?|;B`XTfg`5jJtJ#c!L-X^u zpY%0bFk}FaB4mIB|E_HAmxZ78xA`CY{9nXt-}!%Ao%HAOk$)D-PhJE7NC2QjaBmr6 z1^yy)@@Ily|33Koeg4T|*Xu$4gJytVZr8u0gaH7+eYlt+5xL+1ElZ$sWDpwGX>c~V zfXax`8MeGE7%-Vu&*Uf8w0isLJGY5Y&ZgDAxLg5c9Csa!ya+Y7Ho=;vo39+d^6lpQ z)mQy9kp)dsj5U?;ZtBkF`l>}0R%pUh9F}ZsDh9zX=P@G!+L4Wj2^P6d6MLvlhU8C% zID}+;@J6Z>^Wo9L&%T|nI|kX0S3(&j6Eke$e*NHbZIb8&rA)0$1NzxGPV?GjjUSne zwLHz_4%7l$0V=hrGKAs9f*wyeKC5YxuFZSNCM(!Qfs(2KVY#trkL79HM}`Uxq|Ifl z9w$<2TP8~_7ctuSdD10`%}s7RG@0xc{MAhr19OUJxBK&ns;-BV;rX(=IohRWy?sP; zuYl>$EU=$yzt8W?+}BwFI74(&taS4}HcEBT^u4+DFEAtD|3w(-eX@!D8-JTO_^XdE znIdRPGsxv~-v;q-AfO>LF`<=J~xscQPc$&#!&KFM8E;-LSY6X8RUYq=kX0GU66`+Sp zd09o+u^RX8x>Q7{*(<1$nJSr@>lA81hw%Xh1k>6S3bIjl9>oROKvnUvLAXpf$EFNA z@K+X}FgU7M_uwW9Xyy9cH+ib)LQt&=5~TvGa@YCL!hH907c##7qDY_!^s{{+-{7wr z5CG7Od~^tkY(?Dx)e!THuPsdiDdg&bMA;X={N|5u2?=+74qy1YlUk7!%{eiUlCw0v z36j*4k#j1Z2X7otn${{)iAS443_xyTvqPEtxAv)B!Y~v=Qw8FxswNo;Y852m1?)?F zu)Hf6RcPJJwJnnY5P|by3L%8K=FZztS+lFIuFk#y!Pm>6C%)eN{`=oHB*#LyngyZE zqi;fpErrRXB9>XlTh=Oyp`QvifSS#Ul`3i$2#R^f1!77V>^Al|6@r3oR($!Y0n+R-iy}DLZW$ zgG+l0H(@e3mz^L124`YESYdRoMe@6?o7Gm!Zm~l)V1-U{s)FpbilTR}jD$smZT>Li9D!LT|XX`Tea^W9PsW=114zfB5msy9J^FdEAxk9r=KP z0hC-uDS)CS@5~2MUG;~p0dMBX>ZFy;Mek!6_cZ`oQ6VHCH_~!hcLMZs`;s5-D-xKN zoX<*`Gi8c`H4a&pViBiYsSTt*8$tvauq*I)rCCSyd`o z+Gs=`#~7t#LLZ=phWF;7_&(l>b5LBEhd@979vSaD7^nyU?94#EWc$9sUjuw;Foqo3 zmaAY9a13sNb*^aaJcAmM71KbF9TF?5e)7sXP}et23SwJCgUK>lFcD*PCQ1~v@mbNk zIV+ULIUA#Eb{J?6-~wc9-YFM1-T7hHN9cWM+pS|m72y!$luZwa6p3k7FNV=9Z$|ZO zURfcAsKU9~nfIr_tR#9@hW>icD{hLo(lWAk#b! z4hl*(l&b5lOwdFP3PEyah-M0IIz8jPtlr8`UuEY29h;HIoh%=%4|z8>Tj-AZo8b(E zJkEC7Hc}8Mn5rUcQDD!+fP_|I3NBzp#wawQ*@e^sqz#tN)|P8 zXp>HX)ubPiE{-;b59eD5J8t(`m2}LZszcx&9~^&oi`s&#+pPl$ASPOqHciLFl(Fqy zowGFgZg3tBgAjrz9_Fw-2&Be0S=sTSJ?(cd3;5f`hpQJGmUi>uRZhKg%%%W+I^RVY zt%rNL$id{GYlnU;8NdL^NRgopwKnUOOT)pP;9*w@MUA+H>_MlkS)|6QWe?`tygTk` ze>Vdei!ayKQw8Tu)1gL64AN*W)eu850wb>~idJUyZ2%9{4(2!kD!PFsOo*3`UryWK19k^Hg+(7QsnIn;ZY= z60vfyqwI&NREiFabVhHWR3te>TpjHWU5aiPX2dz`l3fpz;bw8PynYFf2Tz2Kb*uo+ z0n}LoH?_LO3Es{#Tym18<7qaL*gKUM*+9G)IVNI`{prcFY*2WNIh-$dc6pTFuDN@7%I)Ey%yH!y~fCG$+7+DL&pv%(k zhuy^eDi3BlAH>zUTh@Y77I#yZ#<}CbmI@v5Jb9FeL~7s~0*S!`%@Afv6F$k9K1ry3;Bg90{ozA`MvpOi)0lu|Tq*60LHR z9>}||>W<^Oo^0|#YH@~O&g!geWsJVuDBu_0Jh|@sbkUXC_^pKs%>wE?pIzVH`Y=Hu z5HPDKKz>1KllGzWjShl!9H8B=T8>T*3933Da(8i9mh5=MoDx>^cjFok+089}3ZYGY z^Wh6t9$HhAD(c;3En3GZL{FxM-n5qOJ{R@DmAv;1jtLL#S;o6f&fTNa!_5%Zqnc|X zkDj9y=NAj!UZ)UyiXG2|ZWdg&&|dV6`BsAfWI21gKTab{xq3$%9=nU`F4~ zB1BSCi=X8zpE+6k#?>@~c?Q=tFY5S|-SP9U&*=nmKbjAcUH{Gc`QAiy4J5UgqnwLb z8F^b>Gg;eqn7_E%$6ut7k%)){`sTbUP`hEHE zXRUz#;_vWd5{h*G*hNZluPgfi;}lo3R}Vs=Q`s&bqmB@UBOg2x%KH6 zfT<6!jzayU7w>>b5|*`=7TmNJ*pGd+kNPF_bL$qvrWL7eJ?akX?3omQl9|tw`Z`gk zRdLdjx2kFy8@8}tFG8@XDJO^1t?=lAciAuVNqZRUo;$cJP=YH|ZwwmZVh*dhd9iEu zb91(^v4)ylK4fE{S(6$g`~9u&@H2E08m@aGoy|o?4n=?yV-FWERk&D`ipS^e(*)kg zx98i!>&&l}gRAyL`Ee9p5bCi|da2JVPMWXl@}o0mL2v z;=EAjpjJEq^+XIat=D(8nfG36!4MxlyP`!4Dq^5C9hOreC<l{yijgFG)yMS{+ zDwdzy@A~J3*u6Ny42hk=e3-2wX!aJ??hp>>K*0BPlz@Evpd8AwT}HZPLr^8xj;{`A zDEmi8-`kv};A2MX7MI}Iu@#<{XZb*JHMyX`-SJ$5X>09ah;(EZ7`12!9_s|ILj^>z zI$_U@wVDMl(dQgiGlmL2%}2*Rr4oQ#qn4xqJBNrB(Sw-*n3xfGn~Mbx?OI!1bmSQ!em=iaWC_*MC;h&$` zb=k^OS{B^~YoBLOoO{MY-+o zOl#~G@peD^R6`U)0%ULFVOY_Agyn;%h;?2rhuyS(bQ$!H&teX@bmmI4ezp%4X=rH7 zZOT2b!eQ>*79Ta^&PA3NbFeaa&j@Bvrz%dVwV~JSTwVR<_feg40P_oP84!Ve16-S0 zH9?367b9z~XbNf$MUr^7$$dJ{%`|#IGEu;S8OZr)e)|CqPqS9B)lgYZXY39_ZFO-cQ;%3hpy4;ye^l0A%C|C?bkR5IW(L{BpmD#L)sKN+G!D!9uUE6@Xhe?&CBDSL-YD*c{glL0msvU5~8Uh-8Y+vMsUvLWPWAAcRG&yeZ^g5)c9H zKVcK^%NaRFkH}~SQbkcpRZ~SQF9*1rkACa(LsF7)RuBnP=QbL1`{>cuA&HnVEwCmR zq1jxBs~mF@PxIwhuW~ilSJp%vu>8m~iN<6f(!9s;VJj2`7)|<;fjomsDaZu(MgywmTm@CF zJ}7u#s?`uoT`9tdl(Kry2w8j+$$2$ZQ>{!yOs0&WwN`Zj#>AbC2%>3jwyA&_SV8CI z5EdEDw=E|TFeC(11ylo1ShMHIYQk~a7eWW6xJ(7pdf`ebvc@of0rI9`47aD8h*W*1P07)4ycToriDmWTZzXocVvJ(A?mvgt3< ze!AC$vZ}xv)zdExKePSx%NmEs)b67L2^crb81z*5(P3uf0AAtKM!Z9I9K#es&jv;Cqq502i)$O_0{}!1Jayl%Z*4A4>Mmj?h`rU zJ9fe6LIbpcO3DbOf&re5L#+FFmapRJ_KQf#3lU0lS_dCPErt$}s(tu$o~-7YO2q)8 z`lS;YJE^Ajz(KdHrAeCAv5A(1!Fkv2hg68UAs?NZ_j#^W(PwmsTC1s=A-kH2c5Qma zlQk~wU&e~wu@MDQZZLIKNT)etRd5@3 zZ0w7v!JjR@b^4>5Y4!0(w!YTxnqH0J2>tor{o`+avVZXMm37N31laG%7wW@axPgnC z2GpbMIY0+9AXHaEXA?Ak<@1sMQ{(5&PySi>Mc>aqr!)Sy@Asu1`7d1e)2{!E6iovY z0cIou5x|a}V+7DzOY_!pckKo`D|gh6RkU#<6tv`HEyf-do#oBx4)*@##c+Q-CB+;WdYQ4|$}2x5 zhTJb&Q;H^gb+=tLL!tv6CB(^Es*a+ zs!bm}L!QLN%WY>64=Jn@wKI*0$%w6-$aY@z?Q-$OrsK^XQ^@`(P0O#myokq#_jh>8 zuU?d{`DXmC)0byi3u;B@_K&`B5BFhp7naTL+Lq0&j|U6M0v2dIB1pFOc=c*}@A!vb zI8|D#aL7ctZL&IDG?c;V&(F1fgTJ0&Fhh?-ue*j795NV~_DAch>MBOYmbh{nZRxg4 zMKaae0HGF{4G7H;J&{?dV!m;uIQQVt;|w{U?B+-AGCjGwWv^ZTNqc%+XNyPs*s)^N zT>YZSlXgALJ|a)(nXsf*ikYfzj@pVa41w#N7u!1`L@*^)tD>OhvTMkGaG24XT1$b( zowlmxUDuH6euCga?)6+yWl@JIK zL$`9f6ggVv)|FuiB2~*=999zPa+Xyga_AsebImZuZ^W0=lR^%Rs4766VR0S>#~?#F z4&YnInoKu9rF66KbpE@G?>&3;-m~`c509U8FJ7dj9aN#OMlBkykHPVMAdRAcAkA&#E5zkQc6!w+9x;7FiVK>-m7i5OHFv=Sny zni2abgp5azv|vNjcjflrms_cZAevpC7nWO1aQuS7K|oUgY`e0`_-yPiFdGPV@JN*b(8{cz^r=jt?JIvmB0)zGK zMQPglBX_+zJCeHj`VUfRDzss+D!`7aXwLQ~Y2vR6e%>YhPg_#|wEKvm^BxVrOpyRY zfh-*siu-*EEcfo%vNj^`<5Hy>kuwBBlTsWpr~zgWWecoLL;#a*hD9N+@MyTKlAbCz zS?=r+-`v*qKcuZ zhK?w7?wNb{X6C$`8=P`cy<+w;>|Hp%tj+d%zwSQ!A+J9!&E?Ral&PMadvawPU2s;b z;l@RfH(9SvWMCu<#DY+M?18q8TC@p)FTs*M?g2bl08FJ0MpE;K0>^|cC^m?9X=ovpsR|no!p#El>*d5JKa^rJ(8IcGaIoB zdOQ5aH~!h>!?5YlnTdhN7`(dU&0GGc{lN=^{_gqd*$6j_ce?#`I4MOW(Ajda+eq-H z**nqh?D+F`++@(jr+OSJaUREv)&vVm&=)GFa z6hZ++qR=;Pn)~IxO^8)hs}j!xF%ux0erZ6iELuBXA@YH6I6g^2*Mxy)h z9y2u%21N!V762kfG$ll2zm&<5b3Q*h9-i$B0hk%G!@^DgX2-C1K+sI{99(oXWpN@6 z0isnQtmKL1uFtoz*}r}E$`rr^ZJ{OM!v_y;zWDTX%BS!#LHmvEAG`M+Z#T|yzALpq zesDazx^Pd#Q$9MaUdc|tZBDkwNCsTct@y(X<#fluCgadNd^1tQRr1?4`! z1` zN^d^9nHMsld@eE%%+Nyd%f-PCsfbVrZrr0wY7j z)6}d`$JCM{sK}NrL)Q;uQWv!r0~Jv-MioPZT2)-3+VqQ>1i<3?Nsp^(fq`)yuO9A? zhR-(d@9&P5)*hEFIGsh|WQ~3x&6*QJZ@GuwG0dSq#a-R~# zVn&Y9fsu^hx|Ah2A8FVkn>9%#(ITL~w~#Aip(r)GHcN%V7Rtxx*!5!!RPt=(5LC=i z5fRC8BW}@@!|d(8BP|LDS`~}OTAKw7d+SzIqGoh~45_KtTv!ketI9lM%SK}0Y1H5t z1U;$aEZ$Yu$aOz%mXF`rhOE@ZIft)ZOW|&u=pUDVl8#Ppu&obZSoob9yN6$Sku%oA zd~w&DEy^?TNd=) zEXesGF6Y{+8<(2;e)i4X{88uD*Ppza|IufEyj%Qt^8e~T8!z6HN9TV~`usQhd3Rb~ z(J;qu5p&MD)ZVSi`(^i*@b<7WT!8vwS zpnrcJ4}D6CjDRLWSm!>Q2Z}x!l8P9U37D#PLDhRYm;rhhz?YmxABu?(sEokCKwtsO zoVclEPK5%Bf4JIR<>tgRAZe>nO8LZ+Rq^1OcfP$}6`i`{X7#uJr2pssAO8Mrda^4o zq@LWZ#!s%-%TfS{^Q0=Omb|lLkBj=&<7Yp5j_2(#5AAxoJk;U0{T~h|qairv0E$3$ zzc-OFzv@5$1Vr?V0A|VnYNY}ix4zokPt(`0!i~Sq$p}>q+2z3##bTyKBN$^*6ueK= zCKK;G`J;=Ahh+UHA08cD-{ugfl8Pc=b#(!OpiceJ9SZQIBK;z{o^$nyYAG&oEp}u) zAI%ecP6eRa7;8Q6zR2K!2u)NG&0rqeysiO348TMWU;t9{y`egiR1PH2>^-P0PS-DC z)lKSE;~5Wn%&1xNOz|Ytoay0LuW|(r1WgupfRqPr_u$nNqDs|rFS*C$0Zf?8j0i*X z-gs9eXL4GVSx}it2$`z(i+Qta3I$YUKhpXE+$x>kS|_1UJ)VTFu=Sv=Hs@dev$8&{ zwjq7*8ySz?Z~nM_{PD@|3_hOMckT!CliM;tAVG&BN{p*T^rzd~8~`?RX7o#H-+A)l z`EAdK*aZSb^lyUB|MTNNmIC_I`o}*N2=_6h_&R*m%rqM*ug=PTNVG4v7qQL z%UKKcye5;mIIHMU%qi0SO`4@`Z`+i2$M0O#x_;?Ty0KcFN>OG4k$njW)l~1wK|Cb@ zT%GJKnyOSdnraaRY|l31&SwlbA983)Q(BtRqqlF=h|p>Rbf5}p`Q-UrBaaG1noCAR zFeBo7;;IOEsN6ij>1HlNLEky)`|GKDXm@$FisP>4jIH!BmMKL61}66AYDwli4#CaX zX<=qEWHU7b!~qHzCAe?8n?Bv_%y~dU_qokVPR&90H6ej2!_mM7<#FkKmFDR-#OXT-98ZmAs~Wk)H=dp4K8TqkN|~3 zY#5M>5>WI0)sT~7U4}dpRa{MTa;wFRBCg!FV5X*`n8*XFNc-rmtAn|025NQAXg~GX-b+tu!6ZJ}S6^ zDu9S6rltS@S&+GuXau08>~CYP5?$bgCWvT+ zwLz=gIdDERd6(ULEgpHm^UHZu0Q#$Tzvhbk8s<%n?HH=Tbs|?$6G#LOtM&} zh*%WqF;2se?=0T5ea>n^e)V{9IkUXðd36n2EjZ-UN$)p6e&HA65pPz`p!x#VGw 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%0D!$GQYU4*;Z`bAoerYjA`A>BV4s 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 IM6N<$g7Ww23IG5A literal 0 HcmV?d00001 diff --git a/tests/data/sample1/original.jpg b/tests/data/sample1/original.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41a0c97bcee644e2ad1ca46101bbf8d14e30cb1c GIT binary patch literal 83398 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 NDArray[np.float64]: + low, high = np.min(x), np.max(x) + + return (x - low) * (up - down) / (high - low) + down + + +def _noise_array( + size: int, params: list[tuple[int | None, float]] +) -> NDArray[np.float64]: + result = np.zeros(shape=(size, size), dtype=np.float64) + + for seed, octaves in params: + noise = PerlinNoise(octaves=octaves, seed=seed) + + arr = np.array( + [[noise([i / size, j / size]) for j in range(size)] for i in range(size)], + dtype=np.float64, + ) + arr = _stretch(arr, -1, 1) + result += arr + + result[result < 0] = 1 + result[(result >= 0) & (result < 0.5)] = 2 + result[(result >= 0.5) & (result < 0.85)] = 3 + result[(result >= 0.85) & (result < 1)] = 4 + + return result + + +def artificial_image(c0: RGBArray, c1: RGBArray, conv: ColorConversion) -> RGBArray: + noise = _noise_array(size=512, params=[(None, 10), (None, 4)]) + + c0_pure = convert_color(c0, conv)[0] + c1_pure = convert_color(c1, conv)[1] + + c0_noise = np.where((noise == 3) | (noise == 4), c0_pure, 0) + c1_noise = np.where((noise >= 2) & (noise < 4), c1_pure, 0) + + img = np.stack([c0_noise, c1_noise, ZEROS], axis=-1) + + return np.asarray(convert_color(img, conv.inverse), dtype=np.uint8) + + +def main() -> None: + h_e = artificial_image(H_RGB, E_RGB, ColorConversion.RGB2HER) + Image.fromarray(h_e).save("tests/data/generated/h_e.jpg") + + h_dab = artificial_image(H_RGB, DAB_RGB, ColorConversion.RGB2HDR) + Image.fromarray(h_dab).save("tests/data/generated/h_dab.jpg") + + +if __name__ == "__main__": + main() diff --git a/tests/test_color_conversion.py b/tests/test_color_conversion.py new file mode 100644 index 0000000..4e842fc --- /dev/null +++ b/tests/test_color_conversion.py @@ -0,0 +1,31 @@ +import numpy as np +import pytest + +from rationai.staining import ColorConversion +from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.typing import StainTuple +from rationai.staining.utils import residual + + +@pytest.mark.parametrize( + "conversion", + ColorConversion, + ids=(conversion.name for conversion in ColorConversion), +) +def test_inverse_conversion(conversion: ColorConversion) -> None: + original = conversion.matrix + inverse = conversion.inverse.matrix + + assert np.all(np.isclose(original, np.linalg.inv(inverse))) + + +STAINS = [ + # Expected values are taken from QuPath + (QUPATH_H, QUPATH_E, (0.316, -0.598, 0.737)), + (QUPATH_H, QUPATH_DAB, (0.633, -0.713, 0.302)), +] + + +@pytest.mark.parametrize("s0,s1,expected", STAINS, ids=["H&E", "H&DAB"]) +def test_residual(s0: StainTuple, s1: StainTuple, expected: StainTuple) -> None: + assert np.all(np.isclose(residual(s0, s1), expected, atol=0.001)) diff --git a/tests/test_stain_estimator.py b/tests/test_stain_estimator.py new file mode 100644 index 0000000..8104b59 --- /dev/null +++ b/tests/test_stain_estimator.py @@ -0,0 +1,105 @@ +from pathlib import Path +from typing import Any + +import numpy as np +import pytest +from numpy.typing import NDArray +from PIL import Image +from skimage.color import deltaE_ciede2000 +from skimage.data import immunohistochemistry +from skimage.filters import gaussian + +from rationai.staining import ColorConversion, convert_color, estimate_stain_vectors +from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.typing import StainArray, Tile + + +ZEROS = np.zeros(shape=(512, 512), dtype=np.float64) + + +H_RGB = np.array([88, 76, 180], dtype=np.uint8) # from QuPath +E_RGB = np.array([199, 50, 112], dtype=np.uint8) # from QuPath +DAB_RGB = np.array([186, 110, 56], dtype=np.uint8) # from QuPath + + +NANS = np.full(shape=(3), fill_value=np.nan) + +GENERATED_DIR = Path("tests/data/generated") + + +def _blur(img: NDArray[np.uint8], sigma: float) -> NDArray[np.uint8]: + result = np.empty_like(img) + channels = [img[..., 0], img[..., 1], img[..., 2]] + + for i, c in enumerate(channels): + result[..., i] = (255 * gaussian(c, sigma=sigma)).astype(np.uint8) + + return result + + +# Input, first expected stain, second expected stain +DATA = [ + ( + immunohistochemistry(), + QUPATH_H, + QUPATH_DAB, + ), + ( + np.asarray(Image.open(GENERATED_DIR / "h_e.jpg")), + QUPATH_H, + QUPATH_E, + ), + ( + np.asarray(Image.open(GENERATED_DIR / "h_dab.jpg")), + QUPATH_H, + QUPATH_DAB, + ), + ( + _blur(np.asarray(Image.open(GENERATED_DIR / "h_e.jpg")), sigma=5), + QUPATH_H, + QUPATH_E, + ), + ( + _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab.jpg")), sigma=5), + QUPATH_H, + QUPATH_DAB, + ), + ( + convert_color(np.stack([ZEROS] * 3, axis=-1), ColorConversion.HER2RGB), + NANS, + NANS, + ), +] + +IDS = [ + "Default skimage image H&DAB", + "Artificial H&E", + "Artificial H&DAB", + "Blurred Artificial H&E", + "Blurred Artificial H&DAB", + "Empty Image", +] + + +@pytest.mark.parametrize("img,expected1,expected2", DATA, ids=IDS) +class TestStainEstimator: + @staticmethod + def _both_nan(x: NDArray[Any], y: NDArray[Any]) -> bool: + return bool(np.isnan(x).all()) and bool(np.isnan(y).all()) + + def test_estimation_vector_similarity( + self, img: Tile, expected1: StainArray, expected2: StainArray + ) -> None: + stain1, stain2 = estimate_stain_vectors(img) + + assert np.dot(stain1, expected1) > 0.97 or self._both_nan(stain1, expected1) + assert np.dot(stain2, expected2) > 0.97 or self._both_nan(stain2, expected2) + + def test_estimation_color_difference( + self, img: Tile, expected1: StainArray, expected2: StainArray + ) -> None: + stain1, stain2 = estimate_stain_vectors(img) + delta = deltaE_ciede2000 + + assert delta(stain1, expected1) < 1 or self._both_nan(stain1, expected1) + assert delta(stain2, expected2) < 1 or self._both_nan(stain2, expected2) diff --git a/tests/test_stain_reconstruction.py b/tests/test_stain_reconstruction.py new file mode 100644 index 0000000..4a5f53b --- /dev/null +++ b/tests/test_stain_reconstruction.py @@ -0,0 +1,40 @@ +import numpy as np +import pytest +from skimage.data import immunohistochemistry +from skimage.metrics import structural_similarity + +from rationai.staining import ColorConversion, convert_color +from rationai.staining.typing import RGBArray + + +IMAGES_AND_CONVS = [ + ( + immunohistochemistry(), + ColorConversion.RGB2HDR, + ), + ( + "sample1_original", + ColorConversion.RGB2HER, + ), +] + +TEST_IDS = ["skimage-default; H&DAB", "Sample1; H&E"] + + +@pytest.mark.parametrize("original,conv", IMAGES_AND_CONVS, ids=TEST_IDS) +def test_structural_similarity( + original: RGBArray | str, conv: ColorConversion, request: pytest.FixtureRequest +) -> None: + """For reconstruction, only structural similarity is tested. + + Due to implementation details, the reconsturction is not idempotent, + and some bigger color shifts can occur in some conversions. + Therefore, the color similarity cannot be reliably tested. + """ + if isinstance(original, str): + original = request.getfixturevalue(original) + + c0, c1, c2 = convert_color(original, conv) # type: ignore[arg-type] + reconstructed = convert_color(np.stack([c0, c1, c2], axis=-1), conv.inverse) + + assert structural_similarity(original, reconstructed, channel_axis=-1) > 0.95 diff --git a/tests/test_stain_separation.py b/tests/test_stain_separation.py new file mode 100644 index 0000000..e02357e --- /dev/null +++ b/tests/test_stain_separation.py @@ -0,0 +1,52 @@ +import numpy as np +import pytest +from numpy.typing import NDArray +from skimage.metrics import structural_similarity + +from rationai.staining import ColorConversion, convert_color +from rationai.staining.typing import RGBArray, StainArray + + +RGB_CONVERSIONS = [ + ColorConversion.RGB2HER, + ColorConversion.RGB2HDR, +] +RGB_NAMES = [c.name for c in RGB_CONVERSIONS] + + +@pytest.mark.parametrize("conversion", RGB_CONVERSIONS, ids=RGB_NAMES) +def test_black_image(black: RGBArray, conversion: ColorConversion) -> None: + c0, c1, c2 = convert_color(black, conversion) + + rgb2stain = np.stack(conversion.value[0]) + expected_values = np.sum(rgb2stain, axis=0) + + assert np.all(c0 == expected_values[0]) + assert np.all(c1 == expected_values[1]) + assert np.all(c2 == expected_values[2]) + + +@pytest.mark.parametrize("conversion", RGB_CONVERSIONS, ids=RGB_NAMES) +def test_white_image(white: RGBArray, conversion: ColorConversion) -> None: + c0, c1, c2 = convert_color(white, conversion) + + assert np.all(c0 == 0) + assert np.all(c1 == 0) + assert np.all(c2 == 0) + + +def test_real_sample1_image( + sample1_original: RGBArray, + sample1_hematoxylin: StainArray, + sample1_eosin: StainArray, + sample1_residual: StainArray, +) -> None: + h, e, r = convert_color(sample1_original, ColorConversion.RGB2HER) + + assert structural_similarity(_prepare(h), sample1_hematoxylin) > 0.95 + assert structural_similarity(_prepare(e), sample1_eosin) > 0.95 + assert structural_similarity(_prepare(r), sample1_residual) > 0.95 + + +def _prepare(c: NDArray[np.float64]) -> NDArray[np.uint8]: + return (255 * (c / np.max(c))).astype(np.uint8) From 4b5b907953251107cb5cea3ff66a8aedd244a1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Tue, 27 Aug 2024 18:01:12 +0200 Subject: [PATCH 22/79] feat: convert_color with sequence --- .pre-commit-config.yaml | 2 +- rationai/staining/convert_color.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 83fa055..ba49995 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.6.2 hooks: # Run the linter. - id: ruff diff --git a/rationai/staining/convert_color.py b/rationai/staining/convert_color.py index 5ae45da..acb6da2 100644 --- a/rationai/staining/convert_color.py +++ b/rationai/staining/convert_color.py @@ -1,3 +1,4 @@ +from collections.abc import Sequence from enum import Enum, auto, unique from typing import overload @@ -96,11 +97,14 @@ def convert_color( @overload -def convert_color(tile: StainArray, conversion: ColorConversion) -> RGBArray: ... +def convert_color( + tile: StainArray | Sequence[StainArray], conversion: ColorConversion +) -> RGBArray: ... def convert_color( - tile: RGBArray | StainArray | Image, conversion: ColorConversion + tile: RGBArray | Image | StainArray | Sequence[StainArray], + conversion: ColorConversion, ) -> RGBArray | tuple[StainArray, ...]: """Converts a tile into the specified color space. @@ -131,5 +135,7 @@ def convert_color( return tuple(np.moveaxis(separate_stains(tile, conversion.matrix), -1, 0)) case ConversionType.STAIN2RGB: + if isinstance(tile, Sequence): + tile = np.stack(tile, axis=-1) tile = np.asarray(tile, dtype=np.float64) return (255 * combine_stains(tile, conversion.matrix)).astype(np.uint8) From 3ff13a4ddd2b14dbf079514644e751bc02aea040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Tue, 27 Aug 2024 18:12:19 +0200 Subject: [PATCH 23/79] docs: reorganize --- docs/{reference => api}/color-conversion.md | 0 docs/{reference => api}/constants.md | 0 .../estimate-stain-vectors.md | 0 docs/{reference => api}/typing.md | 0 docs/{installation.md => getting-started.md} | 12 +- docs/reference/index.md | 4 - mkdocs.yml | 29 +- pdm.lock | 715 ++++++++++++++++-- pyproject.toml | 8 +- 9 files changed, 660 insertions(+), 108 deletions(-) rename docs/{reference => api}/color-conversion.md (100%) rename docs/{reference => api}/constants.md (100%) rename docs/{reference => api}/estimate-stain-vectors.md (100%) rename docs/{reference => api}/typing.md (100%) rename docs/{installation.md => getting-started.md} (88%) delete mode 100644 docs/reference/index.md diff --git a/docs/reference/color-conversion.md b/docs/api/color-conversion.md similarity index 100% rename from docs/reference/color-conversion.md rename to docs/api/color-conversion.md diff --git a/docs/reference/constants.md b/docs/api/constants.md similarity index 100% rename from docs/reference/constants.md rename to docs/api/constants.md diff --git a/docs/reference/estimate-stain-vectors.md b/docs/api/estimate-stain-vectors.md similarity index 100% rename from docs/reference/estimate-stain-vectors.md rename to docs/api/estimate-stain-vectors.md diff --git a/docs/reference/typing.md b/docs/api/typing.md similarity index 100% rename from docs/reference/typing.md rename to docs/api/typing.md diff --git a/docs/installation.md b/docs/getting-started.md similarity index 88% rename from docs/installation.md rename to docs/getting-started.md index 15a16f7..325f7c4 100644 --- a/docs/installation.md +++ b/docs/getting-started.md @@ -1,13 +1,15 @@ -# Installation +# Getting Started -=== "pip" +## Installation + +=== "pdm" ```bash - pip install git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git + pdm add git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git ``` -=== "pdm" +=== "pip" ```bash - pdm add git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git + pip install git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git ``` diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index 47a1bf1..0000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# Reference - -Here's the reference or code API, the classes, functions, parameters, attributes, and -all the `rationai-staining` parts you can use in your applications. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 7df5f07..59419fd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,15 +1,13 @@ site_name: Staining nav: - - Home: index.md - - Getting Started: - - Installation: installation.md - - Reference: - - reference/index.md - - reference/color-conversion.md - - reference/estimate-stain-vectors.md - - reference/constants.md - - reference/typing.md + - Introduction: index.md + - Getting Started: getting-started.md + - API Reference: + - api/color-conversion.md + - estimate_stain_vectors: api/estimate-stain-vectors.md + - api/constants.md + - api/typing.md theme: name: material @@ -19,11 +17,11 @@ theme: - content.action.view - content.code.annotate - content.code.copy + - content.code.select - content.tooltips - navigation.indexes - navigation.sections - navigation.top - - navigation.tabs - navigation.footer - navigation.tracking - search.highlight @@ -52,7 +50,11 @@ theme: plugins: - search - - mkdocstrings + - mkdocstrings: + handlers: + python: + options: + show_if_no_docstring: true markdown_extensions: - pymdownx.superfences: @@ -66,3 +68,8 @@ markdown_extensions: slugify: !!python/object/apply:pymdownx.slugs.slugify kwds: case: lower + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight + - pymdownx.inlinehilite diff --git a/pdm.lock b/pdm.lock index e698408..6420616 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,14 +2,39 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "dev", "test"] +groups = ["default", "dev", "docs", "test"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:a7dd9cc2a5c546a0337b5d1b9ab80d4197f0e484eeb9bbd3c3dcad0709af7758" +content_hash = "sha256:3f01d03ad0d47f602c987ef86d96b65b42cd6b8199430d0f41138b17f05995fc" [[metadata.targets]] requires_python = ">=3.11" +[[package]] +name = "babel" +version = "2.16.0" +requires_python = ">=3.8" +summary = "Internationalization utilities" +groups = ["docs"] +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[[package]] +name = "certifi" +version = "2024.7.4" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." +groups = ["docs"] +files = [ + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, +] + [[package]] name = "cfgv" version = "3.4.0" @@ -21,13 +46,68 @@ files = [ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] +[[package]] +name = "charset-normalizer" +version = "3.3.2" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["docs"] +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["docs"] +dependencies = [ + "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + [[package]] name = "colorama" version = "0.4.6" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Cross-platform colored terminal text." -groups = ["test"] -marker = "sys_platform == \"win32\"" +groups = ["docs", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -159,6 +239,34 @@ files = [ {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +summary = "Copy your docs directly to the gh-pages branch." +groups = ["docs"] +dependencies = [ + "python-dateutil>=2.8.1", +] +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[[package]] +name = "griffe" +version = "1.2.0" +requires_python = ">=3.8" +summary = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +groups = ["docs"] +dependencies = [ + "astunparse>=1.6; python_version < \"3.9\"", + "colorama>=0.4", +] +files = [ + {file = "griffe-1.2.0-py3-none-any.whl", hash = "sha256:a8b2fcb1ecdc5a412e646b0b4375eb20a5d2eac3a11dd8c10c56967a4097663c"}, + {file = "griffe-1.2.0.tar.gz", hash = "sha256:1c9f6ef7455930f3f9b0c4145a961c90385d1e2cbc496f7796fbff560ec60d31"}, +] + [[package]] name = "identify" version = "2.6.0" @@ -170,19 +278,30 @@ files = [ {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, ] +[[package]] +name = "idna" +version = "3.8" +requires_python = ">=3.6" +summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["docs"] +files = [ + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, +] + [[package]] name = "imageio" -version = "2.35.0" +version = "2.35.1" requires_python = ">=3.8" summary = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." groups = ["default"] dependencies = [ - "numpy<2.0.0", + "numpy", "pillow>=8.3.2", ] files = [ - {file = "imageio-2.35.0-py3-none-any.whl", hash = "sha256:ebfb39c0ad7acf93750d7ee151664238aaa9208f202288ea6f3ca7cb0ed719c3"}, - {file = "imageio-2.35.0.tar.gz", hash = "sha256:e88f759803d2968e19a55fa8372e9fbe12967a8598fe042d8719ca46d03f4256"}, + {file = "imageio-2.35.1-py3-none-any.whl", hash = "sha256:6eb2e5244e7a16b85c10b5c2fe0f7bf961b40fcb9f1a9fd1bd1d2c2f8fb3cd65"}, + {file = "imageio-2.35.1.tar.gz", hash = "sha256:4952dfeef3c3947957f6d5dedb1f4ca31c6e509a476891062396834048aeed2a"}, ] [[package]] @@ -196,6 +315,20 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["docs"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + [[package]] name = "lazy-loader" version = "0.4" @@ -211,9 +344,213 @@ files = [ {file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"}, ] +[[package]] +name = "markdown" +version = "3.7" +requires_python = ">=3.8" +summary = "Python implementation of John Gruber's Markdown." +groups = ["docs"] +dependencies = [ + "importlib-metadata>=4.4; python_version < \"3.10\"", +] +files = [ + {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, + {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +requires_python = ">=3.7" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["docs"] +files = [ + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +requires_python = ">=3.6" +summary = "A deep merge function for 🐍." +groups = ["docs"] +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mkdocs" +version = "1.6.0" +requires_python = ">=3.8" +summary = "Project documentation with Markdown." +groups = ["docs"] +dependencies = [ + "click>=7.0", + "colorama>=0.4; platform_system == \"Windows\"", + "ghp-import>=1.0", + "importlib-metadata>=4.4; python_version < \"3.10\"", + "jinja2>=2.11.1", + "markdown>=3.3.6", + "markupsafe>=2.0.1", + "mergedeep>=1.3.4", + "mkdocs-get-deps>=0.2.0", + "packaging>=20.5", + "pathspec>=0.11.1", + "pyyaml-env-tag>=0.1", + "pyyaml>=5.1", + "watchdog>=2.0", +] +files = [ + {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, + {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.1.0" +requires_python = ">=3.8" +summary = "Automatically link across pages in MkDocs." +groups = ["docs"] +dependencies = [ + "Markdown>=3.3", + "markupsafe>=2.0.1", + "mkdocs>=1.1", +] +files = [ + {file = "mkdocs_autorefs-1.1.0-py3-none-any.whl", hash = "sha256:492ac42f50214e81565e968f8cb0df9aba9d981542b9e7121b8f8ae9407fe6eb"}, + {file = "mkdocs_autorefs-1.1.0.tar.gz", hash = "sha256:f2fd43b11f66284bd014f9b542a05c8ecbfaad4e0d7b30b68584788217b6c656"}, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +requires_python = ">=3.8" +summary = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +groups = ["docs"] +dependencies = [ + "importlib-metadata>=4.3; python_version < \"3.10\"", + "mergedeep>=1.3.4", + "platformdirs>=2.2.0", + "pyyaml>=5.1", +] +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.33" +requires_python = ">=3.8" +summary = "Documentation that simply works" +groups = ["docs"] +dependencies = [ + "babel~=2.10", + "colorama~=0.4", + "jinja2~=3.0", + "markdown~=3.2", + "mkdocs-material-extensions~=1.3", + "mkdocs~=1.6", + "paginate~=0.5", + "pygments~=2.16", + "pymdown-extensions~=10.2", + "regex>=2022.4", + "requests~=2.26", +] +files = [ + {file = "mkdocs_material-9.5.33-py3-none-any.whl", hash = "sha256:dbc79cf0fdc6e2c366aa987de8b0c9d4e2bb9f156e7466786ba2fd0f9bf7ffca"}, + {file = "mkdocs_material-9.5.33.tar.gz", hash = "sha256:d23a8b5e3243c9b2f29cdfe83051104a8024b767312dc8fde05ebe91ad55d89d"}, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +requires_python = ">=3.8" +summary = "Extension pack for Python Markdown and MkDocs Material." +groups = ["docs"] +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocstrings" +version = "0.25.2" +requires_python = ">=3.8" +summary = "Automatic documentation from sources, for MkDocs." +groups = ["docs"] +dependencies = [ + "Jinja2>=2.11.1", + "Markdown>=3.3", + "MarkupSafe>=1.1", + "click>=7.0", + "importlib-metadata>=4.6; python_version < \"3.10\"", + "mkdocs-autorefs>=0.3.1", + "mkdocs>=1.4", + "platformdirs>=2.2.0", + "pymdown-extensions>=6.3", + "typing-extensions>=4.1; python_version < \"3.10\"", +] +files = [ + {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"}, + {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"}, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.10.8" +requires_python = ">=3.8" +summary = "A Python handler for mkdocstrings." +groups = ["docs"] +dependencies = [ + "griffe>=0.49", + "mkdocstrings>=0.25", +] +files = [ + {file = "mkdocstrings_python-1.10.8-py3-none-any.whl", hash = "sha256:bb12e76c8b071686617f824029cb1dfe0e9afe89f27fb3ad9a27f95f054dcd89"}, + {file = "mkdocstrings_python-1.10.8.tar.gz", hash = "sha256:5856a59cbebbb8deb133224a540de1ff60bded25e54d8beacc375bb133d39016"}, +] + +[[package]] +name = "mkdocstrings" +version = "0.25.2" +extras = ["python"] +requires_python = ">=3.8" +summary = "Automatic documentation from sources, for MkDocs." +groups = ["docs"] +dependencies = [ + "mkdocstrings-python>=0.5.2", + "mkdocstrings==0.25.2", +] +files = [ + {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"}, + {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"}, +] + [[package]] name = "mypy" -version = "1.11.1" +version = "1.11.2" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["dev"] @@ -223,18 +560,18 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, - {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, - {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, - {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, - {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, - {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, - {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, - {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, - {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, - {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, + {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, + {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, + {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, ] [[package]] @@ -272,28 +609,49 @@ files = [ [[package]] name = "numpy" -version = "1.26.4" -requires_python = ">=3.9" +version = "2.1.0" +requires_python = ">=3.10" summary = "Fundamental package for array computing in Python" groups = ["default"] files = [ - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, + {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, + {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, + {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, + {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, + {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, + {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, + {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, + {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, + {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, + {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, + {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, + {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, + {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, + {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, + {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, + {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, + {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, + {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, + {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, ] [[package]] @@ -301,12 +659,33 @@ name = "packaging" version = "24.1" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["default", "test"] +groups = ["default", "docs", "test"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] +[[package]] +name = "paginate" +version = "0.5.7" +summary = "Divides large result sets into pages for easier browsing" +groups = ["docs"] +files = [ + {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, + {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["docs"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + [[package]] name = "perlin-noise" version = "1.13" @@ -365,7 +744,7 @@ name = "platformdirs" version = "4.2.2" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -groups = ["dev"] +groups = ["dev", "docs"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, @@ -400,6 +779,32 @@ files = [ {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] +[[package]] +name = "pygments" +version = "2.18.0" +requires_python = ">=3.8" +summary = "Pygments is a syntax highlighting package written in Python." +groups = ["docs"] +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[[package]] +name = "pymdown-extensions" +version = "10.9" +requires_python = ">=3.8" +summary = "Extension pack for Python Markdown." +groups = ["docs"] +dependencies = [ + "markdown>=3.6", + "pyyaml", +] +files = [ + {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, + {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, +] + [[package]] name = "pytest" version = "8.3.2" @@ -434,12 +839,26 @@ files = [ {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +groups = ["docs"] +dependencies = [ + "six>=1.5", +] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + [[package]] name = "pyyaml" version = "6.0.2" requires_python = ">=3.8" summary = "YAML parser and emitter for Python" -groups = ["dev"] +groups = ["dev", "docs"] files = [ {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, @@ -471,31 +890,102 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +requires_python = ">=3.6" +summary = "A custom YAML tag for referencing environment variables in YAML files. " +groups = ["docs"] +dependencies = [ + "pyyaml", +] +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[[package]] +name = "regex" +version = "2024.7.24" +requires_python = ">=3.8" +summary = "Alternative regular expression module, to replace re." +groups = ["docs"] +files = [ + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, + {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, + {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, + {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, + {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, + {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["docs"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + [[package]] name = "ruff" -version = "0.6.1" +version = "0.6.2" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev"] files = [ - {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, - {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, - {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, - {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, - {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, - {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, - {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, + {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, + {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, + {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, + {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, + {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, + {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, + {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, + {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, + {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, ] [[package]] @@ -530,7 +1020,7 @@ files = [ [[package]] name = "scipy" -version = "1.14.0" +version = "1.14.1" requires_python = ">=3.10" summary = "Fundamental algorithms for scientific computing in Python" groups = ["default"] @@ -538,28 +1028,47 @@ dependencies = [ "numpy<2.3,>=1.23.5", ] files = [ - {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, - {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, - {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, - {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, - {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, - {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, - {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, - {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, - {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, - {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, - {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, - {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, - {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, - {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, - {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, - {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, - {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"}, + {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"}, + {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"}, + {file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"}, + {file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"}, + {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"}, + {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"}, + {file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"}, + {file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"}, + {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"}, + {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"}, + {file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"}, + {file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"}, + {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"}, +] + +[[package]] +name = "six" +version = "1.16.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" +groups = ["docs"] +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] name = "tifffile" -version = "2024.8.10" +version = "2024.8.24" requires_python = ">=3.9" summary = "Read and write TIFF files" groups = ["default"] @@ -567,8 +1076,8 @@ dependencies = [ "numpy", ] files = [ - {file = "tifffile-2024.8.10-py3-none-any.whl", hash = "sha256:1c224564fa92e7e9f9a0ed65880b2ece97c3f0d10029ffbebfa5e62b3f6b343d"}, - {file = "tifffile-2024.8.10.tar.gz", hash = "sha256:fdc12124f1478a07b1524641dc6b50cf6bde0483011a63fd2a773094090c3dcf"}, + {file = "tifffile-2024.8.24-py3-none-any.whl", hash = "sha256:40faba20cb0af05c0eb500eda63244dd81500360e1518ff4548eb61ce3943099"}, + {file = "tifffile-2024.8.24.tar.gz", hash = "sha256:65a77e50cfcf05e3553b52dd13367caad3f88eae7f533188653ce9b2d88b7464"}, ] [[package]] @@ -582,6 +1091,17 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "urllib3" +version = "2.2.2" +requires_python = ">=3.8" +summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["docs"] +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + [[package]] name = "virtualenv" version = "20.26.3" @@ -598,3 +1118,32 @@ files = [ {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] + +[[package]] +name = "watchdog" +version = "5.0.0" +requires_python = ">=3.9" +summary = "Filesystem events monitoring" +groups = ["docs"] +files = [ + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9"}, + {file = "watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12"}, + {file = "watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4"}, + {file = "watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c"}, + {file = "watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e"}, +] diff --git a/pyproject.toml b/pyproject.toml index 2291c91..aa64ea2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,12 @@ authors = [{ name = "Tomáš Balák" }] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } -dependencies = [ - "numpy>=1.26.4", - "pillow>=10.3.0", - "scikit-image>=0.23.2", -] +dependencies = ["numpy>=1.26.4", "pillow>=10.3.0", "scikit-image>=0.23.2"] [tool.pdm.dev-dependencies] dev = ["mypy", "pre-commit", "ruff"] test = ["pytest", "pytest-cov", "perlin-noise>=1.12"] +docs = ["mkdocs-material>=9.5.32", "mkdocstrings[python]>=0.25.2"] [tool.pdm.scripts] l = { composite = ["lint", "format", "mypy"] } @@ -22,6 +19,7 @@ test = "pytest tests" lint = "ruff check --fix" format = "ruff format" mypy = "mypy ." +docs = "mkdocs serve" post_install = { composite = [ "pre-commit autoupdate", "pre-commit install", From a10335ae2956d01806d4c68319baa8a7d9e4a95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Pek=C3=A1r?= <525077@mail.muni.cz> Date: Tue, 10 Sep 2024 00:18:34 +0200 Subject: [PATCH 24/79] fix: py.typed marker file --- rationai/staining/py.typed | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 rationai/staining/py.typed diff --git a/rationai/staining/py.typed b/rationai/staining/py.typed new file mode 100644 index 0000000..e69de29 From bd1d704d86468a42d2321e9041c746215255c099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Bal=C3=A1k?= <525126@mail.muni.cz> Date: Fri, 28 Feb 2025 08:34:27 +0100 Subject: [PATCH 25/79] feat: light H&DAB protocol, color conversion fixes, modify and reconstruct --- .pre-commit-config.yaml | 6 +- docs/api/modify-and-reconstruct.md | 1 + mkdocs.yml | 1 + rationai/staining/__init__.py | 2 + rationai/staining/constants.py | 13 +++ rationai/staining/convert_color.py | 80 +++++++++++++++--- rationai/staining/modify_and_reconstruct.py | 73 ++++++++++++++++ rationai/staining/scripts/remove_red_stain.py | 38 +++++++++ rationai/staining/typing.py | 11 +++ tests/conftest.py | 11 ++- tests/data/generated/h_dab.jpg | Bin 43338 -> 0 bytes tests/data/generated/h_dab.png | Bin 0 -> 14855 bytes tests/data/generated/h_dab_legacy.png | Bin 0 -> 14366 bytes tests/data/generated/h_e.jpg | Bin 42565 -> 0 bytes tests/data/generated/h_e.png | Bin 0 -> 14366 bytes tests/scripts/generate_artifical_tissue.py | 10 ++- tests/test_color_conversion.py | 5 +- tests/test_modify_and_reconstruct.py | 61 +++++++++++++ tests/test_stain_estimator.py | 32 +++++-- tests/test_stain_reconstruction.py | 6 +- tests/test_stain_separation.py | 1 + 21 files changed, 321 insertions(+), 30 deletions(-) create mode 100644 docs/api/modify-and-reconstruct.md create mode 100644 rationai/staining/modify_and_reconstruct.py create mode 100644 rationai/staining/scripts/remove_red_stain.py delete mode 100644 tests/data/generated/h_dab.jpg create mode 100644 tests/data/generated/h_dab.png create mode 100644 tests/data/generated/h_dab_legacy.png delete mode 100644 tests/data/generated/h_e.jpg create mode 100644 tests/data/generated/h_e.png create mode 100644 tests/test_modify_and_reconstruct.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba49995..9bbe87c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,20 +2,20 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-yaml args: [--unsafe] - repo: https://github.com/compilerla/conventional-pre-commit - rev: v3.4.0 + rev: v3.6.0 hooks: - id: conventional-pre-commit stages: [commit-msg] args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.2 + rev: v0.7.1 hooks: # Run the linter. - id: ruff diff --git a/docs/api/modify-and-reconstruct.md b/docs/api/modify-and-reconstruct.md new file mode 100644 index 0000000..ef9f38d --- /dev/null +++ b/docs/api/modify-and-reconstruct.md @@ -0,0 +1 @@ +::: rationai.staining.modify_and_reconstruct \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 59419fd..d3e70d5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,7 @@ nav: - API Reference: - api/color-conversion.md - estimate_stain_vectors: api/estimate-stain-vectors.md + - modify_and_reconstruct: api/modify-and-reconstruct.md - api/constants.md - api/typing.md diff --git a/rationai/staining/__init__.py b/rationai/staining/__init__.py index e71fe94..12ba09e 100644 --- a/rationai/staining/__init__.py +++ b/rationai/staining/__init__.py @@ -4,6 +4,7 @@ convert_color, ) from rationai.staining.estimate_stain_vectors import estimate_stain_vectors +from rationai.staining.modify_and_reconstruct import modify_and_reconstruct __all__ = [ @@ -11,4 +12,5 @@ "ConversionType", "convert_color", "estimate_stain_vectors", + "modify_and_reconstruct", ] diff --git a/rationai/staining/constants.py b/rationai/staining/constants.py index 6e26e51..46b81eb 100644 --- a/rationai/staining/constants.py +++ b/rationai/staining/constants.py @@ -1,6 +1,19 @@ QUPATH_H = (0.651, 0.701, 0.290) """ QuPath value for default Hematoxylin staining vector. + +Note: + QuPath uses this value by default, even in the H&DAB protocol. + However, this value does not resemble the actual color + of Hematoxylin present in H&DAB-stained slides. + It is therefore advised to use the `LIGHT_H` value when working with + the H&DAB protocol. +""" + +LIGHT_H = (0.849, 0.514, 0.124) +""" +Value for a light blue Hematoxylin staining vector +present in the H&DAB protocol. """ QUPATH_E = (0.216, 0.801, 0.558) diff --git a/rationai/staining/convert_color.py b/rationai/staining/convert_color.py index acb6da2..21ac72b 100644 --- a/rationai/staining/convert_color.py +++ b/rationai/staining/convert_color.py @@ -4,9 +4,9 @@ import numpy as np from PIL.Image import Image -from skimage.color import combine_stains, separate_stains +from skimage.color import combine_stains -from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H from rationai.staining.typing import ( RGBArray, StainArray, @@ -42,17 +42,36 @@ class ColorConversion(Enum): """**Combines** `Hematoxylin`, `Eosin` and `Residual` channels **to RGB**.""" HDR2RGB = ( - (QUPATH_H, QUPATH_DAB, residual(QUPATH_H, QUPATH_DAB)), + (LIGHT_H, QUPATH_DAB, residual(LIGHT_H, QUPATH_DAB)), ConversionType.STAIN2RGB, ) """**Combines** `Hematoxylin`, `DAB` and `Residual` channels **to RGB**.""" - RGB2HER = (inv_mat(HER2RGB[0]), ConversionType.RGB2STAIN) - """**Separates RGB image** into `Hematoxylin`, `Eosin` and `Residual` channels.""" + HDR2RGB_LEGACY = ( + (QUPATH_H, QUPATH_DAB, residual(QUPATH_H, QUPATH_DAB)), + ConversionType.STAIN2RGB, + ) + """**Combines** `Hematoxylin`, `DAB` and `Residual` channels **to RGB**. + + This conversion uses the Hematoxylin vector from QuPath, and it is no longer + recommended and is marked as legacy as it did not + provide expected results for staining detection and separation. + """ RGB2HDR = (inv_mat(HDR2RGB[0]), ConversionType.RGB2STAIN) """**Separates RGB image** into `Hematoxylin`, `DAB` and `Residual` channels.""" + RGB2HER = (inv_mat(HER2RGB[0]), ConversionType.RGB2STAIN) + """**Separates RGB image** into `Hematoxylin`, `Eosin` and `Residual` channels.""" + + RGB2HDR_LEGACY = (inv_mat(HDR2RGB_LEGACY[0]), ConversionType.RGB2STAIN) + """**Separates RGB image** into `Hematoxylin`, `DAB` and `Residual` channels. + + This conversion uses the Hematoxylin vector from QuPath, and it is no longer + recommended and is marked as legacy as it did not + provide expected results for staining detection and separation. + """ + @property def conv_type(self) -> ConversionType: """Returns conversion type associated with the color conversion. @@ -80,31 +99,57 @@ def inverse(self) -> "ColorConversion": Inverse color conversion (i. e., RGB2HER is inverse to HER2RGB). """ match self: + # H&E Protocol case ColorConversion.RGB2HER: return ColorConversion.HER2RGB - case ColorConversion.RGB2HDR: - return ColorConversion.HDR2RGB case ColorConversion.HER2RGB: return ColorConversion.RGB2HER + + # H&DAB Protocol + case ColorConversion.RGB2HDR: + return ColorConversion.HDR2RGB case ColorConversion.HDR2RGB: return ColorConversion.RGB2HDR + # Legacy H&DAB Protocol + case ColorConversion.RGB2HDR_LEGACY: + return ColorConversion.HDR2RGB_LEGACY + case ColorConversion.HDR2RGB_LEGACY: + return ColorConversion.RGB2HDR_LEGACY + + +def _separate_stains( + img: RGBArray | Image, rgb2stain: StainArray, keep_negative_values: bool = False +) -> StainArray: + values = np.maximum(np.asarray(img).astype(np.float64) / 255, 1e-6) + stains = (np.log(values) / np.log(1e-6)) @ rgb2stain + + if not keep_negative_values: + stains = np.maximum(stains, 0) + + return stains + @overload def convert_color( - tile: RGBArray | Image, conversion: ColorConversion + tile: RGBArray | Image, + conversion: ColorConversion, + keep_negative_values: bool = False, ) -> tuple[StainArray, ...]: ... @overload def convert_color( - tile: StainArray | Sequence[StainArray], conversion: ColorConversion + tile: StainArray | Sequence[StainArray], + conversion: ColorConversion, + keep_negative_values: bool = False, ) -> RGBArray: ... def convert_color( tile: RGBArray | Image | StainArray | Sequence[StainArray], conversion: ColorConversion, + keep_negative_values: bool = False, ) -> RGBArray | tuple[StainArray, ...]: """Converts a tile into the specified color space. @@ -120,22 +165,33 @@ def convert_color( tile: Tile that should be converted. Can either be a RGB image or three stain channels stacked along the last axis. Stain channels can be stacked using the following code: - >>> stacked_stains = np.stack([c0, c1, c2], axis=-1) - + ```python + stacked_stains = np.stack([c0, c1, c2], axis=-1) + ``` Here, `c[0-2]` are the individual stain channels. conversion: Desired color conversion. + keep_negative_values: Decides if the negative values produced by color separation + should be kept. + Returns: Depending on the conversion, the result can either be a RGB image, or a tuple of the separated stain channels. """ match conversion.conv_type: case ConversionType.RGB2STAIN: - return tuple(np.moveaxis(separate_stains(tile, conversion.matrix), -1, 0)) + return tuple( + np.moveaxis( + _separate_stains(tile, conversion.matrix, keep_negative_values), # type: ignore[arg-type] + -1, + 0, + ) + ) case ConversionType.STAIN2RGB: if isinstance(tile, Sequence): tile = np.stack(tile, axis=-1) + tile = np.asarray(tile, dtype=np.float64) return (255 * combine_stains(tile, conversion.matrix)).astype(np.uint8) diff --git a/rationai/staining/modify_and_reconstruct.py b/rationai/staining/modify_and_reconstruct.py new file mode 100644 index 0000000..10d3bab --- /dev/null +++ b/rationai/staining/modify_and_reconstruct.py @@ -0,0 +1,73 @@ +import numpy as np +from skimage.color import combine_stains + +from rationai.staining.typing import ModifyFunction, RGBArray, StainTuple +from rationai.staining.utils.inv_mat import inv_mat +from rationai.staining.utils.residual import residual + + +def modify_and_reconstruct( + tile: RGBArray, + modify: ModifyFunction, + stain0: StainTuple, + stain1: StainTuple, + stain2: StainTuple | None = None, +) -> RGBArray: + """Modifies RGB tile in stain space and converts back to RGB. + + Args: + tile: Input RGB representation of the region. + modify: Function that takes three channels in stain space + and returns their modified versions. + stain0: First default color vector. + stain1: Second default color vector. + stain2: Third default color vector. If not provided, + a residual vector is computed from the first two. + + Returns: + Modified region in RGB space. + + Note: + - To ensure as precise reconstruction as possible, + **clipping of negative values is ommited** from stain separation. + + References: + Stain separation is adapted from skimage.color.separate_stains. + + Example: + ```python + import numpy as np + from skimage.data import immunohistochemistry + + from rationai.staining import modify_and_reconstruct + from rationai.staining.constants import QUPATH_DAB, QUPATH_H + + + def modify(c0, c1, c2): + # Remove second channel from the image + c1 = np.zeros_like(c1) + + return c0, c1, c2 + + + original = immunohistochemistry() + modified = modify_and_reconstruct(original, modify, QUPATH_H, QUPATH_DAB) + ``` + """ + if stain2 is None: + stain2 = residual(stain0, stain1) + + mat = (stain0, stain1, stain2) + + stain2rgb = np.stack(mat) + rgb2stain = np.stack(inv_mat(mat)) + + values = np.maximum(tile.astype(np.float64) / 255, 1e-6) + log_adjust = np.log(1e-6) + + stains = (np.log(values) / log_adjust) @ rgb2stain + c0, c1, c2 = tuple(np.moveaxis(stains, -1, 0)) + + modified_stains = np.stack(modify(c0, c1, c2), axis=-1) + + return (255 * combine_stains(modified_stains, stain2rgb)).astype(np.uint8) diff --git a/rationai/staining/scripts/remove_red_stain.py b/rationai/staining/scripts/remove_red_stain.py new file mode 100644 index 0000000..f413265 --- /dev/null +++ b/rationai/staining/scripts/remove_red_stain.py @@ -0,0 +1,38 @@ +from pathlib import Path +from typing import TypeAlias + +import numpy as np +from numpy.typing import NDArray +from PIL import Image + +from rationai.staining.modify_and_reconstruct import modify_and_reconstruct + + +Channel: TypeAlias = NDArray[np.float64] + + +DIRECTORY_PATH = "/mnt/data/Projects/MOU/Bad_scans/stain separation/" +FILES = Path(DIRECTORY_PATH).glob("*.JPG") + +# STAIN DEFINITIONS +HEMATOXYLIN = (0.849, 0.514, 0.124) +DAB = (0.262, 0.631, 0.730) +RED = (0.128, 0.875, 0.466) + + +def modify(c0: Channel, c1: Channel, c2: Channel) -> tuple[Channel, Channel, Channel]: + c2 = np.zeros_like(c2) + + return c0, c1, c2 + + +def main() -> None: + for file in FILES: + img = np.asarray(Image.open(file).convert("RGB")) + modified = modify_and_reconstruct(img, modify, HEMATOXYLIN, DAB, RED) + + Image.fromarray(modified).save(f"{file.stem}.png") + + +if __name__ == "__main__": + main() diff --git a/rationai/staining/typing.py b/rationai/staining/typing.py index e57a567..66f443f 100644 --- a/rationai/staining/typing.py +++ b/rationai/staining/typing.py @@ -1,3 +1,4 @@ +from collections.abc import Callable from typing import TypeAlias from numpy import float64, uint8 @@ -5,6 +6,16 @@ from PIL.Image import Image +ModifyFunction: TypeAlias = Callable[ + [NDArray[float64], NDArray[float64], NDArray[float64]], + tuple[NDArray[float64], NDArray[float64], NDArray[float64]], +] +""" +Type definition for function that modifies stain channels. + +The function takes three arrays in stain space and returns their modified versions. +""" + Tile: TypeAlias = NDArray[float64 | uint8] | Image """ Type definition for a single tile. diff --git a/tests/conftest.py b/tests/conftest.py index d560f2e..6479e1f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,8 +2,17 @@ import pytest from numpy.typing import NDArray from PIL import Image +from skimage.color import rgb2lab -from rationai.staining.typing import RGBArray +from rationai.staining.typing import RGBArray, StainArray + + +def stain2lab(stain: StainArray) -> NDArray[np.float64]: + """Converts a pixel in stain space to LAB space.""" + stain = np.maximum(stain, 1e-6) + rgb = np.exp(stain) + + return rgb2lab(rgb) @pytest.fixture diff --git a/tests/data/generated/h_dab.jpg b/tests/data/generated/h_dab.jpg deleted file mode 100644 index 4ceaaf9daaff92df778098148eebda50edcd1dc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43338 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 ZMrI7Ph{oem}pYi;f_&@KKF>C+; diff --git a/tests/data/generated/h_dab.png b/tests/data/generated/h_dab.png new file mode 100644 index 0000000000000000000000000000000000000000..973134f479e972613496c065dbafc4bf5f59431f GIT binary patch literal 14855 zcmW+-cRbYpAOC#r+*!vNXK#|3k%*8JvI^OWPmocN`y;RL%~`H8Pe2q2Wc{G!`sme z-vyxk*`ik*u?|hSd!w`&EVYUJD=S!U{r*8Ol)i;;1p0$qcebMYdJuFu;sML-v5=<& z0E-~;%v}&48#P;T&!C>t7UFmfW#RlZJkBgR8KzK@cu@uS?Lq`URMrb|-p*EAukr1& z!#` zVAi6ZgZq1Ze{8+_6VV;*f8>SuFRnNE%cT`PA%R9G?x#Yd2{-hOJ&rS{4+l1!BT7ia z5$IpN+*&BVtr-+u zgtqe#jTJF@bF*$+ZfI`7a6Q*Wq4{Sxk?ur%Tn(OKyWI#9R!Q23*J9+@ zlKy;-pH}g>THNnBkp46{hA_KNXkNiREkZJH$bC(?7(mAM2G*THf|r$^6rJvR&vAt! zx8h`4FV{Ykd+&(cvH_-g>c`C|aD+mcS$6#lYiCTIVVDYPW;goNSa`=B!bqN_D)1oa zo3ZO|4vy>hkQumb0JAU{GCG*QlO)x^W~7c=qsIbQnMF4Yp&XN!*2A}4KQqrw;J!NT zY%pwc8p~?j)nh>2Oq)D8_iE0hgFohi^EtaP%ASIZ)m8QS`&T=eCyis#*7x%mIez^< zaBmS=#-4!u1d1T(Pff@-gdZNySF%R@0FrRHGqylQKFi?ApCFX8lp4fJcv|IX{!IU0 zP7&LaWPNoY;dd0bW`ELJMZzC2l&IY%83=bMGN=KiyH;U;;UNLUZ}(2^QEx%H@7a@d z1D@w#I9)9wuX13nVSExQ72b*LHm14v=8s?>k$Gn=Vt-}L=Cmk9#bJz&=ou?Fx9Q%| z=Yy}mq&Cj8y<_4hJ>A&6UrI~nO`&y&mogf@=$6+&heEdbo~CJtAO15gyqhAg8k2uH z3$!X0Lzs32&6e0)hT&1EC4jxF4Biqeql}AQ!C=R zfw-7-um41i!#8Y{VOJ~dSj$>n5UY&Jy8f%wc{;Fi{=D)HvBGX%$KSk6Z-bc6BH9%h zZ>Zt?4(_GQtLosU`xj)U0>!UlY?)R;!i$P^&1%k-V1|8F4<(m}3J9yzTf-_0qcfkq zy+3&u#DOXHVfiVEE+{d(&$>n-q2g^$V2pueNx4|(SY*$92{BOI?{X07$2RMbq507Nr zg|>QaBTCRlWY5&&GkgAdOz#=*=^emll@t)xd|(ChgtWZmf*(|02lJ2iFytq@aCx8zGr17QRUrb1`cn?;b9%_Wh%#p z{?$et+8yr*2^VcFMSW1^kLPn7{|Q|@lJ&l*D`q~Vc<}F+h3Jet5*yeLv@2UF4tlyxsn?;mA5;On zarb$0@(zoZw2M$o?yy*arVVQOKd5R6+p8*aOYzUgfdKSut<;a~M z5x8VBvd-`01~|gb@YWS=o8g*xFRn#H!E8MKn!bZ8G$R!L}@YB$fj721^+#hpe+N~^B29Wt?^u4k-K#gi~tH*z9j-Q~_}FJxk|9;e_<=+jgwtgH@l9aXv*ZO%zAmiaAZPEA3InzX zmQ6~^pl?b*4Qg8M4`A`e@_?W?o)99SdK6y&85gH6ModZ|XU!`Fsiz)#8eIFPKg^Fa z;r&Ams%bp@=#CD7M3Q)oksMAY?cBRsxuh;=5Q22pW`yZZ1ke+AH2o)a`1Q6#V)~;Q zv!ap;U^lxPdZy)04I3&e-3a#`oj&^auG3gvFTB1nF&FGu-s*mG1CB&5w4MC)6EsJ@ zcU7K=edK8A4UHU~hB^*ScP@nUi9eJ-9DiBG_du{Z|GFKm-_vwy&>%SjU8B2MUb8W; z0-OEH?SG%H#NVa$PPrgx7Ncr+~u# zzi%=(1;^pL9}|Z-tVq5$pO0`hQs@XwUeEM9`wNd}c~h!v`%*<67fFYq1z7POG^H8t z3-RG1$leAYf#uZr=k=S*1fhBjvE- z(;8iMgZxZkdC-JRYB1-J;nC%I`$tMgiBe>_5Jb%>{bH=qB(x)Hgp9vzF}MtN`&`L~ zGQFVk5sGg|{xWLQrKFiMc<4%-3|1T3&VnI64$!^GFS&Y!yybj-7HBgTX1{?B2EPUO!#0|Hko|j;yeC*50(t@K$je_2Zy}fvkSn!vRlQy8+&}q%@xk* zG{u#CPERC<2G9$3b5~*&G8qT?Qq36G&11cnbrQ*zr=R@901dqsswL0HTHj_38(7It zOi`CHf~vQ56b z<^zFO`O%m5jL-76ouw!jzCJ}MxUmnx>S@{=cni~pY_R(4)t+0CHDsRy>L6o3;@PSCa#KPPM&g=Tzj&A}PgpY@;Xj8_Vf#MeA&GCQGKa7`c zO9|gh9w*(jgAL_jP!bipBdUY3N!*SIknI(|pNZD!H-TKk43=desP# z^s5vo`wx-a*-4;R?`4ZoVEcvuzsc6VLc-=fe~u3hNNDpRYdH*&l8iH4X>~?k#7-K9 zavUt*euN1ICK&JOT*$+Fl7nAUwfkB)!!~<{{@&!QV=^hG!X9)tBAMvbi`ogCTW@|u zwJfK?8P*ye*Rj?q-bWt*FC@iZk&s_O#qbX78 zU*~P>K3x&3R^_yiWZUid z{l0Iz*BZEFy4!;x2aO7R!qt>CQIlmMykjHj*HUzk&oaL{5LdV8pRZ_LQ|Bj!e)So? zl*4U7xwbV1?F}=|c4#%yIRCZ(yVU)RzKrxeHGp^dPTN&_0vU?gogQ6jy>Lmfe&YC@ zYOpenqFEn&c@Jkj=X%g>cWhR;qg8p5_|*R;_VwIps}iZvw_{k0%LDJpRp1)1#Cvo@ zG-RUl+vMtv4;|%3B)j^$+y@llXryD6@`~Ln`Zkid(0bO_%Tl($oc_GF?4})K#~W-3 zkxQ%eUX3I!Oj>uw=-v~bH^v|GUM9bBhX1^KvP*T_c*C+g+AK2yB%~>RLQL?^CszpD z+&}&zu0S9cJ!z@^;LCO^nyS&Wwvnpvc(4k{Gzd^#0j8g&>LN+ako1S5clO*>UqTCS zw-O>;T$v97mHk(2e0b3KtQU2yy41<`Q@iiaoi|(MYg@Wa`qGf!n?E&^_Hou1j#$Cr zK7T*q$UeJvzvZUTOHF}C8pbcJ&f<#P@_Wy1Gx}K3u8hziQ&9f(bjr}#HVc|1w)8ZM zmpccyk&{(p(QR%uMU5D3SN73!(rE0LhGoz0lRl0k2Pq1cb-tFI?JFKI7{Ak+}ht;>BZaxN+KSJdp8g#3|xu4I;#O zE_HXSEm@otwo&58YUGNdCSu@6X+^GMgHe4DE<&kk*8oppFkXM z9Q*cMF7Uqo^e;6~e!SJ(FpM32edcEV$TPMqUD7yjA4A082mQ?qQ~3{j8kSP_?>Os^ zjFwC>vQmJ!VgVv8>m7>_&SXR9>4xR)x((r|SD`;R7XdHw=SZe2?zYJ|G!MF5vu?SZ z(4f=hd}xMuyDo6Yd}(oE!jdx+?}KdpAv-5^Q@oE_BI#ANsKh3P((NK5! zj8dY=RqIXAubB43Q(1E^Uhb*Psy!GxMtPcY^Cxr^B$%9ve#RAoa%+LFmco0La~hH(=GE! zc3pWZ+UZo}Kw#vXv1;^Vl1JjJJqHrhc6p|zvxI3-lU0-;+kzbFKWE`g&>rTq99l!PuIpGhZ@QsE?meH+ClG zwylh-p!{0rdkMcj|0VF77`NVf9|$+To2baAi!_*k&#JZ%DR{2jf-wvrzbKVD2U?dQ zFUXO2QQ&N5-ajK6)Pv3~21FNXD^ImFp133pNnK39n__l%ITpcUQFiM`4iz_m6*0!? zI;N+hZSC-w8vq=V`yINw^knmJMU2J*^7FruAdYa$U(J%>Loz-6JE}UU+?Bv#tFG9D z7vF})Mv+2Cq$E56hehtEtzy$~gkz(N(fLQ==7`irHIk0-to~_S169+)(Q*_~S!9^gT;*(G%LyKz?KE-GBQd%gVK9Z?2d6mxW}D@R{scqFcK!}GII))hG3L;^|J0f&{uj|j z=jiCQo;>ZIHg)90YDO{+=48nQ&%PaCXIdycqNX+q60Mx!@-L|=`Dfv`(JbOh6b_mA zs1@J|L~d(_{o_rebVWxP_~_G;aiwSt(cKFd3^d(3AHi8eWCwa<9~niEe!B<)-g{-J zf+QSF6p++U?8+1Mngwg{HJS*pQyIc9-l31~eUUw(SEg6G4zivzvCW2yE6vG5fZ5QW zcdCE4EG``PpWXTef?8*R^=&Z}2xt!1>9gu!P8>UcRYWEL&0t1YSfVef$#5Enn|*>% zQE{W6rYshO12~bP*w-Ua72zkjj&P1Zl%GB)aIx&>1$NQ&=ZN0%a#I8!0;Z-gKb!1%;4*{KN7yRWnTfqi$V&a0*kj)I5`GMDI+cO zb6`&&;hj4#a7?#MFHf}&y7!d}0HI)*e@+Se zWsQXE;umbLo*MfeAx5}Doc+%VXr^+f1?So1%?XM*#4W}qVSg|GQorFmXt@o1Y|5PO z7DZiH6iEp@ef0&@5&u{@`X=B!3qF=|Wc_>2=P~!KNp3Zj#~ zSrco%yR&zpG&biZW8EO950UPxw=-O?eY;Hvg6Pj@FX28w3*;=(qZpZdTK zU1_M6rdfcH;YS?&I{&bxbkv>Wn6Rq^Rd4@}m@}dA?#6nAoW&7Ll+~6L6YlA!zTq1J z>{af4faZDt1b$NHw^W}WmpOK7*FGuNgRjOl^+WdD^|MSaqoLzrW8a%184F!={xstV zL|>>=F_!h*MQef(`V7aS;4A$eJtRrAWbCWJ7#5%Uo57OJ5c76y+MBq~v~elRmh4c2 zK>?(qrHiF37^7lTPc>D+L>>fmtOd~p-S7ujXb>F$Ac?;LQC9;=(JxSRv243d4KidB z48W3JrO8ti2KfLq_rH^P1>v(N1)aA+fEceYkCSR&JSrnHF|mrWG4<5IRZejT0stpJ z0IZOn{va;f;z9bd#Uub2glQ=Nq9y>ar~m*8FA&p%*b_x7g**Se{NC?&1d%GP zSq|LO4Du6PxAg)@TO>gEz0NIWQ56mon*O~@@wim&@0R1HEAq6%f7)FH0MHn>1IiXN z=~9Jv<<6z_dCO0+&)9krGQd&0`|?Pj9lFQplyI66K&Hb48M=U8Vp1H)AtsS`3v4&6 z!0!q`e2O?sP ztr$`me>w@9#IudF_TcBh>@~YN+tfV<*ordy=uC<)mbMo^T~;Ud`$X=_D73>o_U=b+ z)c^(|uSaNg&pbyq!ZjGq_wJWBDAIY3fTgQVR4>bf3uGAHJ_0Wxj;%MME&tlv5=oKi zo|uu;;Jii4{1p>;0u_%tHxKAu&V17-T`0}u8UG`~uL^QO*bvIaT(AGy()j%W0QkYC zdBJk*MOy?=z`@NV4PaR1aUXDu0AT-{4Oqs8%z^-pPy;em>ZLFMfNfh8KnwNOnlI^7 zYZ3tH^}iO<^HOfFC^25=eT0q!6sVW92T#zoeebON*dPe-Kw?*3JkZAD-hJzQZI}<7 z^t*>2ebLFw{btvT=4%Kf|8gRLNyLF(Yxi@%=WJ(!0LJ(=op+bK`FAM-0K~Oj;VK`P zQbUhCQy?I~ADhSU4Q>CndkY7WVgMY76)1Pg`j5xiX0klfgl)!Mj{B-#EDpN_#kt}9 zm`<`7gjF6jV&mBQ;J!>fZWO7b%fJ1h7^lqcftl5nfkRUj_*Zzk!{%Q%EpdWzQ;f{g z7VfTz8gohuo2v085jbZUHaOyLOTN4IE(t=cts5`^cX{W00|} zmo4}h&fRia;{eW4!>aCTOMjTVIe6mH1H&w{vimlY7c{&Yji6VNpB}Y9LiE*>PbB@_=;qHl zQ$~Kl14=DZ=NC7}jdgX_sIiXWcF7lHWGl7*^pA%FG5SMSfZkp zFCg~J>Ch^9>HqVf-07V&p@ajTr|Y|W2)eVBhA)B@G{T$Yby;VuqTSw6tEeTw{>Du_k(WPRI`)ziCa_&Kb^ z;RKZAsR_GHVv&rskly1JgK?SCV9o3H-wKYpW{ql;3Y!hQ27WiR#!<~eytM}Dgugfw zYGgw@#UvDE(aB~27u7hcO0K?PYgkPPkiZL zm}`Op%YE|&KIbtpZlRdaCvyBa{yJ}Z39!8W7w0VGM+q<2E3aGCRsl@;KRu~u!jT>P z9$8da6RD4_upumCz@wEXx;qg#*6p!Y@gi{_$UeW}N>{I#pGh z_wugmCG(2J-HnpH9AMjqAYjwNT}gXXb&zQFNz?#+wf+HW1;?^>J>30jr)_v5`>2?$ ztOyI7BSBFVb2sMO@L3nYn%ALh!7$@QTBttiL7oMQrBJ|bv^7G`EgReo2chk;=wa``c73x zsj=TDjrUI?Bd3T(o$r*`ci4;*--rs zN%7gI-34VR47RAV!DYr)_DDbE-DQZfUu}5pK-P5F?HEv5(}djG-UqGkY*@Z1si{xm zP>1sXOC`I7cFsc;SKqvbp7Cpr`@6##fbqcqX!z27BwUmz^H$e^O0U#9B+g5aGKoK1 zu=ERdjGmQxA!R=RaRWeB)mLfFTcX^F&lUh;FSJ9`sWA!|;A0Q(CD~TAf?OpFeVMq8smYs_vdXS8pfiF zzXQV3%k;8M?p_s4js3`v8Tc(AjnvHKgYe**e~TFDJ!iu`<2=BfjE>EQocsI$w{l@~ z1Ki*P2(t^I6?QPTPhR|mfxpCSan264$IGM0hxlFJMUAUx&S-o+ZFS8(Oh-?I$`I}s zK?-w>g)R@UyH56EnapysK~4EhTVie-CTTN5yTvszSGXoiPAnq_%2aziB+YG1Mq1#V z<2$#95)`j4)6(f(6`vlH1ka6=pS9o7%D$}h0NInG$&O;wI#GFCcq}j8!wujPz8t0{ zlUGmKZT@q7>P@V>i~I6|qicpK63xkh|4V4tuB*B0^mcFOd;aDWYdOKhpp2ik{m8S& zOzFX!z=~#^?Fg-yyGeI2_-?aKr#I2@wRIU*RqQJNCG)->%f;=F!H@$>>$8-5ec74| z*#`8cn0}L2!?4M|6G;Q-Hdd{Q-g>29{>;xuY~hJ@YBWqvWO;j_^$Rq3ENk}m*9Vh& z&wG+f=VRWoJ=}*}tG_ZLAX0Fxu)nH#NC+(~NIdDJ ztT#FOwMI#nb?&G``cpLfhxoRoLLTrZc`+lwAJ6^l~~2!dh1TvLb{ z-R_K!u2)X{1!hQ%#ksy2gL=p{xGOSuGBxygYs!`Q+TR=Up)_-fWDhQ(hq zzH$=UW3kA(y9H>Jt#g!xUiND$8QR>06E$ zYjJVav<(vt1M+QoSI-&QZ%=t@?$wot&;<=Snd8Z1Iwrb1(RIqk{z}DB;OdT9bREvv zx2#$K@ctsGsoxgnbanum30y~6Ev)?d#7_vRg%vm4ck2f^;$Pg2awJ%c2cCb*d+Bx^ zj|=++PMPHqMV7lIk2mJ-1_4!BFrgYoQQ)co3GOm`TcA*WU)Gm4qN57z!`k4rDlv?G zA!#~)f1(S0d&hS>VgI~|HK1DLPpvEN){+%WW*NKtHXT(Dfh3)_W-uXlpIPXTr{vqx zE)F%tEDItB#j`e+TbNGzLEG{_GAX-7%VHHr={b;+?(apPku7b0fOwny%-@XVuK|)YhFhBpo+l9ru%Ows zHA1ovV#4{;4i7k14677^l#ymvWUe1|r1jwr0~mGl82fnd%H;qxrXSDwWo#t28^52p z3+NzC$U0qWO;2xWq}zUXG5Kk~d~GCBd8-j6{-QCz^4M3BXy!A@eA9fi!!qd(vM@eUn>*t{(iKD z6P+ujIbX|!eDG4xd_0Z=TU<3eIILbW#zv+$@Tpa`$3W!nx83F0r~H2ik?0LnN&^0?LZ3pPz(y0diYJvZ z5r#U%`+kL$+!4R>+T-{k^2I{(1%}AY(k>I4!@WjuO3Pdk=4XaZ zlT(fPBhqM7KH8|jtOx#_?nQHleMJql1YsCn31r$D0pF+%*S=kImcBp^PIU5TY`_~% z?Mwo-lejDv?$#{MB7;(zLe~K6N6XSPyXXf?qjv3Ramk`I(C~%`lAaw27c1^%l z<*C1hq?50%*^;m4D5ZE4@ja&x8rQ>GkI%0ElzhbsF?*jQ&%Iw$5oQ|6>U`8V{2v0J zUzriEdRy^OaV%DJvg4ccB0e!jPj_epJIT0Ey5ztl#LqQja0~hqr=d$>;z2_ND=v=^ z^_1V=*=~CWUUM%g^OS|*G$CH!zj(>N^y2Zq8tr;q zlVP5)Jz*-*3bfij6~LD%_TA1c>ixS4l%sMY<+i4#y6u?;>7IyEuVPf%hZuTz(@o`2`)t^$gl0uXTuoFYoNVg)f zr#HX8dmpcz5aX?4NL6wd5*I-C3Et>Vmx9ArX66O{|M$J4xt@(-azX-Ty8-?ZQPPIx zJfwPh2ax-lV5OtUR>@tIkkxxhKO8#;A6W9Y#*(d6rnjsX-P%o|76ew+;GJ$Gzlt zETmPEiSoyHUzhz}9=bKwa#QxO?k$vh>H?i=tZ2J2IC1%Qsa6}h#hG`goGzp&O%%R@ ze|?El)V>jZW!ANoQk!3j{Nb}(CPyP%PGCEKhy2o*G1gCKdXZqaE|}v@%($&}b@6)O zOH}gtm|gYU&+WNB=7pzewfyqHkAqa zf}V#eG&%Mzfda2T@XVYs+Mj5&2P-U?e_OYoD_gvu;SE9~`Jdivi zmm&v#{W4^v!LF(>Xjyg%mUeOa1b#djLnuM-Hz94a3)ly3R%S~`Bwp#lfX0-v1db~jvOh66}p>vrb+UVl9JPbwRCZnJ6iVdRa z1pJP>zOaVx25;s!|C2$f&i{5lp`I zPowKnqOijs2HOd%@mBka0_p_PfqV=$#AMp7?~M#DkXQ)#?(#Cy_pxVx`*oyqhs)s? z)qv(4%I@Pu6d~AsCd={OzkTjdg9O#=ozOD0>49A8?Gox`*ZEsQQ!ih0@8X6Kr0gmM z$5b81)XQUw_#dJi;S9?t6Rb%0exjCEheb;2QK>NJE=~wK&V2cI(Cm4)&1-PCS4N~y ze}TZgtiL_K@;$@hHnb@j+mDG)7<2g1C5y3p&^voGSE_y2&R(D|sB@6UJr*OO4RRQg zEiJnrlefrbTAawkPT;D#^e2XjMs|CvKrwS9v5Cz}@~tT4sUNTV5*>hWP+SimQSa&Qjg%z%n$i+o9KVs{S~OK3rLow|Ncw%|xKq*8S2 zNK(G&r-4|ba&KJM3vVCMkTLG0@B>9_`)H6~UXOq0H}&U}%;U=j=jlYG@T0I=5t;9d z()6Wy`RFv6IXY#uY^FeoG0_BrH}8t+KJ)es@z)!h9Lg~Az{8c+V!Phpmw5Xj;|4}_ zdSJXY7K!eFKgggyEpFF;B5~!!9z5l{R8ZnGM&Yuyj*MJjT)k+>4ZT*7HVQp|`^?4{ zjAqY!v97g!jQ62a<~OD@&I^4#^{EHfJ_@)zevVY6RPwJ``JC*v!lrZTBRP)CN2Y(* z2rX6B8jz0!NKhixp?FnfLqSfvB7W}rN$TJAGK=+UEMe5}`GgyKncxT=lVYqdV_>kv zw~)6`!p`DDolwqdABb$Qu^Yvnvikgd4OjX&BFKwyiB;{q%|7&Lh-pBER%h{Pp?mU6 z+784l*4kvnJj&s=!PY!lp}_6=>WAzK-pHBhSJMv-)c~`;6iy*sX9IJI)7yApt}tJ7E`V&E zC>^b=zTC?ihP^`!C8D3P3u8U*@W%5LNF<;f@Of5k#9()4O z(7LA(w`YHBANEPva$40i;Hj@;K%CFXj57PgjFscZXEw{n$8n<#v$}xT@I%@fhu)R| zib%aB*~Ay#8R^k>&>IJ8s-y(5AGh$oi?q=9Ldu>Ad}u_IrBh<=f&yh|6q=iod(&j^ zyQY$)a)8>PnifA!eg3obgBYCDb~4T;=qu?@X^l|1T#I}~t|$9ExIfZrI)a_!{;mW$ zEr{l*Vd+Wr*yZebWJ_rSNPuEQWW;(k6)vy#ApLF?wU22#(f=%GsXzo>WPrhmsg1ia zJt@DQi;GBasW88S-O`gXp*c$^LEFQKRTw!qT=!>S7oXGlZ&-s(YbDEA z1vf+|{!A)5I1lLE+@k*)0lVOEzywX%<9{0{@WJFUvCJMjmR|;i^0SoeVr}CfKeu#n zg=;(I*n!}6&2TS%k|vt6b2>z7=TmJEw63C6Gy*xRXMN{FISoMUTab7eh9wKAlKl;A zYPNusN=?Y6PLg~g2akRe4hQ1Q;opjCh+mDR`)3C$hw!NB%~GFPBdiLCQI`V4|gvEuPbZX`2z}a%XSy8w#bnnlV7%OT6Oxal$>aLCiyV zK6Bpa!9&J71U;*5YT+HJxAg99zDJ*cAf}05HbUsFobCO;pDxB}@0H#RIJ=g0pYAN? zWeXKP$&90-L9o4P8!gg}X0 z>&t@5q@^ax>`rh&CLH1vwukbpL7>txtxQtWl#Z;q66Y_nJ?p)XaTDJeeA&uS7C06n z-pX>+=-q{NQMJ#cCtRui1E&&aH!|9x@WG2YzRN;Co`##)hBAs}TNnCr6K-j6v;p=I zI5UFyOx#k{*6WDNBS7B7c9P3i=(Nza@W+}%5a=w&?|+?$Am!(xNt+wJZVWo$=FINjk>eA{~rLoMQ)VqihHoeXI=1CgB^hurQ6mW zXK}gY&0DmdA?78~t(|KDxtK#yiM_v42y~nuV>aL^89{mq)>qOpbGhq(k_K2u&c@u0 z>~l;35fn((9e=t|N;g%e)1egP)X5 zf|7V@=k?0+XY?dvB}s68oJie54CdKkK@rLXL|`1P7yx%KnRq;01+dxjA;rE&fuS1n zqoScdRRceFLMQa&ea>3Ks5n~Dt%XXBCH%T41EPPsrHfWy;yB9me_Jo^3{IO$r8Ono)yzYOkf z(#b8Hz6VE<>9;S)oi(RHy#RZL^--~9EQb}yP?E@|!oH_{0T&WPACF*a}*ryj3a+YLyi6y1O(~ zd*gM`H+^KrHQPO9hHXGGU}r%OI>>%!UWRWaoJjq^?@Vsc{0XEUKO_xk;o2mpXTx3G zre4KtNI>TA?zO&N?EFv55KS)(^_l&VCZ>1MT2@&`yIK89GM=0~xZATdEa1M`7l4~W zC4{j3e*!Xdri_AORPat91}6-DFzTiRcfJDykxL(<4G+V3^C@3XkNSjIVM!OADc{`@ z{?OI9&*${Vk1luEg;Zk)c=4g~bT@g{L!2Tb_SBH~MUc~S=}F|@livP;3jR>XQPIU% xxXRsbjy59-_TTski`mXT{pydb2LHBbP}37v$>{iPx;+j6rbZTq)fX^?{{h$OUbFxJ literal 0 HcmV?d00001 diff --git a/tests/data/generated/h_dab_legacy.png b/tests/data/generated/h_dab_legacy.png new file mode 100644 index 0000000000000000000000000000000000000000..270e45f78e889780ffde33bf52159f12b7a5f2bc GIT binary patch literal 14366 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 literal 0 HcmV?d00001 diff --git a/tests/data/generated/h_e.jpg b/tests/data/generated/h_e.jpg deleted file mode 100644 index d3552c2f1dc4367053bb581629f992bc43dd00e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42565 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 diff --git a/tests/data/generated/h_e.png b/tests/data/generated/h_e.png new file mode 100644 index 0000000000000000000000000000000000000000..951b6697b379c00ca08849f1a59bcad3eb42136b GIT binary patch literal 14366 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 literal 0 HcmV?d00001 diff --git a/tests/scripts/generate_artifical_tissue.py b/tests/scripts/generate_artifical_tissue.py index 15349c6..06cb971 100644 --- a/tests/scripts/generate_artifical_tissue.py +++ b/tests/scripts/generate_artifical_tissue.py @@ -11,6 +11,7 @@ H_RGB = np.array([88, 76, 180], dtype=np.uint8) # from QuPath E_RGB = np.array([199, 50, 112], dtype=np.uint8) # from QuPath DAB_RGB = np.array([186, 110, 56], dtype=np.uint8) # from QuPath +LIGHT_H_RGB = np.array([38, 123, 223], dtype=np.uint8) def _stretch(x: NDArray[np.float64], down: float, up: float) -> NDArray[np.float64]: @@ -58,10 +59,13 @@ def artificial_image(c0: RGBArray, c1: RGBArray, conv: ColorConversion) -> RGBAr def main() -> None: h_e = artificial_image(H_RGB, E_RGB, ColorConversion.RGB2HER) - Image.fromarray(h_e).save("tests/data/generated/h_e.jpg") + Image.fromarray(h_e).save("tests/data/generated/h_e.png") - h_dab = artificial_image(H_RGB, DAB_RGB, ColorConversion.RGB2HDR) - Image.fromarray(h_dab).save("tests/data/generated/h_dab.jpg") + h_dab_legacy = artificial_image(H_RGB, DAB_RGB, ColorConversion.RGB2HDR_LEGACY) + Image.fromarray(h_dab_legacy).save("tests/data/generated/h_dab_legacy.png") + + h_dab = artificial_image(LIGHT_H_RGB, DAB_RGB, ColorConversion.RGB2HDR) + Image.fromarray(h_dab).save("tests/data/generated/h_dab.png") if __name__ == "__main__": diff --git a/tests/test_color_conversion.py b/tests/test_color_conversion.py index 4e842fc..302d421 100644 --- a/tests/test_color_conversion.py +++ b/tests/test_color_conversion.py @@ -2,7 +2,7 @@ import pytest from rationai.staining import ColorConversion -from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H from rationai.staining.typing import StainTuple from rationai.staining.utils import residual @@ -22,10 +22,11 @@ def test_inverse_conversion(conversion: ColorConversion) -> None: STAINS = [ # Expected values are taken from QuPath (QUPATH_H, QUPATH_E, (0.316, -0.598, 0.737)), + (LIGHT_H, QUPATH_DAB, (0.418, -0.796, 0.437)), (QUPATH_H, QUPATH_DAB, (0.633, -0.713, 0.302)), ] -@pytest.mark.parametrize("s0,s1,expected", STAINS, ids=["H&E", "H&DAB"]) +@pytest.mark.parametrize("s0,s1,expected", STAINS, ids=["H&E", "H&DAB", "H&DAB_LEGACY"]) def test_residual(s0: StainTuple, s1: StainTuple, expected: StainTuple) -> None: assert np.all(np.isclose(residual(s0, s1), expected, atol=0.001)) diff --git a/tests/test_modify_and_reconstruct.py b/tests/test_modify_and_reconstruct.py new file mode 100644 index 0000000..f9c2a86 --- /dev/null +++ b/tests/test_modify_and_reconstruct.py @@ -0,0 +1,61 @@ +import numpy as np +import pytest +from numpy.typing import NDArray +from skimage.data import immunohistochemistry +from skimage.metrics import structural_similarity + +from rationai.staining import modify_and_reconstruct +from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.typing import ModifyFunction, RGBArray, StainTuple + + +C = NDArray[np.float64] + + +def _no_change(c0: C, c1: C, c2: C) -> tuple[C, C, C]: + return c0, c1, c2 + + +IMAGES_AND_STAINS = [ + ( + immunohistochemistry(), + _no_change, + LIGHT_H, + QUPATH_DAB, + None, + ), + ( + "sample1_original", + _no_change, + QUPATH_H, + QUPATH_E, + None, + ), +] + +TEST_IDS = ["skimage-default; no change", "Sample1; no change"] + + +@pytest.mark.parametrize( + "original,modify,stain0,stain1,stain2", IMAGES_AND_STAINS, ids=TEST_IDS +) +def test_modify_and_reconstruct( + original: RGBArray | str, + modify: ModifyFunction, + stain0: StainTuple, + stain1: StainTuple, + stain2: StainTuple, + request: pytest.FixtureRequest, +) -> None: + if isinstance(original, str): + original = request.getfixturevalue(original) + + reconstructed = modify_and_reconstruct( + tile=original, # type: ignore[arg-type] + modify=modify, + stain0=stain0, + stain1=stain1, + stain2=stain2, + ) + + assert structural_similarity(original, reconstructed, channel_axis=-1) > 0.99 diff --git a/tests/test_stain_estimator.py b/tests/test_stain_estimator.py index 8104b59..83e390e 100644 --- a/tests/test_stain_estimator.py +++ b/tests/test_stain_estimator.py @@ -3,6 +3,7 @@ import numpy as np import pytest +from conftest import stain2lab from numpy.typing import NDArray from PIL import Image from skimage.color import deltaE_ciede2000 @@ -10,7 +11,7 @@ from skimage.filters import gaussian from rationai.staining import ColorConversion, convert_color, estimate_stain_vectors -from rationai.staining.constants import QUPATH_DAB, QUPATH_E, QUPATH_H +from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H from rationai.staining.typing import StainArray, Tile @@ -45,22 +46,32 @@ def _blur(img: NDArray[np.uint8], sigma: float) -> NDArray[np.uint8]: QUPATH_DAB, ), ( - np.asarray(Image.open(GENERATED_DIR / "h_e.jpg")), + np.asarray(Image.open(GENERATED_DIR / "h_e.png")), QUPATH_H, QUPATH_E, ), ( - np.asarray(Image.open(GENERATED_DIR / "h_dab.jpg")), + np.asarray(Image.open(GENERATED_DIR / "h_dab.png")), + LIGHT_H, + QUPATH_DAB, + ), + ( + np.asarray(Image.open(GENERATED_DIR / "h_dab_legacy.png")), QUPATH_H, QUPATH_DAB, ), ( - _blur(np.asarray(Image.open(GENERATED_DIR / "h_e.jpg")), sigma=5), + _blur(np.asarray(Image.open(GENERATED_DIR / "h_e.png")), sigma=5), QUPATH_H, QUPATH_E, ), ( - _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab.jpg")), sigma=5), + _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab.png")), sigma=5), + LIGHT_H, + QUPATH_DAB, + ), + ( + _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab_legacy.png")), sigma=5), QUPATH_H, QUPATH_DAB, ), @@ -72,11 +83,13 @@ def _blur(img: NDArray[np.uint8], sigma: float) -> NDArray[np.uint8]: ] IDS = [ - "Default skimage image H&DAB", + "Default skimage image H&DAB_LEGACY", "Artificial H&E", "Artificial H&DAB", + "Artificial H&DAB_LEGACY", "Blurred Artificial H&E", "Blurred Artificial H&DAB", + "Blurred Artificial H&DAB_LEGACY", "Empty Image", ] @@ -101,5 +114,8 @@ def test_estimation_color_difference( stain1, stain2 = estimate_stain_vectors(img) delta = deltaE_ciede2000 - assert delta(stain1, expected1) < 1 or self._both_nan(stain1, expected1) - assert delta(stain2, expected2) < 1 or self._both_nan(stain2, expected2) + stain1, stain2 = stain2lab(stain1), stain2lab(stain2) + expected1, expected2 = stain2lab(expected1), stain2lab(expected2) + + assert delta(stain1, expected1) < 15 or self._both_nan(stain1, expected1) + assert delta(stain2, expected2) < 15 or self._both_nan(stain2, expected2) diff --git a/tests/test_stain_reconstruction.py b/tests/test_stain_reconstruction.py index 4a5f53b..323a764 100644 --- a/tests/test_stain_reconstruction.py +++ b/tests/test_stain_reconstruction.py @@ -12,13 +12,17 @@ immunohistochemistry(), ColorConversion.RGB2HDR, ), + ( + immunohistochemistry(), + ColorConversion.RGB2HDR_LEGACY, + ), ( "sample1_original", ColorConversion.RGB2HER, ), ] -TEST_IDS = ["skimage-default; H&DAB", "Sample1; H&E"] +TEST_IDS = ["skimage-default; H&DAB", "skimage-default; H&DAB_LEGACY", "Sample1; H&E"] @pytest.mark.parametrize("original,conv", IMAGES_AND_CONVS, ids=TEST_IDS) diff --git a/tests/test_stain_separation.py b/tests/test_stain_separation.py index e02357e..ecca7d8 100644 --- a/tests/test_stain_separation.py +++ b/tests/test_stain_separation.py @@ -10,6 +10,7 @@ RGB_CONVERSIONS = [ ColorConversion.RGB2HER, ColorConversion.RGB2HDR, + ColorConversion.RGB2HDR_LEGACY, ] RGB_NAMES = [c.name for c in RGB_CONVERSIONS] From b8570a026cbd4717cb50242dec2f0cce255671eb Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni.cz> Date: Tue, 4 Mar 2025 23:46:53 +0100 Subject: [PATCH 26/79] feat: ml init --- .gitignore | 9 +- .gitlab-ci.yml | 7 +- .mypy.ini | 3 +- .pre-commit-config.yaml | 12 +- .pylintrc | 399 --- README.md | 43 +- .../datasets/stain_normalization/predict.yaml | 6 + .../datasets/stain_normalization/test.yaml | 6 + .../datasets/stain_normalization/train.yaml | 6 + .../datasets/stain_normalization/val.yaml | 7 + configs/data/modify/test.yaml | 12 + configs/data/modify/train.yaml | 12 + configs/data/transforms/test.yaml | 4 + configs/data/transforms/train.yaml | 16 + configs/default.yaml | 42 + .../py.typed => configs/experiment/.gitkeep | 0 configs/hydra/default.yaml | 7 + configs/logger/mlflow.yaml | 6 + configs/model/backbone/resnet50.yaml | 2 + configs/model/backbone/vgg16.yaml | 2 + configs/model/decode_head/unet2048.yaml | 5 + configs/model/decode_head/unet512.yaml | 5 + docs/api/color-conversion.md | 1 - docs/api/constants.md | 1 - docs/api/estimate-stain-vectors.md | 1 - docs/api/modify-and-reconstruct.md | 1 - docs/api/typing.md | 1 - docs/getting-started.md | 15 - docs/index.md | 1 - mkdocs.yml | 76 - nohup.out | 2772 +++++++++++++++++ pdm.lock | 2265 ++++++++++---- preprocessing/mask_generator.py | 69 + preprocessing/tiler.py | 120 + pyproject.toml | 32 +- pytest.ini | 6 - rationai/staining/__init__.py | 16 - rationai/staining/constants.py | 27 - rationai/staining/convert_color.py | 197 -- rationai/staining/estimate_stain_vectors.py | 63 - rationai/staining/modify_and_reconstruct.py | 73 - rationai/staining/scripts/remove_red_stain.py | 38 - rationai/staining/typing.py | 47 - rationai/staining/utils/__init__.py | 6 - rationai/staining/utils/inv_mat.py | 8 - rationai/staining/utils/normalize.py | 9 - rationai/staining/utils/residual.py | 12 - stain_normalization/__init__.py | 0 stain_normalization/data/__init__.py | 4 + stain_normalization/data/data_module.py | 51 + stain_normalization/data/datasets/__init__.py | 4 + .../data/datasets/stain_normalization.py | 114 + .../data/transformation/__init__.py | 7 + .../transformation/combiend_modification.py | 23 + .../transformation/exposure_adjustment.py | 17 + .../data/transformation/hed_factor.py | 27 + .../data/transformation/hue_shift.py | 34 + stain_normalization/main.py | 35 + stain_normalization/modeling/__init__.py | 3 + .../modeling/backbone/__init__.py | 5 + .../modeling/backbone/resnet50.py | 7 + .../modeling/backbone/vgg16.py | 6 + .../modeling/decode_head/__init__.py | 4 + .../modeling/decode_head/unet.py | 35 + stain_normalization/modeling/l1ssim_loss.py | 75 + .../stain_normalization_model.py | 68 + stain_normalization/typing.py | 20 + tests/conftest.py | 51 - tests/data/generated/h_dab.png | Bin 14855 -> 0 bytes tests/data/generated/h_dab_legacy.png | Bin 14366 -> 0 bytes tests/data/generated/h_e.png | Bin 14366 -> 0 bytes tests/data/sample1/eosin.png | Bin 183161 -> 0 bytes tests/data/sample1/hematoxylin.png | Bin 203258 -> 0 bytes tests/data/sample1/original.jpg | Bin 83398 -> 0 bytes tests/data/sample1/residual.png | Bin 79895 -> 0 bytes tests/scripts/generate_artifical_tissue.py | 72 - tests/test_color_conversion.py | 32 - tests/test_modify_and_reconstruct.py | 61 - tests/test_stain_estimator.py | 121 - tests/test_stain_reconstruction.py | 44 - tests/test_stain_separation.py | 53 - 81 files changed, 5396 insertions(+), 2045 deletions(-) delete mode 100644 .pylintrc create mode 100644 configs/data/datasets/stain_normalization/predict.yaml create mode 100644 configs/data/datasets/stain_normalization/test.yaml create mode 100644 configs/data/datasets/stain_normalization/train.yaml create mode 100644 configs/data/datasets/stain_normalization/val.yaml create mode 100644 configs/data/modify/test.yaml create mode 100644 configs/data/modify/train.yaml create mode 100644 configs/data/transforms/test.yaml create mode 100644 configs/data/transforms/train.yaml create mode 100644 configs/default.yaml rename rationai/staining/py.typed => configs/experiment/.gitkeep (100%) create mode 100644 configs/hydra/default.yaml create mode 100644 configs/logger/mlflow.yaml create mode 100644 configs/model/backbone/resnet50.yaml create mode 100644 configs/model/backbone/vgg16.yaml create mode 100644 configs/model/decode_head/unet2048.yaml create mode 100644 configs/model/decode_head/unet512.yaml delete mode 100644 docs/api/color-conversion.md delete mode 100644 docs/api/constants.md delete mode 100644 docs/api/estimate-stain-vectors.md delete mode 100644 docs/api/modify-and-reconstruct.md delete mode 100644 docs/api/typing.md delete mode 100644 docs/getting-started.md delete mode 100644 docs/index.md delete mode 100644 mkdocs.yml create mode 100644 nohup.out create mode 100644 preprocessing/mask_generator.py create mode 100644 preprocessing/tiler.py delete mode 100644 pytest.ini delete mode 100644 rationai/staining/__init__.py delete mode 100644 rationai/staining/constants.py delete mode 100644 rationai/staining/convert_color.py delete mode 100644 rationai/staining/estimate_stain_vectors.py delete mode 100644 rationai/staining/modify_and_reconstruct.py delete mode 100644 rationai/staining/scripts/remove_red_stain.py delete mode 100644 rationai/staining/typing.py delete mode 100644 rationai/staining/utils/__init__.py delete mode 100644 rationai/staining/utils/inv_mat.py delete mode 100644 rationai/staining/utils/normalize.py delete mode 100644 rationai/staining/utils/residual.py create mode 100644 stain_normalization/__init__.py create mode 100644 stain_normalization/data/__init__.py create mode 100644 stain_normalization/data/data_module.py create mode 100644 stain_normalization/data/datasets/__init__.py create mode 100644 stain_normalization/data/datasets/stain_normalization.py create mode 100644 stain_normalization/data/transformation/__init__.py create mode 100644 stain_normalization/data/transformation/combiend_modification.py create mode 100644 stain_normalization/data/transformation/exposure_adjustment.py create mode 100644 stain_normalization/data/transformation/hed_factor.py create mode 100644 stain_normalization/data/transformation/hue_shift.py create mode 100644 stain_normalization/main.py create mode 100644 stain_normalization/modeling/__init__.py create mode 100644 stain_normalization/modeling/backbone/__init__.py create mode 100644 stain_normalization/modeling/backbone/resnet50.py create mode 100644 stain_normalization/modeling/backbone/vgg16.py create mode 100644 stain_normalization/modeling/decode_head/__init__.py create mode 100644 stain_normalization/modeling/decode_head/unet.py create mode 100644 stain_normalization/modeling/l1ssim_loss.py create mode 100644 stain_normalization/stain_normalization_model.py create mode 100644 stain_normalization/typing.py delete mode 100644 tests/conftest.py delete mode 100644 tests/data/generated/h_dab.png delete mode 100644 tests/data/generated/h_dab_legacy.png delete mode 100644 tests/data/generated/h_e.png delete mode 100644 tests/data/sample1/eosin.png delete mode 100644 tests/data/sample1/hematoxylin.png delete mode 100644 tests/data/sample1/original.jpg delete mode 100644 tests/data/sample1/residual.png delete mode 100644 tests/scripts/generate_artifical_tissue.py delete mode 100644 tests/test_color_conversion.py delete mode 100644 tests/test_modify_and_reconstruct.py delete mode 100644 tests/test_stain_estimator.py delete mode 100644 tests/test_stain_reconstruction.py delete mode 100644 tests/test_stain_separation.py diff --git a/.gitignore b/.gitignore index f490645..1c12553 100644 --- a/.gitignore +++ b/.gitignore @@ -138,7 +138,7 @@ venv.bak/ .ropeproject # mkdocs documentation -/site +site # mypy .mypy_cache/ @@ -166,6 +166,10 @@ cython_debug/ # Mlflow mlruns/ mlflow_store/ +mlflow_artifacts/ + +# Pytorch Lightning +lightning_logs/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can @@ -173,3 +177,6 @@ mlflow_store/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ + +# Project +/data diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9d40d40..b132c47 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,6 @@ include: project: rationai/digital-pathology/templates/ci-templates - file: - - Pytest.gitlab-ci.yml - - Python-Lint.gitlab-ci.yml - - MkDocs.gitlab-ci.yml + file: Python-Lint.gitlab-ci.yml stages: - lint - - test - - deploy diff --git a/.mypy.ini b/.mypy.ini index 8d15f3c..1c6f44e 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -2,5 +2,4 @@ strict = True ignore_missing_imports = True disallow_untyped_calls = False -disable_error_code = no-any-return -explicit_package_bases = True \ No newline at end of file +disable_error_code = no-any-return \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9bbe87c..8b99ad0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,19 +7,17 @@ repos: - id: check-yaml args: [--unsafe] - - repo: https://github.com/compilerla/conventional-pre-commit - rev: v3.6.0 + - repo: https://github.com/commitizen-tools/commitizen + rev: v3.30.1 hooks: - - id: conventional-pre-commit - stages: [commit-msg] - args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] + - id: commitizen - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.1 + rev: v0.7.3 hooks: # Run the linter. - id: ruff entry: pdm lint --force-exclude - # Run the formatter. + # Run the formatter. - id: ruff-format entry: pdm format --force-exclude diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index c608030..0000000 --- a/.pylintrc +++ /dev/null @@ -1,399 +0,0 @@ -# This Pylint rcfile contains a best-effort configuration to uphold the -# best-practices and style described in the Google Python style guide: -# https://google.github.io/styleguide/pyguide.html -# -# Its canonical open-source location is: -# https://google.github.io/styleguide/pylintrc - -[MAIN] - -# Files or directories to be skipped. They should be base names, not paths. -ignore=third_party - -# Files or directories matching the regex patterns are skipped. The regex -# matches against base names, not paths. -ignore-patterns= - -# Pickle collected data for later comparisons. -persistent=no - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=4 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=R, - abstract-method, - apply-builtin, - arguments-differ, - attribute-defined-outside-init, - backtick, - bad-option-value, - basestring-builtin, - buffer-builtin, - c-extension-no-member, - consider-using-enumerate, - cmp-builtin, - cmp-method, - coerce-builtin, - coerce-method, - delslice-method, - div-method, - eq-without-hash, - execfile-builtin, - file-builtin, - filter-builtin-not-iterating, - fixme, - getslice-method, - global-statement, - hex-method, - idiv-method, - implicit-str-concat, - import-error, - import-self, - import-star-module-level, - input-builtin, - intern-builtin, - invalid-str-codec, - locally-disabled, - long-builtin, - long-suffix, - map-builtin-not-iterating, - misplaced-comparison-constant, - missing-function-docstring, - metaclass-assignment, - next-method-called, - next-method-defined, - no-absolute-import, - no-init, # added - no-member, - no-name-in-module, - no-self-use, - nonzero-method, - oct-method, - old-division, - old-ne-operator, - old-octal-literal, - old-raise-syntax, - parameter-unpacking, - print-statement, - raising-string, - range-builtin-not-iterating, - raw_input-builtin, - rdiv-method, - reduce-builtin, - relative-import, - reload-builtin, - round-builtin, - setslice-method, - signature-differs, - standarderror-builtin, - suppressed-message, - sys-max-int, - trailing-newlines, - unichr-builtin, - unicode-builtin, - unnecessary-pass, - unpacking-in-except, - useless-else-on-loop, - useless-suppression, - using-cmp-argument, - wrong-import-order, - xrange-builtin, - zip-builtin-not-iterating, - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[BASIC] - -# Good variable names which should always be accepted, separated by a comma -good-names=main,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl - -# Regular expression matching correct function names -function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*)|(?P_?[a-z][a-z0-9_]*))$ - -# Regular expression matching correct variable names -variable-rgx=^[a-z][a-z0-9_]*$ - -# Regular expression matching correct constant names -const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ - -# Regular expression matching correct attribute names -attr-rgx=^_{0,2}[a-z][a-z0-9_]*$ - -# Regular expression matching correct argument names -argument-rgx=^[a-z][a-z0-9_]*$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=^[a-z][a-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=^_?[A-Z][a-zA-Z0-9]*$ - -# Regular expression matching correct module names -module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$ - -# Regular expression matching correct method names -method-rgx=(?x)^(?:(?P_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P_{0,2}[a-z][a-z0-9_]*))$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=12 - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=88 - -# TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt -# lines made too long by directives to pytype. - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=(?x)( - ^\s*(\#\ )??$| - ^\s*(from\s+\S+\s+)?import\s+.+$) - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=yes - -# Maximum number of lines in a module -max-module-lines=99999 - -# String used as indentation unit. The internal Google style guide mandates 2 -# spaces. Google's externaly-published style guide says 4, consistent with -# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google -# projects (like TensorFlow). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=TODO - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=yes - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_) - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging,absl.logging,tensorflow.io.logging - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub, - TERMIOS, - Bastion, - rexec, - sets - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant, absl - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls, - class_ - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs diff --git a/README.md b/README.md index 1328bc6..71036c8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,42 @@ -# Staining +# Stain Normalization +export MLFLOW_TRACKING_USERNAME= -[[`Documentation`](https://rationai.gitlab-pages.ics.muni.cz/digital-pathology/libraries/staining)] \ No newline at end of file + + +[![PyTorch Lightning](https://img.shields.io/badge/pytorch-lightning-blue.svg?logo=PyTorch%20Lightning)](https://github.com/Lightning-AI/lightning) +[![License](https://img.shields.io/badge/License-MIT-red.svg)](https://gitlab.ics.muni.cz/rationai/digital-pathology/pathology/patch-camelyon/-/blob/master/LICENSE) + + +The main goal ... + + +## Getting Started + +### Installation + +Install [PDM](https://pdm.fming.dev/) package manager and install all the dependencies using the following command: +```bash +pdm install +``` + +### Preprocessing + +```bash +export MLFLOW_TRACKING_USERNAME= +pdm run preprocessing/generate_tissue_mask.py +pdm run preprocessing/tiling.py +``` + +### Training + +```bash +export MLFLOW_TRACKING_USERNAME= +pdm fit model/backbone=(vgg16|resnet18) +``` + +### Testing + +```bash +export MLFLOW_TRACKING_USERNAME= +pdm test model/backbone=(vgg16|resnet18) 'checkpoint=""' +``` diff --git a/configs/data/datasets/stain_normalization/predict.yaml b/configs/data/datasets/stain_normalization/predict.yaml new file mode 100644 index 0000000..7832a66 --- /dev/null +++ b/configs/data/datasets/stain_normalization/predict.yaml @@ -0,0 +1,6 @@ +defaults: + - /data/transforms@transforms: test + - /data/modify@modify: test + +_target_: stain_normalization.data.datasets.StainNormalizationPredict +uris: ["mlflow-artifacts:"] diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml new file mode 100644 index 0000000..311cda0 --- /dev/null +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -0,0 +1,6 @@ +defaults: + - /data/transforms@transforms: test + - /data/modify@modify: test + +_target_: stain_normalization.data.datasets.StainNormalization +uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test/tiles.parquet"] diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml new file mode 100644 index 0000000..3d99dad --- /dev/null +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -0,0 +1,6 @@ +defaults: + - /data/transforms@transforms: train + - /data/modify@modify: train + +_target_: stain_normalization.data.datasets.StainNormalization +uris: ["mlflow-artifacts:"] diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml new file mode 100644 index 0000000..53e608c --- /dev/null +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -0,0 +1,7 @@ +defaults: + - /data/transforms@transforms: test + - /data/modify@modify: test + +_target_: stain_normalization.data.datasets.StainNormalization +uris: ["mlflow-artifacts:"] + diff --git a/configs/data/modify/test.yaml b/configs/data/modify/test.yaml new file mode 100644 index 0000000..c8d3ae7 --- /dev/null +++ b/configs/data/modify/test.yaml @@ -0,0 +1,12 @@ +_target_: albumentations.OneOf +transforms: + - _target_: stain_normalization.data.transformation.HED + h_range: [0.8, 1.2] + e_range: [0.8, 1.2] + - _target_: stain_normalization.data.transformation.ExposureAdjustment + brightness_range: [0.8, 1.2] + - _target_: UnnaturalColorModification + hue_shift_range: [0.2, 1.0] + - _target_: CombinedModifications + brightness_range: [-0.4, 0.4] + intensity_range: [0.65, 1.35] \ No newline at end of file diff --git a/configs/data/modify/train.yaml b/configs/data/modify/train.yaml new file mode 100644 index 0000000..c8d3ae7 --- /dev/null +++ b/configs/data/modify/train.yaml @@ -0,0 +1,12 @@ +_target_: albumentations.OneOf +transforms: + - _target_: stain_normalization.data.transformation.HED + h_range: [0.8, 1.2] + e_range: [0.8, 1.2] + - _target_: stain_normalization.data.transformation.ExposureAdjustment + brightness_range: [0.8, 1.2] + - _target_: UnnaturalColorModification + hue_shift_range: [0.2, 1.0] + - _target_: CombinedModifications + brightness_range: [-0.4, 0.4] + intensity_range: [0.65, 1.35] \ No newline at end of file diff --git a/configs/data/transforms/test.yaml b/configs/data/transforms/test.yaml new file mode 100644 index 0000000..7c0a147 --- /dev/null +++ b/configs/data/transforms/test.yaml @@ -0,0 +1,4 @@ +_target_: albumentations.Normalize +mean: [198.9923, 156.7051, 185.0198] +std: [36.8293, 46.7353, 35.8960] +max_pixel_value: 1 diff --git a/configs/data/transforms/train.yaml b/configs/data/transforms/train.yaml new file mode 100644 index 0000000..81162f1 --- /dev/null +++ b/configs/data/transforms/train.yaml @@ -0,0 +1,16 @@ +_target_: albumentations.Compose +transforms: + - _target_: albumentations.RandomRotate90 + p: 1.0 + - _target_: albumentations.Flip + p: 0.75 + - _target_: albumentations.RandomGamma + p: 0.5 + - _target_: albumentations.RandomBrightnessContrast + p: 0.5 + - _target_: albumentations.HueSaturationValue + p: 0.5 + - _target_: albumentations.Normalize + mean: [198.9923, 156.7051, 185.0198] + std: [36.8293, 46.7353, 35.8960] + max_pixel_value: 1 diff --git a/configs/default.yaml b/configs/default.yaml new file mode 100644 index 0000000..79092e5 --- /dev/null +++ b/configs/default.yaml @@ -0,0 +1,42 @@ +defaults: + - hydra: default + - logger: mlflow + - /data/datasets@data.train: stain_normalization/train + - /data/datasets@data.val: stain_normalization/val + - /data/datasets@data.test: stain_normalization/test + - /data/datasets@data.predict: stain_normalization/predict + - /model/backbone: resnet50 + - /model/decode_head: unet2048 + - _self_ + +seed: ${random_seed:} +mode: ??? +checkpoint: null + +trainer: + enable_checkpointing: True + max_epochs: 30 + log_every_n_steps: 5 + callbacks: + - _target_: lightning.pytorch.callbacks.ModelCheckpoint + save_top_k: 1 + monitor: validation/loss + mode: min + +data: + batch_size: 256 + num_workers: 8 + +metadata: + user: xlopatka + experiment_name: Stain Normalization + run_name: Test Stain Normalization + description: Testing Stain Normalization + hyperparams: {} + + + + + + + diff --git a/rationai/staining/py.typed b/configs/experiment/.gitkeep similarity index 100% rename from rationai/staining/py.typed rename to configs/experiment/.gitkeep diff --git a/configs/hydra/default.yaml b/configs/hydra/default.yaml new file mode 100644 index 0000000..275e331 --- /dev/null +++ b/configs/hydra/default.yaml @@ -0,0 +1,7 @@ +defaults: + - _self_ + - override hydra_logging: disabled + - override job_logging: disabled +output_subdir: null +run: + dir: . diff --git a/configs/logger/mlflow.yaml b/configs/logger/mlflow.yaml new file mode 100644 index 0000000..10355c7 --- /dev/null +++ b/configs/logger/mlflow.yaml @@ -0,0 +1,6 @@ +_target_: rationai.mlkit.lightning.loggers.MLFlowLogger +experiment_name: ${metadata.experiment_name} +run_name: ${metadata.run_name} +tags: + mlflow.user: ${metadata.user} + mlflow.note.content: ${metadata.description} diff --git a/configs/model/backbone/resnet50.yaml b/configs/model/backbone/resnet50.yaml new file mode 100644 index 0000000..4b6b5f2 --- /dev/null +++ b/configs/model/backbone/resnet50.yaml @@ -0,0 +1,2 @@ +_target_: stain_normalization.modeling.backbone.resnet50 +weights: null diff --git a/configs/model/backbone/vgg16.yaml b/configs/model/backbone/vgg16.yaml new file mode 100644 index 0000000..4e72da5 --- /dev/null +++ b/configs/model/backbone/vgg16.yaml @@ -0,0 +1,2 @@ +_target_: stain_normalization.modeling.backbone.vgg16 +weights: null diff --git a/configs/model/decode_head/unet2048.yaml b/configs/model/decode_head/unet2048.yaml new file mode 100644 index 0000000..1936549 --- /dev/null +++ b/configs/model/decode_head/unet2048.yaml @@ -0,0 +1,5 @@ +decode_head: + _target_: stain_normalization.modeling.decode_head.UNetDecoder + in_channels: 2048 + weights: null + diff --git a/configs/model/decode_head/unet512.yaml b/configs/model/decode_head/unet512.yaml new file mode 100644 index 0000000..d3461f1 --- /dev/null +++ b/configs/model/decode_head/unet512.yaml @@ -0,0 +1,5 @@ +decode_head: + _target_: stain_normalization.modeling.decode_head.UNetDecoder + in_channels: 512 + weights: null + diff --git a/docs/api/color-conversion.md b/docs/api/color-conversion.md deleted file mode 100644 index 43b6952..0000000 --- a/docs/api/color-conversion.md +++ /dev/null @@ -1 +0,0 @@ -::: rationai.staining.convert_color \ No newline at end of file diff --git a/docs/api/constants.md b/docs/api/constants.md deleted file mode 100644 index 616707f..0000000 --- a/docs/api/constants.md +++ /dev/null @@ -1 +0,0 @@ -::: rationai.staining.constants diff --git a/docs/api/estimate-stain-vectors.md b/docs/api/estimate-stain-vectors.md deleted file mode 100644 index 520ea02..0000000 --- a/docs/api/estimate-stain-vectors.md +++ /dev/null @@ -1 +0,0 @@ -::: rationai.staining.estimate_stain_vectors \ No newline at end of file diff --git a/docs/api/modify-and-reconstruct.md b/docs/api/modify-and-reconstruct.md deleted file mode 100644 index ef9f38d..0000000 --- a/docs/api/modify-and-reconstruct.md +++ /dev/null @@ -1 +0,0 @@ -::: rationai.staining.modify_and_reconstruct \ No newline at end of file diff --git a/docs/api/typing.md b/docs/api/typing.md deleted file mode 100644 index 36b0bbe..0000000 --- a/docs/api/typing.md +++ /dev/null @@ -1 +0,0 @@ -::: rationai.staining.typing \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 325f7c4..0000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,15 +0,0 @@ -# Getting Started - -## Installation - -=== "pdm" - - ```bash - pdm add git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git - ``` - -=== "pip" - - ```bash - pip install git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git - ``` diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 00dd3b4..0000000 --- a/docs/index.md +++ /dev/null @@ -1 +0,0 @@ -Staining library \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index d3e70d5..0000000 --- a/mkdocs.yml +++ /dev/null @@ -1,76 +0,0 @@ -site_name: Staining - -nav: - - Introduction: index.md - - Getting Started: getting-started.md - - API Reference: - - api/color-conversion.md - - estimate_stain_vectors: api/estimate-stain-vectors.md - - modify_and_reconstruct: api/modify-and-reconstruct.md - - api/constants.md - - api/typing.md - -theme: - name: material - features: - - announce.dismiss - - content.action.edit - - content.action.view - - content.code.annotate - - content.code.copy - - content.code.select - - content.tooltips - - navigation.indexes - - navigation.sections - - navigation.top - - navigation.footer - - navigation.tracking - - search.highlight - - search.share - - search.suggest - - toc.follow - palette: - - media: "(prefers-color-scheme)" - toggle: - icon: material/link - name: Switch to light mode - - media: "(prefers-color-scheme: light)" - scheme: default - primary: indigo - accent: indigo - toggle: - icon: material/toggle-switch - name: Switch to dark mode - - media: "(prefers-color-scheme: dark)" - scheme: slate - primary: black - accent: indigo - toggle: - icon: material/toggle-switch-off - name: Switch to system preference - -plugins: - - search - - mkdocstrings: - handlers: - python: - options: - show_if_no_docstring: true - -markdown_extensions: - - pymdownx.superfences: - custom_fences: - - name: mermaid - class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format - - pymdownx.tabbed: - alternate_style: true - combine_header_slug: true - slugify: !!python/object/apply:pymdownx.slugs.slugify - kwds: - case: lower - - admonition - - pymdownx.details - - pymdownx.superfences - - pymdownx.highlight - - pymdownx.inlinehilite diff --git a/nohup.out b/nohup.out new file mode 100644 index 0000000..1485bf9 --- /dev/null +++ b/nohup.out @@ -0,0 +1,2772 @@ + + 0%| | 0/235 [00:00 + main() + File "/home/jovyan/machine-learning/preprocessing/mask_generator.py", line 63, in main + process_items(slides, process_item=process_slide) + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/rationai/masks/processing.py", line 56, in process_items + ready, pending = ray.wait(pending) + ^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/auto_init_hook.py", line 21, in auto_init_wrapper + return fn(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/client_mode_hook.py", line 103, in wrapper + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/worker.py", line 2976, in wait + ready_ids, remaining_ids = worker.core_worker.wait( + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "python/ray/_raylet.pyx", line 3816, in ray._raylet.CoreWorker.wait + File "python/ray/includes/common.pxi", line 79, in ray._raylet.check_status +KeyboardInterrupt +Exception ignored in atexit callback: +Traceback (most recent call last): + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/client_mode_hook.py", line 103, in wrapper + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/worker.py", line 1905, in shutdown + _global_node.kill_all_processes(check_alive=False, allow_graceful=True) + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/node.py", line 1637, in kill_all_processes + self._kill_process_type( + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/node.py", line 1458, in _kill_process_type + self._kill_process_impl( + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/node.py", line 1514, in _kill_process_impl + process.wait(timeout_seconds) + File "/usr/lib/python3.11/subprocess.py", line 1277, in wait + self._wait(timeout=sigint_timeout) + File "/usr/lib/python3.11/subprocess.py", line 2025, in _wait + if self._waitpid_lock.acquire(False): + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +KeyboardInterrupt: + File "/home/jovyan/machine-learning/preprocessing/mask_generator.py", line 46 + folders = [ + ^ +SyntaxError: '[' was never closed + + 0%| | 0/87 [00:00 + main() + File "/home/jovyan/machine-learning/preprocessing/tiler.py", line 88, in main + train_slides_df, train_tiles_df = tiling( + ^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/rationai/tiling/tiling.py", line 107, in tiling + ready, pending = ray.wait(pending) + ^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/auto_init_hook.py", line 21, in auto_init_wrapper + return fn(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/client_mode_hook.py", line 103, in wrapper + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/ray/_private/worker.py", line 2976, in wait +object address : 0x70c88736d240 +object refcount : 4 +object type : 0x9d49e0 +object type name: KeyboardInterrupt +object repr : KeyboardInterrupt() +lost sys.stderr +Exception ignored in atexit callback: +Exception ignored in sys.unraisablehook: +KeyboardInterrupt + + 0%| | 0/655 [00:00`_ for more details. + warnings.warn( +/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/mlflow/types/utils.py:407: UserWarning: Hint: Inferred schema contains integer column(s). Integer columns in Python cannot represent missing values. If your input data contains missing values at inference time, it will be encoded as floats and will cause a schema enforcement error. The best way to avoid this problem is to infer the model schema based on a realistic data sample (training dataset) that includes missing values. Alternatively, you can declare integer columns as doubles (float64) whenever these columns may have missing values. See `Handling Integers With Missing Values `_ for more details. + warnings.warn( +/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/mlflow/types/utils.py:407: UserWarning: Hint: Inferred schema contains integer column(s). Integer columns in Python cannot represent missing values. If your input data contains missing values at inference time, it will be encoded as floats and will cause a schema enforcement error. The best way to avoid this problem is to infer the model schema based on a realistic data sample (training dataset) that includes missing values. Alternatively, you can declare integer columns as doubles (float64) whenever these columns may have missing values. See `Handling Integers With Missing Values `_ for more details. + warnings.warn( + 0%| | 0/73 [00:00`_ for more details. + warnings.warn( +/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/mlflow/types/utils.py:407: UserWarning: Hint: Inferred schema contains integer column(s). Integer columns in Python cannot represent missing values. If your input data contains missing values at inference time, it will be encoded as floats and will cause a schema enforcement error. The best way to avoid this problem is to infer the model schema based on a realistic data sample (training dataset) that includes missing values. Alternatively, you can declare integer columns as doubles (float64) whenever these columns may have missing values. See `Handling Integers With Missing Values `_ for more details. + warnings.warn( +/home/jovyan/machine-learning/.venv/lib/python3.11/site-packages/mlflow/types/utils.py:407: UserWarning: Hint: Inferred schema contains integer column(s). Integer columns in Python cannot represent missing values. If your input data contains missing values at inference time, it will be encoded as floats and will cause a schema enforcement error. The best way to avoid this problem is to infer the model schema based on a realistic data sample (training dataset) that includes missing values. Alternatively, you can declare integer columns as doubles (float64) whenever these columns may have missing values. See `Handling Integers With Missing Values `_ for more details. + warnings.warn( diff --git a/pdm.lock b/pdm.lock index 6420616..395416d 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,37 +2,208 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "dev", "docs", "test"] -strategy = ["inherit_metadata"] -lock_version = "4.5.0" -content_hash = "sha256:3f01d03ad0d47f602c987ef86d96b65b42cd6b8199430d0f41138b17f05995fc" +groups = ["default", "dev"] +strategy = [] +lock_version = "4.4" +content_hash = "sha256:24e67ec88809826b854439f3edd657a4285070b448d3ae0add27a80782d3b633" -[[metadata.targets]] -requires_python = ">=3.11" +[[package]] +name = "aiohappyeyeballs" +version = "2.3.6" +requires_python = ">=3.8" +summary = "Happy Eyeballs for asyncio" +files = [ + {file = "aiohappyeyeballs-2.3.6-py3-none-any.whl", hash = "sha256:15dca2611fa78442f1cb54cf07ffb998573f2b4fbeab45ca8554c045665c896b"}, + {file = "aiohappyeyeballs-2.3.6.tar.gz", hash = "sha256:88211068d2a40e0436033956d7de3926ff36d54776f8b1022d6b21320cadae79"}, +] [[package]] -name = "babel" -version = "2.16.0" +name = "aiohttp" +version = "3.10.3" +requires_python = ">=3.8" +summary = "Async http client/server framework (asyncio)" +dependencies = [ + "aiohappyeyeballs>=2.3.0", + "aiosignal>=1.1.2", + "attrs>=17.3.0", + "frozenlist>=1.1.1", + "multidict<7.0,>=4.5", + "yarl<2.0,>=1.0", +] +files = [ + {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b"}, + {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2"}, + {file = "aiohttp-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e"}, + {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec"}, + {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9"}, + {file = "aiohttp-3.10.3-cp311-cp311-win32.whl", hash = "sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b"}, + {file = "aiohttp-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806"}, + {file = "aiohttp-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c"}, + {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68"}, + {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3"}, + {file = "aiohttp-3.10.3-cp312-cp312-win32.whl", hash = "sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a"}, + {file = "aiohttp-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf"}, + {file = "aiohttp-3.10.3.tar.gz", hash = "sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696"}, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +requires_python = ">=3.7" +summary = "aiosignal: a list of registered asynchronous callbacks" +dependencies = [ + "frozenlist>=1.1.0", +] +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[[package]] +name = "albucore" +version = "0.0.23" +requires_python = ">=3.9" +summary = "High-performance image processing functions for deep learning and computer vision." +dependencies = [ + "numpy>=1.24.4", + "opencv-python-headless>=4.9.0.80", + "simsimd>=5.9.2", + "stringzilla>=3.10.4", +] +files = [ + {file = "albucore-0.0.23-py3-none-any.whl", hash = "sha256:99274ac0c15a1a7d9a726df9d54d5ab70d9d0c189e2a935399dba3d4bafad415"}, + {file = "albucore-0.0.23.tar.gz", hash = "sha256:57823982b954913b84a9e2cf71058c4577b02397a62c41885be2d9b295efa8ab"}, +] + +[[package]] +name = "albumentations" +version = "2.0.4" +requires_python = ">=3.9" +summary = "Fast, flexible, and advanced augmentation library for deep learning, computer vision, and medical imaging. Albumentations offers a wide range of transformations for both 2D (images, masks, bboxes, keypoints) and 3D (volumes, volumetric masks) data, with optimized performance and seamless integration into ML workflows." +dependencies = [ + "PyYAML", + "albucore==0.0.23", + "numpy>=1.24.4", + "opencv-python-headless>=4.9.0.80", + "pydantic>=2.9.2", + "scipy>=1.10.0", +] +files = [ + {file = "albumentations-2.0.4-py3-none-any.whl", hash = "sha256:1d60b62527d34bb8791fad90f6faeeb065ecc5cb4577ff85614f022d56183010"}, + {file = "albumentations-2.0.4.tar.gz", hash = "sha256:4f0cd22576fba8030fc99f1ccacee1452a1880ac2a9ce0882f0d93e5477d5c70"}, +] + +[[package]] +name = "alembic" +version = "1.13.2" requires_python = ">=3.8" -summary = "Internationalization utilities" -groups = ["docs"] +summary = "A database migration tool for SQLAlchemy." dependencies = [ - "pytz>=2015.7; python_version < \"3.9\"", + "Mako", + "SQLAlchemy>=1.3.0", + "typing-extensions>=4", ] files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, +] + +[[package]] +name = "aniso8601" +version = "9.0.1" +summary = "A library for parsing ISO 8601 strings." +files = [ + {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"}, + {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"}, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +requires_python = ">=3.8" +summary = "Reusable constraint types to use with typing.Annotated" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +summary = "ANTLR 4.9.3 runtime for Python 3.7" +files = [ + {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, +] + +[[package]] +name = "attrs" +version = "24.2.0" +requires_python = ">=3.7" +summary = "Classes Without Boilerplate" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[[package]] +name = "blinker" +version = "1.8.2" +requires_python = ">=3.8" +summary = "Fast, simple object-to-object and broadcast signaling" +files = [ + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, +] + +[[package]] +name = "cachetools" +version = "5.5.0" +requires_python = ">=3.7" +summary = "Extensible memoizing collections and decorators" +files = [ + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, ] [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." -groups = ["docs"] files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +requires_python = ">=3.8" +summary = "Foreign Function Interface for Python calling C code." +dependencies = [ + "pycparser", +] +files = [ + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [[package]] @@ -40,7 +211,6 @@ name = "cfgv" version = "3.4.0" requires_python = ">=3.8" summary = "Validate configuration and produce human readable error messages." -groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -51,7 +221,6 @@ name = "charset-normalizer" version = "3.3.2" requires_python = ">=3.7.0" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -groups = ["docs"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, @@ -92,179 +261,388 @@ name = "click" version = "8.1.7" requires_python = ">=3.7" summary = "Composable command line interface toolkit" -groups = ["docs"] -dependencies = [ - "colorama; platform_system == \"Windows\"", - "importlib-metadata; python_version < \"3.8\"", -] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [[package]] -name = "colorama" -version = "0.4.6" -requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -summary = "Cross-platform colored terminal text." -groups = ["docs", "test"] +name = "cloudpickle" +version = "3.0.0" +requires_python = ">=3.8" +summary = "Pickler class to extend the standard pickle.Pickler functionality" files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, + {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"}, + {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"}, ] [[package]] -name = "coverage" -version = "7.6.1" -requires_python = ">=3.8" -summary = "Code coverage measurement for Python" -groups = ["test"] -files = [ - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, -] - -[[package]] -name = "coverage" -version = "7.6.1" -extras = ["toml"] +name = "contourpy" +version = "1.3.0" +requires_python = ">=3.9" +summary = "Python library for calculating contours of 2D quadrilateral grids" +dependencies = [ + "numpy>=1.23", +] +files = [ + {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, + {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, + {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, + {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, + {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, + {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, + {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, + {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, +] + +[[package]] +name = "cycler" +version = "0.12.1" requires_python = ">=3.8" -summary = "Code coverage measurement for Python" -groups = ["test"] -dependencies = [ - "coverage==7.6.1", - "tomli; python_full_version <= \"3.11.0a6\"", -] -files = [ - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +summary = "Composable style cycles" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[[package]] +name = "databricks-sdk" +version = "0.31.1" +requires_python = ">=3.7" +summary = "Databricks SDK for Python (Beta)" +dependencies = [ + "google-auth~=2.0", + "requests<3,>=2.28.1", +] +files = [ + {file = "databricks_sdk-0.31.1-py3-none-any.whl", hash = "sha256:9ab286f87ae1cc98a00ef7d207e40661f4d14a464071425ad169d235919b35f6"}, + {file = "databricks_sdk-0.31.1.tar.gz", hash = "sha256:8609e655d0e5ecb15c2a8a6468e737f8dcb4f28c33239388de3ab386b921d790"}, +] + +[[package]] +name = "deprecated" +version = "1.2.14" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "Python @deprecated decorator to deprecate old python classes, functions or methods." +dependencies = [ + "wrapt<2,>=1.10", +] +files = [ + {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, + {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, ] [[package]] name = "distlib" version = "0.3.8" summary = "Distribution utilities" -groups = ["dev"] files = [ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] +[[package]] +name = "docker" +version = "7.1.0" +requires_python = ">=3.8" +summary = "A Python library for the Docker Engine API." +dependencies = [ + "requests>=2.26.0", + "urllib3>=1.26.0", +] +files = [ + {file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"}, + {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, +] + +[[package]] +name = "durationpy" +version = "0.9" +summary = "Module for converting between datetime.timedelta and Go's Duration strings." +files = [ + {file = "durationpy-0.9-py3-none-any.whl", hash = "sha256:e65359a7af5cedad07fb77a2dd3f390f8eb0b74cb845589fa6c057086834dd38"}, + {file = "durationpy-0.9.tar.gz", hash = "sha256:fd3feb0a69a0057d582ef643c355c40d2fa1c942191f914d12203b1a01ac722a"}, +] + [[package]] name = "filelock" version = "3.15.4" requires_python = ">=3.8" summary = "A platform independent file lock." -groups = ["dev"] files = [ {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [[package]] -name = "ghp-import" -version = "2.1.0" -summary = "Copy your docs directly to the gh-pages branch." -groups = ["docs"] +name = "flask" +version = "3.0.3" +requires_python = ">=3.8" +summary = "A simple framework for building complex web applications." dependencies = [ - "python-dateutil>=2.8.1", + "Jinja2>=3.1.2", + "Werkzeug>=3.0.0", + "blinker>=1.6.2", + "click>=8.1.3", + "itsdangerous>=2.1.2", +] +files = [ + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, +] + +[[package]] +name = "fonttools" +version = "4.53.1" +requires_python = ">=3.8" +summary = "Tools to manipulate font files" +files = [ + {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, + {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, + {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, + {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, + {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, + {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, + {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, +] + +[[package]] +name = "frozenlist" +version = "1.4.1" +requires_python = ">=3.8" +summary = "A list-like structure which implements collections.abc.MutableSequence" +files = [ + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] + +[[package]] +name = "fsspec" +version = "2024.6.1" +requires_python = ">=3.8" +summary = "File-system specification" files = [ - {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, - {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, + {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, + {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, ] [[package]] -name = "griffe" -version = "1.2.0" +name = "fsspec" +version = "2024.6.1" +extras = ["http"] requires_python = ">=3.8" -summary = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -groups = ["docs"] +summary = "File-system specification" dependencies = [ - "astunparse>=1.6; python_version < \"3.9\"", - "colorama>=0.4", + "aiohttp!=4.0.0a0,!=4.0.0a1", + "fsspec==2024.6.1", ] files = [ - {file = "griffe-1.2.0-py3-none-any.whl", hash = "sha256:a8b2fcb1ecdc5a412e646b0b4375eb20a5d2eac3a11dd8c10c56967a4097663c"}, - {file = "griffe-1.2.0.tar.gz", hash = "sha256:1c9f6ef7455930f3f9b0c4145a961c90385d1e2cbc496f7796fbff560ec60d31"}, + {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, + {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, +] + +[[package]] +name = "gitdb" +version = "4.0.11" +requires_python = ">=3.7" +summary = "Git Object Database" +dependencies = [ + "smmap<6,>=3.0.1", +] +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[[package]] +name = "gitpython" +version = "3.1.43" +requires_python = ">=3.7" +summary = "GitPython is a Python library used to interact with Git repositories" +dependencies = [ + "gitdb<5,>=4.0.1", +] +files = [ + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, +] + +[[package]] +name = "google-auth" +version = "2.34.0" +requires_python = ">=3.7" +summary = "Google Authentication Library" +dependencies = [ + "cachetools<6.0,>=2.0.0", + "pyasn1-modules>=0.2.1", + "rsa<5,>=3.1.4", +] +files = [ + {file = "google_auth-2.34.0-py2.py3-none-any.whl", hash = "sha256:72fd4733b80b6d777dcde515628a9eb4a577339437012874ea286bca7261ee65"}, + {file = "google_auth-2.34.0.tar.gz", hash = "sha256:8eb87396435c19b20d32abd2f984e31c191a15284af72eb922f10e5bde9c04cc"}, +] + +[[package]] +name = "graphene" +version = "3.3" +summary = "GraphQL Framework for Python" +dependencies = [ + "aniso8601<10,>=8", + "graphql-core<3.3,>=3.1", + "graphql-relay<3.3,>=3.1", +] +files = [ + {file = "graphene-3.3-py2.py3-none-any.whl", hash = "sha256:bb3810be33b54cb3e6969506671eb72319e8d7ba0d5ca9c8066472f75bf35a38"}, + {file = "graphene-3.3.tar.gz", hash = "sha256:529bf40c2a698954217d3713c6041d69d3f719ad0080857d7ee31327112446b0"}, +] + +[[package]] +name = "graphql-core" +version = "3.2.3" +requires_python = ">=3.6,<4" +summary = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +files = [ + {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, + {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, +] + +[[package]] +name = "graphql-relay" +version = "3.2.0" +requires_python = ">=3.6,<4" +summary = "Relay library for graphql-core" +dependencies = [ + "graphql-core<3.3,>=3.2", +] +files = [ + {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"}, + {file = "graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"}, +] + +[[package]] +name = "greenlet" +version = "3.0.3" +requires_python = ">=3.7" +summary = "Lightweight in-process concurrent programming" +files = [ + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[[package]] +name = "gunicorn" +version = "23.0.0" +requires_python = ">=3.7" +summary = "WSGI HTTP Server for UNIX" +dependencies = [ + "packaging", +] +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[[package]] +name = "hydra-core" +version = "1.3.2" +summary = "A framework for elegantly configuring complex applications" +dependencies = [ + "antlr4-python3-runtime==4.9.*", + "omegaconf<2.4,>=2.2", + "packaging", +] +files = [ + {file = "hydra-core-1.3.2.tar.gz", hash = "sha256:8a878ed67216997c3e9d88a8e72e7b4767e81af37afb4ea3334b269a4390a824"}, + {file = "hydra_core-1.3.2-py3-none-any.whl", hash = "sha256:fa0238a9e31df3373b35b0bfb672c34cc92718d21f81311d8996a16de1141d8b"}, ] [[package]] @@ -272,7 +650,6 @@ name = "identify" version = "2.6.0" requires_python = ">=3.8" summary = "File identification library for Python" -groups = ["dev"] files = [ {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, @@ -280,39 +657,35 @@ files = [ [[package]] name = "idna" -version = "3.8" -requires_python = ">=3.6" +version = "3.7" +requires_python = ">=3.5" summary = "Internationalized Domain Names in Applications (IDNA)" -groups = ["docs"] files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] -name = "imageio" -version = "2.35.1" +name = "importlib-metadata" +version = "8.4.0" requires_python = ">=3.8" -summary = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." -groups = ["default"] +summary = "Read metadata from Python packages" dependencies = [ - "numpy", - "pillow>=8.3.2", + "zipp>=0.5", ] files = [ - {file = "imageio-2.35.1-py3-none-any.whl", hash = "sha256:6eb2e5244e7a16b85c10b5c2fe0f7bf961b40fcb9f1a9fd1bd1d2c2f8fb3cd65"}, - {file = "imageio-2.35.1.tar.gz", hash = "sha256:4952dfeef3c3947957f6d5dedb1f4ca31c6e509a476891062396834048aeed2a"}, + {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, + {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, ] [[package]] -name = "iniconfig" -version = "2.0.0" -requires_python = ">=3.7" -summary = "brain-dead simple config-ini parsing" -groups = ["test"] +name = "itsdangerous" +version = "2.2.0" +requires_python = ">=3.8" +summary = "Safely pass data to untrusted environments and back." files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] @@ -320,7 +693,6 @@ name = "jinja2" version = "3.1.4" requires_python = ">=3.7" summary = "A very fast and expressive template engine." -groups = ["docs"] dependencies = [ "MarkupSafe>=2.0", ] @@ -330,18 +702,156 @@ files = [ ] [[package]] -name = "lazy-loader" -version = "0.4" -requires_python = ">=3.7" -summary = "Makes it easy to load subpackages and functions on demand." -groups = ["default"] +name = "joblib" +version = "1.4.2" +requires_python = ">=3.8" +summary = "Lightweight pipelining with Python functions" +files = [ + {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, + {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, +] + +[[package]] +name = "jsonschema" +version = "4.23.0" +requires_python = ">=3.8" +summary = "An implementation of JSON Schema validation for Python" dependencies = [ - "importlib-metadata; python_version < \"3.8\"", - "packaging", + "attrs>=22.2.0", + "jsonschema-specifications>=2023.03.6", + "referencing>=0.28.4", + "rpds-py>=0.7.1", +] +files = [ + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, +] + +[[package]] +name = "jsonschema-specifications" +version = "2024.10.1" +requires_python = ">=3.9" +summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +dependencies = [ + "referencing>=0.31.0", ] files = [ - {file = "lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"}, - {file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"}, + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.6" +requires_python = ">=3.8" +summary = "A fast implementation of the Cassowary constraint solver" +files = [ + {file = "kiwisolver-1.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45a5cb5abad1ad9c265eed7e058fefafeb7964565b93b397ba2f480faec8d674"}, + {file = "kiwisolver-1.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e52b2568c47fb4f54d17576954e02b1de156c85152f87283a99db9670fd18c0"}, + {file = "kiwisolver-1.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:00af95204100bc1d0f26e1ed52ec77d6e3da5c9b845c88d31875c164e4ba6c0c"}, + {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ab1fedf86f3951a9e90a64edd15f598860ed60cd3664259756f097d527b5ae"}, + {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc985766bf20141ce64baecc39fb9fedbce094b2b8de1bb62676b79328988e4"}, + {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1942a155c737a7c3835a957897f0cc9ebc0085b7a75d934d86aecb1b27b8873"}, + {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f464403e391724f8e7dff188d3fb77a85bd1273b3fdba182e6671abcc44434f8"}, + {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce5efe545eea86f52ec5a1185e5052815ea86778e8268bad71fa46433f7c0bef"}, + {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cb30165f71b7b3378668346e220c81d590593a3a1ff76428a53780310df03f35"}, + {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5a987f740e1c9964e614acb87ba1f014b4be760a341effc8dc789913d1840e6"}, + {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f2ceaa6d0450623d108956647ef19a1a28c7e07880f1171c932477308d44d80b"}, + {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:788cbf99738f18ae8a27b9d4d7314502b4b917005cfdacd1d6a59038332ae24d"}, + {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2f6668678a6b9488a7f8a6320e1b1c6396d179a976472dbc08d1600d04119511"}, + {file = "kiwisolver-1.4.6-cp311-cp311-win32.whl", hash = "sha256:10a09a3e4213c2806bcfd2eb4edb756c557973d2cacf06873b18a247fce897da"}, + {file = "kiwisolver-1.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:683ffef2c51fdc54112dc610d06b59b88c21e23fb669b905da6d5bec80da1bde"}, + {file = "kiwisolver-1.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:3b852c7f0ed9a2fd339c228829bca0964233ed45de50aae3e87b72ca37d177f8"}, + {file = "kiwisolver-1.4.6-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:979df7e9334f6a3694ee9be8d42817e519ef6d155a16499714d082cf41296852"}, + {file = "kiwisolver-1.4.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50c9c6c42bb6ca231626d1182b9128e89c5ce3c64456f811ff0280deb42d7bfe"}, + {file = "kiwisolver-1.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ace86489e7951bd26329a589198d3875c3d48380f889c69d3eb254b506a80101"}, + {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f94771988da902b475f78e85cf63c5c94392773b4a6494234d87c1b363b2fbc5"}, + {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62379eee430b1c477bb0a0bf6858a57c7c0dad9cee8b3144a5cb5d366c66a54"}, + {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e99b97d69499a7414572c906fbc7ca312519f2e17999730129f6c4492786e953"}, + {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab93f58afe3a02922a343189404f24ed885564e6316649790240124b95ef1d6e"}, + {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34105f4460ba50fc18a16a8e77a5122f7affe075628763fda748ad0ec534c3ee"}, + {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0081f85f0222620563409d4804c6567a930a45dafbe9674c7913fde131653992"}, + {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:df2a4a7cc2e01991e039a792457751b601bdf30143ab5f23f9a1e58f20c875f4"}, + {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1f401784df70ea2870e4e10adade66b5b06cb2c151bc2a8a414a1d10554e9a81"}, + {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:b19761c8c613b6d04c44f1a4797a144b44136f17ec009ccfb025e17b5698140c"}, + {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee7289430ded484cc2eff9d8ffcce58ed7fe2c26919321dbc0580322a49e0120"}, + {file = "kiwisolver-1.4.6-cp312-cp312-win32.whl", hash = "sha256:331b9d9f408e874ecf34bd79b79df8e099f0b1b351b8844609c1bfdc8d2d45b2"}, + {file = "kiwisolver-1.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:a9be95d086578b3ada61a4621c0e7ee5f456820bfdccc3329061fdeae1e31179"}, + {file = "kiwisolver-1.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:773f2d87825779ab69196dfcf63e9d91043273421c6128c8d4ed82bc6316068f"}, + {file = "kiwisolver-1.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:140f376c22b5148453acff768cff19c34ebbd593126617018732ea1d9ce65547"}, + {file = "kiwisolver-1.4.6.tar.gz", hash = "sha256:3cda29d601445e6aa11f80d90a9b8c2ae501650c55d7ad29829bd44499c9e7e0"}, +] + +[[package]] +name = "kubernetes" +version = "32.0.1" +requires_python = ">=3.6" +summary = "Kubernetes python client" +dependencies = [ + "certifi>=14.05.14", + "durationpy>=0.7", + "google-auth>=1.0.1", + "oauthlib>=3.2.2", + "python-dateutil>=2.5.3", + "pyyaml>=5.4.1", + "requests", + "requests-oauthlib", + "six>=1.9.0", + "urllib3>=1.24.2", + "websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0", +] +files = [ + {file = "kubernetes-32.0.1-py2.py3-none-any.whl", hash = "sha256:35282ab8493b938b08ab5526c7ce66588232df00ef5e1dbe88a419107dc10998"}, + {file = "kubernetes-32.0.1.tar.gz", hash = "sha256:42f43d49abd437ada79a79a16bd48a604d3471a117a8347e87db693f2ba0ba28"}, +] + +[[package]] +name = "lightning" +version = "2.4.0" +requires_python = ">=3.9" +summary = "The Deep Learning framework to train, deploy, and ship AI products Lightning fast." +dependencies = [ + "PyYAML<8.0,>=5.4", + "fsspec[http]<2026.0,>=2022.5.0", + "lightning-utilities<2.0,>=0.10.0", + "packaging<25.0,>=20.0", + "pytorch-lightning", + "torch<4.0,>=2.1.0", + "torchmetrics<3.0,>=0.7.0", + "tqdm<6.0,>=4.57.0", + "typing-extensions<6.0,>=4.4.0", +] +files = [ + {file = "lightning-2.4.0-py3-none-any.whl", hash = "sha256:560163af9711cf59055c448232c473150a299089efce0d2be3cc3288082d8768"}, + {file = "lightning-2.4.0.tar.gz", hash = "sha256:9156604cc56e4b2b603f34fa7f0fe5107375c8e6d85e74544b319a15faa9ed0e"}, +] + +[[package]] +name = "lightning-utilities" +version = "0.11.6" +requires_python = ">=3.8" +summary = "Lightning toolbox for across the our ecosystem." +dependencies = [ + "packaging>=17.1", + "setuptools", + "typing-extensions", +] +files = [ + {file = "lightning_utilities-0.11.6-py3-none-any.whl", hash = "sha256:ecd9953c316cbaf56ad820fbe7bd062187b9973c4a23d47b076cd59dc080a310"}, + {file = "lightning_utilities-0.11.6.tar.gz", hash = "sha256:79fc27ef8ec8b8d55a537920f2c7610270c0c9e037fa6efc78f1aa34ec8cdf04"}, +] + +[[package]] +name = "mako" +version = "1.3.5" +requires_python = ">=3.8" +summary = "A super-fast templating language that borrows the best ideas from the existing templating languages." +dependencies = [ + "MarkupSafe>=0.9.2", +] +files = [ + {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, + {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, ] [[package]] @@ -349,10 +859,6 @@ name = "markdown" version = "3.7" requires_python = ">=3.8" summary = "Python implementation of John Gruber's Markdown." -groups = ["docs"] -dependencies = [ - "importlib-metadata>=4.4; python_version < \"3.10\"", -] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -363,7 +869,6 @@ name = "markupsafe" version = "2.1.5" requires_python = ">=3.7" summary = "Safely add untrusted strings to HTML/XML markup." -groups = ["docs"] files = [ {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, @@ -389,269 +894,464 @@ files = [ ] [[package]] -name = "mergedeep" -version = "1.3.4" -requires_python = ">=3.6" -summary = "A deep merge function for 🐍." -groups = ["docs"] +name = "matplotlib" +version = "3.9.2" +requires_python = ">=3.9" +summary = "Python plotting package" +dependencies = [ + "contourpy>=1.0.1", + "cycler>=0.10", + "fonttools>=4.22.0", + "kiwisolver>=1.3.1", + "numpy>=1.23", + "packaging>=20.0", + "pillow>=8", + "pyparsing>=2.3.1", + "python-dateutil>=2.7", +] files = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, + {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"}, + {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"}, + {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"}, + {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"}, + {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"}, + {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"}, + {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, + {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, + {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, + {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, + {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, + {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"}, + {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"}, + {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"}, + {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"}, + {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"}, + {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"}, + {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"}, + {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"}, + {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"}, + {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"}, + {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"}, + {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, ] [[package]] -name = "mkdocs" -version = "1.6.0" +name = "mlflow" +version = "2.16.0" requires_python = ">=3.8" -summary = "Project documentation with Markdown." -groups = ["docs"] +summary = "MLflow is an open source platform for the complete machine learning lifecycle" dependencies = [ - "click>=7.0", - "colorama>=0.4; platform_system == \"Windows\"", - "ghp-import>=1.0", - "importlib-metadata>=4.4; python_version < \"3.10\"", - "jinja2>=2.11.1", - "markdown>=3.3.6", - "markupsafe>=2.0.1", - "mergedeep>=1.3.4", - "mkdocs-get-deps>=0.2.0", - "packaging>=20.5", - "pathspec>=0.11.1", - "pyyaml-env-tag>=0.1", - "pyyaml>=5.1", - "watchdog>=2.0", + "Flask<4", + "Jinja2<4,>=2.11; platform_system != \"Windows\"", + "alembic!=1.10.0,<2", + "docker<8,>=4.0.0", + "graphene<4", + "gunicorn<24; platform_system != \"Windows\"", + "markdown<4,>=3.3", + "matplotlib<4", + "mlflow-skinny==2.16.0", + "numpy<3", + "pandas<3", + "pyarrow<18,>=4.0.0", + "scikit-learn<2", + "scipy<2", + "sqlalchemy<3,>=1.4.0", ] files = [ - {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, - {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, + {file = "mlflow-2.16.0-py3-none-any.whl", hash = "sha256:9f27ef6ae7a82d7ecd67b6b4a4d50637a5e8160639115570fbc689758f9c0b54"}, + {file = "mlflow-2.16.0.tar.gz", hash = "sha256:82ea1a2e800f404f1586783b7636091c0a5754cf9ff45afeadf3a5e467f5168f"}, ] [[package]] -name = "mkdocs-autorefs" -version = "1.1.0" +name = "mlflow-skinny" +version = "2.16.0" requires_python = ">=3.8" -summary = "Automatically link across pages in MkDocs." -groups = ["docs"] +summary = "MLflow is an open source platform for the complete machine learning lifecycle" dependencies = [ - "Markdown>=3.3", - "markupsafe>=2.0.1", - "mkdocs>=1.1", + "cachetools<6,>=5.0.0", + "click<9,>=7.0", + "cloudpickle<4", + "databricks-sdk<1,>=0.20.0", + "gitpython<4,>=3.1.9", + "importlib-metadata!=4.7.0,<9,>=3.7.0", + "opentelemetry-api<3,>=1.9.0", + "opentelemetry-sdk<3,>=1.9.0", + "packaging<25", + "protobuf<6,>=3.12.0", + "pyyaml<7,>=5.1", + "requests<3,>=2.17.3", + "sqlparse<1,>=0.4.0", ] files = [ - {file = "mkdocs_autorefs-1.1.0-py3-none-any.whl", hash = "sha256:492ac42f50214e81565e968f8cb0df9aba9d981542b9e7121b8f8ae9407fe6eb"}, - {file = "mkdocs_autorefs-1.1.0.tar.gz", hash = "sha256:f2fd43b11f66284bd014f9b542a05c8ecbfaad4e0d7b30b68584788217b6c656"}, + {file = "mlflow_skinny-2.16.0-py3-none-any.whl", hash = "sha256:c55541f50efd0f6637377b10e8a654847a3fcd815b8680a95f02e0ca6bd7700c"}, + {file = "mlflow_skinny-2.16.0.tar.gz", hash = "sha256:9b823173063743783b4e7b6c52bdadcc7d9dab48eb883ac454c0d56609df6b2d"}, ] [[package]] -name = "mkdocs-get-deps" -version = "0.2.0" +name = "mpmath" +version = "1.3.0" +summary = "Python library for arbitrary-precision floating-point arithmetic" +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[[package]] +name = "msgpack" +version = "1.1.0" requires_python = ">=3.8" -summary = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" -groups = ["docs"] -dependencies = [ - "importlib-metadata>=4.3; python_version < \"3.10\"", - "mergedeep>=1.3.4", - "platformdirs>=2.2.0", - "pyyaml>=5.1", +summary = "MessagePack serializer" +files = [ + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, + {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] + +[[package]] +name = "multidict" +version = "6.0.5" +requires_python = ">=3.7" +summary = "multidict implementation" files = [ - {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, - {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] [[package]] -name = "mkdocs-material" -version = "9.5.33" +name = "mypy" +version = "1.11.1" requires_python = ">=3.8" -summary = "Documentation that simply works" -groups = ["docs"] +summary = "Optional static typing for Python" dependencies = [ - "babel~=2.10", - "colorama~=0.4", - "jinja2~=3.0", - "markdown~=3.2", - "mkdocs-material-extensions~=1.3", - "mkdocs~=1.6", - "paginate~=0.5", - "pygments~=2.16", - "pymdown-extensions~=10.2", - "regex>=2022.4", - "requests~=2.26", + "mypy-extensions>=1.0.0", + "typing-extensions>=4.6.0", ] files = [ - {file = "mkdocs_material-9.5.33-py3-none-any.whl", hash = "sha256:dbc79cf0fdc6e2c366aa987de8b0c9d4e2bb9f156e7466786ba2fd0f9bf7ffca"}, - {file = "mkdocs_material-9.5.33.tar.gz", hash = "sha256:d23a8b5e3243c9b2f29cdfe83051104a8024b767312dc8fde05ebe91ad55d89d"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, + {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, + {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, + {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, + {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, + {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, + {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, + {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, + {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, ] [[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -requires_python = ">=3.8" -summary = "Extension pack for Python Markdown and MkDocs Material." -groups = ["docs"] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "networkx" +version = "3.3" +requires_python = ">=3.10" +summary = "Python package for creating and manipulating graphs and networks" +files = [ + {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, + {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Node.js virtual environment builder" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +requires_python = ">=3.9" +summary = "Fundamental package for array computing in Python" +files = [ + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.4.5.8" +requires_python = ">=3" +summary = "CUBLAS native runtime libraries" +files = [ + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.4.127" +requires_python = ">=3" +summary = "CUDA profiling tools runtime libs." +files = [ + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.4.127" +requires_python = ">=3" +summary = "NVRTC native runtime libraries" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.4.127" +requires_python = ">=3" +summary = "CUDA Runtime native Libraries" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.1.0.70" +requires_python = ">=3" +summary = "cuDNN runtime libraries" +dependencies = [ + "nvidia-cublas-cu12", +] +files = [ + {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f"}, + {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-win_amd64.whl", hash = "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a"}, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.2.1.3" +requires_python = ">=3" +summary = "CUFFT native runtime libraries" +files = [ + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.5.147" +requires_python = ">=3" +summary = "CURAND native runtime libraries" +files = [ + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.6.1.9" +requires_python = ">=3" +summary = "CUDA solver native runtime libraries" +dependencies = [ + "nvidia-cublas-cu12", + "nvidia-cusparse-cu12", + "nvidia-nvjitlink-cu12", +] +files = [ + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260"}, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.3.1.170" +requires_python = ">=3" +summary = "CUSPARSE native runtime libraries" +dependencies = [ + "nvidia-nvjitlink-cu12", +] +files = [ + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1"}, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.6.2" +summary = "NVIDIA cuSPARSELt" +files = [ + {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:df2c24502fd76ebafe7457dbc4716b2fec071aabaed4fb7691a201cde03704d9"}, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.21.5" +requires_python = ">=3" +summary = "NVIDIA Collective Communication Library (NCCL) Runtime" +files = [ + {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.4.127" +requires_python = ">=3" +summary = "Nvidia JIT LTO Library" +files = [ + {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.4.127" +requires_python = ">=3" +summary = "NVIDIA Tools Extension" +files = [ + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, +] + +[[package]] +name = "oauthlib" +version = "3.2.2" +requires_python = ">=3.6" +summary = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, + {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, + {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, ] [[package]] -name = "mkdocstrings" -version = "0.25.2" -requires_python = ">=3.8" -summary = "Automatic documentation from sources, for MkDocs." -groups = ["docs"] +name = "omegaconf" +version = "2.3.0" +requires_python = ">=3.6" +summary = "A flexible configuration library" dependencies = [ - "Jinja2>=2.11.1", - "Markdown>=3.3", - "MarkupSafe>=1.1", - "click>=7.0", - "importlib-metadata>=4.6; python_version < \"3.10\"", - "mkdocs-autorefs>=0.3.1", - "mkdocs>=1.4", - "platformdirs>=2.2.0", - "pymdown-extensions>=6.3", - "typing-extensions>=4.1; python_version < \"3.10\"", + "PyYAML>=5.1.0", + "antlr4-python3-runtime==4.9.*", ] files = [ - {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"}, - {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"}, + {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, + {file = "omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7"}, ] [[package]] -name = "mkdocstrings-python" -version = "1.10.8" -requires_python = ">=3.8" -summary = "A Python handler for mkdocstrings." -groups = ["docs"] +name = "opencv-python-headless" +version = "4.11.0.86" +requires_python = ">=3.6" +summary = "Wrapper package for OpenCV python bindings." dependencies = [ - "griffe>=0.49", - "mkdocstrings>=0.25", + "numpy>=1.17.0; python_version >= \"3.7\"", + "numpy>=1.17.3; python_version >= \"3.8\"", + "numpy>=1.19.3; python_version >= \"3.9\"", + "numpy>=1.21.2; python_version >= \"3.10\"", + "numpy>=1.23.5; python_version >= \"3.11\"", ] files = [ - {file = "mkdocstrings_python-1.10.8-py3-none-any.whl", hash = "sha256:bb12e76c8b071686617f824029cb1dfe0e9afe89f27fb3ad9a27f95f054dcd89"}, - {file = "mkdocstrings_python-1.10.8.tar.gz", hash = "sha256:5856a59cbebbb8deb133224a540de1ff60bded25e54d8beacc375bb133d39016"}, + {file = "opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b"}, ] [[package]] -name = "mkdocstrings" -version = "0.25.2" -extras = ["python"] +name = "openslide-python" +version = "1.3.1" requires_python = ">=3.8" -summary = "Automatic documentation from sources, for MkDocs." -groups = ["docs"] +summary = "Python interface to OpenSlide" dependencies = [ - "mkdocstrings-python>=0.5.2", - "mkdocstrings==0.25.2", + "Pillow", ] files = [ - {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"}, - {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"}, + {file = "openslide-python-1.3.1.tar.gz", hash = "sha256:0909c6257cd8decfbbd0082e8c0cd94bbe3a89ad31e142cfa9accc8bb959294e"}, + {file = "openslide_python-1.3.1-cp311-cp311-win32.whl", hash = "sha256:c4720598ba39e7b879e757eff31195f8b80d4638dcb0fbb297ca9823039724ae"}, + {file = "openslide_python-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:53a468cd92bdd17cf5b56592242709519c0c7d7028b2f466d20d75264471cc6d"}, + {file = "openslide_python-1.3.1-cp312-cp312-win32.whl", hash = "sha256:d10caf1a1c1e1f598d80e7a5e1a266979ed9bccf9ba8bf45aa34cf04639d9f9e"}, + {file = "openslide_python-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:d834fbca0824b902da9d8541f7c34a3e62496823a42de5ac7bf6c35e4c799678"}, ] [[package]] -name = "mypy" -version = "1.11.2" +name = "opentelemetry-api" +version = "1.27.0" requires_python = ">=3.8" -summary = "Optional static typing for Python" -groups = ["dev"] +summary = "OpenTelemetry Python API" dependencies = [ - "mypy-extensions>=1.0.0", - "tomli>=1.1.0; python_version < \"3.11\"", - "typing-extensions>=4.6.0", + "deprecated>=1.2.6", + "importlib-metadata<=8.4.0,>=6.0", ] files = [ - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7"}, + {file = "opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342"}, ] [[package]] -name = "mypy-extensions" -version = "1.0.0" -requires_python = ">=3.5" -summary = "Type system extensions for programs checked with the mypy type checker." -groups = ["dev"] -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +name = "opentelemetry-sdk" +version = "1.27.0" +requires_python = ">=3.8" +summary = "OpenTelemetry Python SDK" +dependencies = [ + "opentelemetry-api==1.27.0", + "opentelemetry-semantic-conventions==0.48b0", + "typing-extensions>=3.7.4", ] - -[[package]] -name = "networkx" -version = "3.3" -requires_python = ">=3.10" -summary = "Python package for creating and manipulating graphs and networks" -groups = ["default"] files = [ - {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, - {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, + {file = "opentelemetry_sdk-1.27.0-py3-none-any.whl", hash = "sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d"}, + {file = "opentelemetry_sdk-1.27.0.tar.gz", hash = "sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f"}, ] [[package]] -name = "nodeenv" -version = "1.9.1" -requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -summary = "Node.js virtual environment builder" -groups = ["dev"] -files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +name = "opentelemetry-semantic-conventions" +version = "0.48b0" +requires_python = ">=3.8" +summary = "OpenTelemetry Semantic Conventions" +dependencies = [ + "deprecated>=1.2.6", + "opentelemetry-api==1.27.0", ] - -[[package]] -name = "numpy" -version = "2.1.0" -requires_python = ">=3.10" -summary = "Fundamental package for array computing in Python" -groups = ["default"] -files = [ - {file = "numpy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:76368c788ccb4f4782cf9c842b316140142b4cbf22ff8db82724e82fe1205dce"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8e93a01a35be08d31ae33021e5268f157a2d60ebd643cfc15de6ab8e4722eb1"}, - {file = "numpy-2.1.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9523f8b46485db6939bd069b28b642fec86c30909cea90ef550373787f79530e"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54139e0eb219f52f60656d163cbe67c31ede51d13236c950145473504fa208cb"}, - {file = "numpy-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebbf9fbdabed208d4ecd2e1dfd2c0741af2f876e7ae522c2537d404ca895c3"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:378cb4f24c7d93066ee4103204f73ed046eb88f9ad5bb2275bb9fa0f6a02bd36"}, - {file = "numpy-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f699a709120b220dfe173f79c73cb2a2cab2c0b88dd59d7b49407d032b8ebd"}, - {file = "numpy-2.1.0-cp311-cp311-win32.whl", hash = "sha256:ffbd6faeb190aaf2b5e9024bac9622d2ee549b7ec89ef3a9373fa35313d44e0e"}, - {file = "numpy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0af3a5987f59d9c529c022c8c2a64805b339b7ef506509fba7d0556649b9714b"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fe76d75b345dc045acdbc006adcb197cc680754afd6c259de60d358d60c93736"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f358ea9e47eb3c2d6eba121ab512dfff38a88db719c38d1e67349af210bc7529"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:dd94ce596bda40a9618324547cfaaf6650b1a24f5390350142499aa4e34e53d1"}, - {file = "numpy-2.1.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b47c551c6724960479cefd7353656498b86e7232429e3a41ab83be4da1b109e8"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0756a179afa766ad7cb6f036de622e8a8f16ffdd55aa31f296c870b5679d745"}, - {file = "numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24003ba8ff22ea29a8c306e61d316ac74111cebf942afbf692df65509a05f111"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b34fa5e3b5d6dc7e0a4243fa0f81367027cb6f4a7215a17852979634b5544ee0"}, - {file = "numpy-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4f982715e65036c34897eb598d64aef15150c447be2cfc6643ec7a11af06574"}, - {file = "numpy-2.1.0-cp312-cp312-win32.whl", hash = "sha256:c4cd94dfefbefec3f8b544f61286584292d740e6e9d4677769bc76b8f41deb02"}, - {file = "numpy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0cdef204199278f5c461a0bed6ed2e052998276e6d8ab2963d5b5c39a0500bc"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8ab81ccd753859ab89e67199b9da62c543850f819993761c1e94a75a814ed667"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:442596f01913656d579309edcd179a2a2f9977d9a14ff41d042475280fc7f34e"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:848c6b5cad9898e4b9ef251b6f934fa34630371f2e916261070a4eb9092ffd33"}, - {file = "numpy-2.1.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:54c6a63e9d81efe64bfb7bcb0ec64332a87d0b87575f6009c8ba67ea6374770b"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652e92fc409e278abdd61e9505649e3938f6d04ce7ef1953f2ec598a50e7c195"}, - {file = "numpy-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab32eb9170bf8ffcbb14f11613f4a0b108d3ffee0832457c5d4808233ba8977"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8fb49a0ba4d8f41198ae2d52118b050fd34dace4b8f3fb0ee34e23eb4ae775b1"}, - {file = "numpy-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:44e44973262dc3ae79e9063a1284a73e09d01b894b534a769732ccd46c28cc62"}, - {file = "numpy-2.1.0-cp313-cp313-win32.whl", hash = "sha256:ab83adc099ec62e044b1fbb3a05499fa1e99f6d53a1dde102b2d85eff66ed324"}, - {file = "numpy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:de844aaa4815b78f6023832590d77da0e3b6805c644c33ce94a1e449f16d6ab5"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:343e3e152bf5a087511cd325e3b7ecfd5b92d369e80e74c12cd87826e263ec06"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f07fa2f15dabe91259828ce7d71b5ca9e2eb7c8c26baa822c825ce43552f4883"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5474dad8c86ee9ba9bb776f4b99ef2d41b3b8f4e0d199d4f7304728ed34d0300"}, - {file = "numpy-2.1.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1f817c71683fd1bb5cff1529a1d085a57f02ccd2ebc5cd2c566f9a01118e3b7d"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a3336fbfa0d38d3deacd3fe7f3d07e13597f29c13abf4d15c3b6dc2291cbbdd"}, - {file = "numpy-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a894c51fd8c4e834f00ac742abad73fc485df1062f1b875661a3c1e1fb1c2f6"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:9156ca1f79fc4acc226696e95bfcc2b486f165a6a59ebe22b2c1f82ab190384a"}, - {file = "numpy-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:624884b572dff8ca8f60fab591413f077471de64e376b17d291b19f56504b2bb"}, - {file = "numpy-2.1.0.tar.gz", hash = "sha256:7dc90da0081f7e1da49ec4e398ede6a8e9cc4f5ebe5f9e06b443ed889ee9aaa2"}, +files = [ + {file = "opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl", hash = "sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f"}, + {file = "opentelemetry_semantic_conventions-0.48b0.tar.gz", hash = "sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a"}, ] [[package]] @@ -659,41 +1359,38 @@ name = "packaging" version = "24.1" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["default", "docs", "test"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] -name = "paginate" -version = "0.5.7" -summary = "Divides large result sets into pages for easier browsing" -groups = ["docs"] -files = [ - {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, - {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -requires_python = ">=3.8" -summary = "Utility library for gitignore style pattern matching of file paths." -groups = ["docs"] -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +name = "pandas" +version = "2.2.2" +requires_python = ">=3.9" +summary = "Powerful data structures for data analysis, time series, and statistics" +dependencies = [ + "numpy>=1.23.2; python_version == \"3.11\"", + "python-dateutil>=2.8.2", + "pytz>=2020.1", + "tzdata>=2022.7", ] - -[[package]] -name = "perlin-noise" -version = "1.13" -summary = "Python implementation for Perlin Noise with unlimited coordinates space" -groups = ["test"] files = [ - {file = "perlin_noise-1.13-py3-none-any.whl", hash = "sha256:09f274c8da38f5a2a48b1626032a1b7738990df758a3bc7549ff3464869c6ca4"}, - {file = "perlin_noise-1.13.tar.gz", hash = "sha256:0e0f074743336fbe9cf2cdbdeb74c75d43780a8b3cbc3415859cd396ab4da177"}, + {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"}, + {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"}, + {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"}, + {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"}, + {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"}, + {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"}, + {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"}, + {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"}, + {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"}, + {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"}, + {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"}, + {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"}, + {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, + {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, + {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"}, ] [[package]] @@ -701,7 +1398,6 @@ name = "pillow" version = "10.4.0" requires_python = ">=3.8" summary = "Python Imaging Library (Fork)" -groups = ["default"] files = [ {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, @@ -739,34 +1435,31 @@ files = [ {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, ] +[[package]] +name = "pkgconfig" +version = "1.5.5" +requires_python = ">=3.3,<4.0" +summary = "Interface Python with pkg-config" +files = [ + {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, + {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, +] + [[package]] name = "platformdirs" version = "4.2.2" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -groups = ["dev", "docs"] files = [ {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] -[[package]] -name = "pluggy" -version = "1.5.0" -requires_python = ">=3.8" -summary = "plugin and hook calling mechanisms for python" -groups = ["test"] -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - [[package]] name = "pre-commit" version = "3.8.0" requires_python = ">=3.9" summary = "A framework for managing and maintaining multi-language pre-commit hooks." -groups = ["dev"] dependencies = [ "cfgv>=2.0.0", "identify>=1.0.0", @@ -780,63 +1473,115 @@ files = [ ] [[package]] -name = "pygments" -version = "2.18.0" +name = "protobuf" +version = "5.28.0" requires_python = ">=3.8" -summary = "Pygments is a syntax highlighting package written in Python." -groups = ["docs"] +summary = "" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "protobuf-5.28.0-cp310-abi3-win32.whl", hash = "sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0"}, + {file = "protobuf-5.28.0-cp310-abi3-win_amd64.whl", hash = "sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6"}, + {file = "protobuf-5.28.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:532627e8fdd825cf8767a2d2b94d77e874d5ddb0adefb04b237f7cc296748681"}, + {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:018db9056b9d75eb93d12a9d35120f97a84d9a919bcab11ed56ad2d399d6e8dd"}, + {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:6206afcb2d90181ae8722798dcb56dc76675ab67458ac24c0dd7d75d632ac9bd"}, + {file = "protobuf-5.28.0-py3-none-any.whl", hash = "sha256:510ed78cd0980f6d3218099e874714cdf0d8a95582e7b059b06cabad855ed0a0"}, + {file = "protobuf-5.28.0.tar.gz", hash = "sha256:dde74af0fa774fa98892209992295adbfb91da3fa98c8f67a88afe8f5a349add"}, ] [[package]] -name = "pymdown-extensions" -version = "10.9" +name = "pyarrow" +version = "17.0.0" requires_python = ">=3.8" -summary = "Extension pack for Python Markdown." -groups = ["docs"] +summary = "Python library for Apache Arrow" dependencies = [ - "markdown>=3.6", - "pyyaml", + "numpy>=1.16.6", +] +files = [ + {file = "pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977"}, + {file = "pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4"}, + {file = "pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03"}, + {file = "pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22"}, + {file = "pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b"}, + {file = "pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7"}, + {file = "pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28"}, ] + +[[package]] +name = "pyasn1" +version = "0.6.0" +requires_python = ">=3.8" +summary = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" files = [ - {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, - {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, ] [[package]] -name = "pytest" -version = "8.3.2" +name = "pyasn1-modules" +version = "0.4.0" requires_python = ">=3.8" -summary = "pytest: simple powerful testing with Python" -groups = ["test"] +summary = "A collection of ASN.1-based protocols modules" dependencies = [ - "colorama; sys_platform == \"win32\"", - "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", - "iniconfig", - "packaging", - "pluggy<2,>=1.5", - "tomli>=1; python_version < \"3.11\"", + "pyasn1<0.7.0,>=0.4.6", +] +files = [ + {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, + {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +requires_python = ">=3.8" +summary = "C parser in Python" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +requires_python = ">=3.8" +summary = "Data validation using Python type hints" +dependencies = [ + "annotated-types>=0.6.0", + "pydantic-core==2.27.2", + "typing-extensions>=4.12.2", ] files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [[package]] -name = "pytest-cov" -version = "5.0.0" +name = "pydantic-core" +version = "2.27.2" requires_python = ">=3.8" -summary = "Pytest plugin for measuring coverage." -groups = ["test"] +summary = "Core functionality for Pydantic validation and serialization" dependencies = [ - "coverage[toml]>=5.2.1", - "pytest>=4.6", + "typing-extensions!=4.7.0,>=4.6.0", +] +files = [ + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] + +[[package]] +name = "pyparsing" +version = "3.1.4" +requires_python = ">=3.6.8" +summary = "pyparsing module - Classes and methods to define and execute parsing grammars" files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, + {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, + {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, ] [[package]] @@ -844,7 +1589,6 @@ name = "python-dateutil" version = "2.9.0.post0" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Extensions to the standard Python datetime module" -groups = ["docs"] dependencies = [ "six>=1.5", ] @@ -853,12 +1597,52 @@ files = [ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] +[[package]] +name = "pytorch-lightning" +version = "2.4.0" +requires_python = ">=3.8" +summary = "PyTorch Lightning is the lightweight PyTorch wrapper for ML researchers. Scale your models. Write less boilerplate." +dependencies = [ + "PyYAML>=5.4", + "fsspec[http]>=2022.5.0", + "lightning-utilities>=0.10.0", + "packaging>=20.0", + "torch>=2.1.0", + "torchmetrics>=0.7.0", + "tqdm>=4.57.0", + "typing-extensions>=4.4.0", +] +files = [ + {file = "pytorch-lightning-2.4.0.tar.gz", hash = "sha256:6aa897fd9d6dfa7b7b49f37c2f04e13592861831d08deae584dfda423fdb71c8"}, + {file = "pytorch_lightning-2.4.0-py3-none-any.whl", hash = "sha256:9ac7935229ac022ef06994c928217ed37f525ac6700f7d4fc57009624570e655"}, +] + +[[package]] +name = "pytz" +version = "2024.1" +summary = "World timezone definitions, modern and historical" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pyvips" +version = "2.2.3" +summary = "binding for the libvips image processing library, API mode" +dependencies = [ + "cffi>=1.0.0", + "pkgconfig", +] +files = [ + {file = "pyvips-2.2.3.tar.gz", hash = "sha256:43bceced0db492654c93008246a58a508e0373ae1621116b87b322f2ac72212f"}, +] + [[package]] name = "pyyaml" version = "6.0.2" requires_python = ">=3.8" summary = "YAML parser and emitter for Python" -groups = ["dev", "docs"] files = [ {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, @@ -891,57 +1675,100 @@ files = [ ] [[package]] -name = "pyyaml-env-tag" -version = "0.1" -requires_python = ">=3.6" -summary = "A custom YAML tag for referencing environment variables in YAML files. " -groups = ["docs"] +name = "rationai-kube-jobs" +version = "0.1.0" +requires_python = ">=3.11" +git = "ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git" +revision = "7ce565cc35bfd1abe30db2e1e4e606e65dda8c84" +summary = "A simple CLI tool for managing Kubernetes jobs." +dependencies = [ + "click>=8.1.7", + "kubernetes>=31.0.0", +] + +[[package]] +name = "rationai-masks" +version = "1.0.0" +requires_python = ">=3.11" +git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git" +revision = "7d56f2ba3c7b411bdf6043ae1224676c745317d2" +summary = "" +dependencies = [ + "numpy>=1.9.0", + "openslide-python>=1.3.1", + "pandas>=2.2.2", + "pillow>=10.4.0", + "pyvips>=2.2.3", + "ray>=2.34.0", + "tqdm>=4.66.5", +] + +[[package]] +name = "rationai-mlkit" +version = "0.1.15" +requires_python = ">=3.11" +git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git" +revision = "19712cca6931f11d25292cd35c5678b53592b5e7" +summary = "" +dependencies = [ + "GitPython>=3.1.43", + "hydra-core>=1.3.2", + "lightning>=2.2.4", + "mlflow>=2.12.1", + "openslide-python>=1.3.1", + "torch>=2.2.0", +] + +[[package]] +name = "rationai-tiling" +version = "1.0.0" +requires_python = ">=3.11" +git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git" +revision = "5889fc70093e097684f6014dab8ad5d0616e14fd" +summary = "" +dependencies = [ + "mlflow>=2.15.1", + "numpy>=1.9.0", + "openslide-python>=1.3.1", + "pandas>=2.2.2", + "pyvips>=2.2.3", + "ray>=2.34.0", + "tqdm>=4.66.5", +] + +[[package]] +name = "ray" +version = "2.38.0" +requires_python = ">=3.9" +summary = "Ray provides a simple, universal API for building distributed applications." dependencies = [ + "aiosignal", + "click>=7.0", + "filelock", + "frozenlist", + "jsonschema", + "msgpack<2.0.0,>=1.0.0", + "packaging", + "protobuf!=3.19.5,>=3.15.3", "pyyaml", + "requests", ] files = [ - {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, - {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, + {file = "ray-2.38.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:ece802cf3a1c102b53f63b8bc90d947971c4b387deaf233c224ed8ef34a1f3cb"}, ] [[package]] -name = "regex" -version = "2024.7.24" +name = "referencing" +version = "0.35.1" requires_python = ">=3.8" -summary = "Alternative regular expression module, to replace re." -groups = ["docs"] -files = [ - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, - {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, - {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, - {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, - {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, - {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, +summary = "JSON Referencing + Python" +dependencies = [ + "attrs>=22.2.0", + "rpds-py>=0.7.0", +] +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [[package]] @@ -949,7 +1776,6 @@ name = "requests" version = "2.32.3" requires_python = ">=3.8" summary = "Python HTTP for Humans." -groups = ["docs"] dependencies = [ "certifi>=2017.4.17", "charset-normalizer<4,>=2", @@ -961,61 +1787,83 @@ files = [ {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +requires_python = ">=3.4" +summary = "OAuthlib authentication support for Requests." +dependencies = [ + "oauthlib>=3.0.0", + "requests>=2.0.0", +] +files = [ + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, +] + +[[package]] +name = "rpds-py" +version = "0.21.0" +requires_python = ">=3.9" +summary = "Python bindings to Rust's persistent data structures (rpds)" +files = [ + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d"}, + {file = "rpds_py-0.21.0.tar.gz", hash = "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db"}, +] + +[[package]] +name = "rsa" +version = "4.9" +requires_python = ">=3.6,<4" +summary = "Pure-Python RSA implementation" +dependencies = [ + "pyasn1>=0.1.3", +] +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + [[package]] name = "ruff" -version = "0.6.2" +version = "0.6.0" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." -groups = ["dev"] -files = [ - {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, - {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, - {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, - {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, - {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, - {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, - {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, -] - -[[package]] -name = "scikit-image" -version = "0.24.0" +files = [ + {file = "ruff-0.6.0-py3-none-linux_armv6l.whl", hash = "sha256:92dcce923e5df265781e5fc76f9a1edad52201a7aafe56e586b90988d5239013"}, + {file = "ruff-0.6.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:31b90ff9dc79ed476c04e957ba7e2b95c3fceb76148f2079d0d68a908d2cfae7"}, + {file = "ruff-0.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d834a9ec9f8287dd6c3297058b3a265ed6b59233db22593379ee38ebc4b9768"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2089267692696aba342179471831a085043f218706e642564812145df8b8d0d"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa62b423ee4bbd8765f2c1dbe8f6aac203e0583993a91453dc0a449d465c84da"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7344e1a964b16b1137ea361d6516ce4ee61a0403fa94252a1913ecc1311adcae"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:487f3a35c3f33bf82be212ce15dc6278ea854e35573a3f809442f73bec8b2760"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75db409984077a793cf344d499165298a6f65449e905747ac65983b12e3e64b1"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84908bd603533ecf1db456d8fc2665d1f4335d722e84bc871d3bbd2d1116c272"}, + {file = "ruff-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f1749a0aef3ec41ed91a0e2127a6ae97d2e2853af16dbd4f3c00d7a3af726c5"}, + {file = "ruff-0.6.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:016fea751e2bcfbbd2f8cb19b97b37b3fd33148e4df45b526e87096f4e17354f"}, + {file = "ruff-0.6.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6ae80f141b53b2e36e230017e64f5ea2def18fac14334ffceaae1b780d70c4f7"}, + {file = "ruff-0.6.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:eaaaf33ea4b3f63fd264d6a6f4a73fa224bbfda4b438ffea59a5340f4afa2bb5"}, + {file = "ruff-0.6.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7667ddd1fc688150a7ca4137140867584c63309695a30016880caf20831503a0"}, + {file = "ruff-0.6.0-py3-none-win32.whl", hash = "sha256:ae48365aae60d40865a412356f8c6f2c0be1c928591168111eaf07eaefa6bea3"}, + {file = "ruff-0.6.0-py3-none-win_amd64.whl", hash = "sha256:774032b507c96f0c803c8237ce7d2ef3934df208a09c40fa809c2931f957fe5e"}, + {file = "ruff-0.6.0-py3-none-win_arm64.whl", hash = "sha256:a5366e8c3ae6b2dc32821749b532606c42e609a99b0ae1472cf601da931a048c"}, + {file = "ruff-0.6.0.tar.gz", hash = "sha256:272a81830f68f9bd19d49eaf7fa01a5545c5a2e86f32a9935bb0e4bb9a1db5b8"}, +] + +[[package]] +name = "scikit-learn" +version = "1.6.1" requires_python = ">=3.9" -summary = "Image processing in Python" -groups = ["default"] +summary = "A set of python modules for machine learning and data mining" dependencies = [ - "imageio>=2.33", - "lazy-loader>=0.4", - "networkx>=2.8", - "numpy>=1.23", - "packaging>=21", - "pillow>=9.1", - "scipy>=1.9", - "tifffile>=2022.8.12", + "joblib>=1.2.0", + "numpy>=1.19.5", + "scipy>=1.6.0", + "threadpoolctl>=3.1.0", ] files = [ - {file = "scikit_image-0.24.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:272909e02a59cea3ed4aa03739bb88df2625daa809f633f40b5053cf09241831"}, - {file = "scikit_image-0.24.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:190ebde80b4470fe8838764b9b15f232a964f1a20391663e31008d76f0c696f7"}, - {file = "scikit_image-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c98cc695005faf2b79904e4663796c977af22586ddf1b12d6af2fa22842dc2"}, - {file = "scikit_image-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa27b3a0dbad807b966b8db2d78da734cb812ca4787f7fbb143764800ce2fa9c"}, - {file = "scikit_image-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:dacf591ac0c272a111181afad4b788a27fe70d213cfddd631d151cbc34f8ca2c"}, - {file = "scikit_image-0.24.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6fccceb54c9574590abcddc8caf6cefa57c13b5b8b4260ab3ff88ad8f3c252b3"}, - {file = "scikit_image-0.24.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ccc01e4760d655aab7601c1ba7aa4ddd8b46f494ac46ec9c268df6f33ccddf4c"}, - {file = "scikit_image-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18836a18d3a7b6aca5376a2d805f0045826bc6c9fc85331659c33b4813e0b563"}, - {file = "scikit_image-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8579bda9c3f78cb3b3ed8b9425213c53a25fa7e994b7ac01f2440b395babf660"}, - {file = "scikit_image-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:82ab903afa60b2da1da2e6f0c8c65e7c8868c60a869464c41971da929b3e82bc"}, - {file = "scikit_image-0.24.0.tar.gz", hash = "sha256:5d16efe95da8edbeb363e0c4157b99becbd650a60b77f6e3af5768b66cf007ab"}, + {file = "scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25fc636bdaf1cc2f4a124a116312d837148b5e10872147bdaf4887926b8c03d8"}, + {file = "scikit_learn-1.6.1.tar.gz", hash = "sha256:b4fc2525eca2c69a59260f583c56a7557c6ccdf8deafdba6e060f94c1c59738e"}, ] [[package]] @@ -1023,7 +1871,6 @@ name = "scipy" version = "1.14.1" requires_python = ">=3.10" summary = "Fundamental algorithms for scientific computing in Python" -groups = ["default"] dependencies = [ "numpy<2.3,>=1.23.5", ] @@ -1055,29 +1902,189 @@ files = [ {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"}, ] +[[package]] +name = "setuptools" +version = "72.2.0" +requires_python = ">=3.8" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" +files = [ + {file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"}, + {file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"}, +] + +[[package]] +name = "simsimd" +version = "6.2.1" +summary = "Portable mixed-precision BLAS-like vector math library for x86 and ARM" +files = [ + {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173e66699597a4fcf6fa50b52cced40216fdcfba15f60b761a2bd9cb1d98a444"}, + {file = "simsimd-6.2.1.tar.gz", hash = "sha256:5e202c5386a4141946b7aee05faac8ebc2e36bca0a360b24080e57b59bc4ef6a"}, +] + [[package]] name = "six" version = "1.16.0" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" summary = "Python 2 and 3 compatibility utilities" -groups = ["docs"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] -name = "tifffile" -version = "2024.8.24" +name = "smmap" +version = "5.0.1" +requires_python = ">=3.7" +summary = "A pure Python implementation of a sliding window memory map manager" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.33" +requires_python = ">=3.7" +summary = "Database Abstraction Library" +dependencies = [ + "greenlet!=0.4.17; python_version < \"3.13\" and (platform_machine == \"aarch64\" or (platform_machine == \"ppc64le\" or (platform_machine == \"x86_64\" or (platform_machine == \"amd64\" or (platform_machine == \"AMD64\" or (platform_machine == \"win32\" or platform_machine == \"WIN32\"))))))", + "typing-extensions>=4.6.0", +] +files = [ + {file = "SQLAlchemy-2.0.33-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:570ec43e8c3c020abac4f0720baa5fe5187334e3f1e8e1777183c041962b61cc"}, + {file = "SQLAlchemy-2.0.33-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81759e77a4985abdbac068762a0eaf0f11860fe041ad6da170aae7615ea72531"}, + {file = "SQLAlchemy-2.0.33-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82c72da5be489c8d150deba70d5732398695418df5232bceb52ee323ddd9753b"}, + {file = "SQLAlchemy-2.0.33-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:30a3f55be76364b64c83788728faaba782ab282a24909e1994404c2146d39982"}, + {file = "SQLAlchemy-2.0.33-cp311-cp311-win32.whl", hash = "sha256:17d0c69f66392ad2db1609373a74d1f834b2e632f3f52d446747b8ec220aea53"}, + {file = "SQLAlchemy-2.0.33-cp311-cp311-win_amd64.whl", hash = "sha256:c5d5a733c6af7f392435e673d1b136f6bdf2366033abb35eed680400dc730840"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d81e3aeab456fe24c3f0dcfd4f952a3a5ee45e9c14fc66d34c1d7a60cf7b698"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca8788dc1baee100f09110f33a01d928cf9df4483d2bfb25a37be31a659d46bb"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684aee5fd811091b2f48006fb3fe6c7f2de4a716ef8d294a2aab762099753133"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1109cc6dc5c9d1223c42186391e6a5509e6d4ab2c30fa629573c10184f742f2e"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-win32.whl", hash = "sha256:c633e2d2f8a7b88c06e276bbe16cb7e62fed815fcbeb69cd9752cea166ecb8e8"}, + {file = "SQLAlchemy-2.0.33-cp312-cp312-win_amd64.whl", hash = "sha256:77eaf8fdf305266b806a91ae4633edbf86ad37e13bd92ac85e305e7f654c19a5"}, + {file = "SQLAlchemy-2.0.33-py3-none-any.whl", hash = "sha256:ae294808afde1b14a1a69aa86a69cadfe391848bbb233a5332a8065e4081cabc"}, + {file = "sqlalchemy-2.0.33.tar.gz", hash = "sha256:91c93333c2b37ff721dc83b37e28c29de4c502b5612f2d093468037b86aa2be0"}, +] + +[[package]] +name = "sqlparse" +version = "0.5.1" +requires_python = ">=3.8" +summary = "A non-validating SQL parser." +files = [ + {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, + {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, +] + +[[package]] +name = "stringzilla" +version = "3.12.1" +summary = "SIMD-accelerated string search, sort, hashes, fingerprints, & edit distances" +files = [ + {file = "stringzilla-3.12.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef30bd15638f83aa12978a0d184d1830caf55a7f80ccbbab0528f73873d4a017"}, + {file = "stringzilla-3.12.1.tar.gz", hash = "sha256:b812c9fc9a0ff36594e847443443895be91d38aa460a7b02b4a6e3048b76e2c8"}, +] + +[[package]] +name = "sympy" +version = "1.13.1" +requires_python = ">=3.8" +summary = "Computer algebra system (CAS) in Python" +dependencies = [ + "mpmath<1.4,>=1.1.0", +] +files = [ + {file = "sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8"}, + {file = "sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f"}, +] + +[[package]] +name = "threadpoolctl" +version = "3.5.0" +requires_python = ">=3.8" +summary = "threadpoolctl" +files = [ + {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, + {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, +] + +[[package]] +name = "torch" +version = "2.6.0" +requires_python = ">=3.9.0" +summary = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +dependencies = [ + "filelock", + "fsspec", + "jinja2", + "networkx", + "nvidia-cublas-cu12==12.4.5.8; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cuda-cupti-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cuda-nvrtc-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cuda-runtime-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cudnn-cu12==9.1.0.70; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cufft-cu12==11.2.1.3; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-curand-cu12==10.3.5.147; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cusolver-cu12==11.6.1.9; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cusparse-cu12==12.3.1.170; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-cusparselt-cu12==0.6.2; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-nccl-cu12==2.21.5; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-nvjitlink-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "nvidia-nvtx-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "sympy==1.13.1; python_version >= \"3.9\"", + "triton==3.2.0; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "typing-extensions>=4.10.0", +] +files = [ + {file = "torch-2.6.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:7979834102cd5b7a43cc64e87f2f3b14bd0e1458f06e9f88ffa386d07c7446e1"}, +] + +[[package]] +name = "torchmetrics" +version = "1.4.1" +requires_python = ">=3.8" +summary = "PyTorch native Metrics" +dependencies = [ + "lightning-utilities>=0.8.0", + "numpy>1.20.0", + "packaging>17.1", + "torch>=1.10.0", +] +files = [ + {file = "torchmetrics-1.4.1-py3-none-any.whl", hash = "sha256:c2e7cd56dd8bdc60ae63d712f3bdce649f23bd174d9180bdd0b746e0230b865a"}, +] + +[[package]] +name = "torchvision" +version = "0.21.0" requires_python = ">=3.9" -summary = "Read and write TIFF files" -groups = ["default"] +summary = "image and video datasets and models for torch deep learning" dependencies = [ "numpy", + "pillow!=8.3.*,>=5.3.0", + "torch==2.6.0", +] +files = [ + {file = "torchvision-0.21.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:3891cd086c5071bda6b4ee9d266bb2ac39c998c045c2ebcd1e818b8316fb5d41"}, +] + +[[package]] +name = "tqdm" +version = "4.66.5" +requires_python = ">=3.7" +summary = "Fast, Extensible Progress Meter" +files = [ + {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, + {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, ] + +[[package]] +name = "triton" +version = "3.2.0" +summary = "A language and compiler for custom Deep Learning operations" files = [ - {file = "tifffile-2024.8.24-py3-none-any.whl", hash = "sha256:40faba20cb0af05c0eb500eda63244dd81500360e1518ff4548eb61ce3943099"}, - {file = "tifffile-2024.8.24.tar.gz", hash = "sha256:65a77e50cfcf05e3553b52dd13367caad3f88eae7f533188653ce9b2d88b7464"}, + {file = "triton-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8009a1fb093ee8546495e96731336a33fb8856a38e45bb4ab6affd6dbc3ba220"}, ] [[package]] @@ -1085,18 +2092,26 @@ name = "typing-extensions" version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" -groups = ["dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "tzdata" +version = "2024.1" +requires_python = ">=2" +summary = "Provider of IANA time zone data" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + [[package]] name = "urllib3" version = "2.2.2" requires_python = ">=3.8" summary = "HTTP library with thread-safe connection pooling, file post, and more." -groups = ["docs"] files = [ {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, @@ -1107,11 +2122,9 @@ name = "virtualenv" version = "20.26.3" requires_python = ">=3.7" summary = "Virtual Python Environment builder" -groups = ["dev"] dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", - "importlib-metadata>=6.6; python_version < \"3.8\"", "platformdirs<5,>=3.9.1", ] files = [ @@ -1120,30 +2133,108 @@ files = [ ] [[package]] -name = "watchdog" -version = "5.0.0" -requires_python = ">=3.9" -summary = "Filesystem events monitoring" -groups = ["docs"] -files = [ - {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553"}, - {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9"}, - {file = "watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e"}, - {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d"}, - {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b"}, - {file = "watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45"}, - {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1"}, - {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8"}, - {file = "watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5"}, - {file = "watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9"}, - {file = "watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12"}, - {file = "watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4"}, - {file = "watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c"}, - {file = "watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e"}, +name = "websocket-client" +version = "1.8.0" +requires_python = ">=3.8" +summary = "WebSocket client for Python with low level API options" +files = [ + {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, + {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, +] + +[[package]] +name = "werkzeug" +version = "3.0.4" +requires_python = ">=3.8" +summary = "The comprehensive WSGI web application library." +dependencies = [ + "MarkupSafe>=2.1.1", +] +files = [ + {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, + {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +requires_python = ">=3.6" +summary = "Module for decorators, wrappers and monkey patching." +files = [ + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[[package]] +name = "yarl" +version = "1.9.4" +requires_python = ">=3.7" +summary = "Yet another URL library" +dependencies = [ + "idna>=2.0", + "multidict>=4.0", +] +files = [ + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] + +[[package]] +name = "zipp" +version = "3.20.1" +requires_python = ">=3.8" +summary = "Backport of pathlib-compatible object wrapper for zip files" +files = [ + {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, + {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, ] diff --git a/preprocessing/mask_generator.py b/preprocessing/mask_generator.py new file mode 100644 index 0000000..aa40f73 --- /dev/null +++ b/preprocessing/mask_generator.py @@ -0,0 +1,69 @@ +from pathlib import Path +import pyvips +import ray +from openslide import PROPERTY_NAME_MPP_X, PROPERTY_NAME_MPP_Y, OpenSlide +from rationai.masks import tissue_mask, write_big_tiff +from rationai.masks import process_items + + +# folders: +# archive tumor cases +# chive negative cases +# Prospective negative cases +# Prospective test cases +# Prospective tumor cases + +SLIDES_PATH = "/mnt/data/scans/AI scans/Prostata/" +MASK_DEST = "./data/tissue_masks" +LEVEL = 3 + + +@ray.remote +def process_slide(slide_path: Path) -> None: + # pyvips.Image xres and yres variables don't respect level therefore we + # extract proper spatial resulution based on desired level using OpenSlide + with OpenSlide(slide_path) as slide: + downsample = slide.level_downsamples[LEVEL] + xres = 1000 / \ + (float(slide.properties[PROPERTY_NAME_MPP_X]) * downsample) + yres = 1000 / \ + (float(slide.properties[PROPERTY_NAME_MPP_Y]) * downsample) + + slide = pyvips.Image.new_from_file(slide_path, level=LEVEL) + mask = tissue_mask(slide) + mask_path = Path(MASK_DEST, f"{Path(slide_path).stem}.tiff") + mask_path.parent.mkdir(exist_ok=True, parents=True) + write_big_tiff(mask, path=mask_path, xres=xres, yres=yres) + + +BROKEN_SLIDES = { + 'P-2016_3829-04-1.mrxs', 'P-2016_3732-06-1.mrxs', 'P-2016_3732-03-1.mrxs', 'P-2016_3760-06-1.mrxs', 'P-2016_3629-13-1.mrxs', 'P-2016_3926-03-1.mrxs', + 'P-2016_3852-02-1.mrxs', 'P-2016_3988-07-1.mrxs', 'P-2016_3852-01-1.mrxs', + 'P-2016_3851-02-1.mrxs', 'P-2016_3629-12-1.mrxs', 'P-2016_3667-10-0.mrxs', 'P-2016_3606-04-1.mrxs', 'P-2016_3597-10-1.mrxs', 'P-2016_3988-10-1.mrxs', 'P-2016_3829-01-1.mrxs', 'P-2016_3926-02-1.mrxs', 'P-2019_3025-03-1.mrxs', + 'P-2016_3760-04-1.mrxs', 'P-2016_3732-04-1.mrxs', 'P-2016_3667-09-1.mrxs', 'P-2019_3292-06-1.mrxs', 'P-2016_3988-02-1.mrxs', 'P-2016_3667-11-0.mrxs', 'P-2016_3606-05-1.mrxs', 'P-2016_3851-09-1.mrxs', 'P-2016_3627-09-1.mrxs', 'P-2016_3606-03-1.mrxs', 'P-2016_3627-10-1.mrxs', 'P-2016_3852-03-1.mrxs', 'P-2016_3851-07-1.mrxs', 'P-2016_3829-03-1.mrxs', 'P-2016_3627-06-1.mrxs', 'P-2016_3597-09-1.mrxs', 'P-2016_3926-01-1.mrxs', 'P-2016_3629-11-1.mrxs', 'P-2016_3760-03-1.mrxs'} + +def main() -> None: + folders = [ + # "archive tumor cases", #DONE + # "archive negative cases", # DONE + # "Prospective negative cases", #DONE + # "Prospective test cases", # DONE + # "Prospective tumor cases" # DONE + ] + + for folder in folders: + slides = [] + for slide in Path(SLIDES_PATH, folder).rglob("*.mrxs"): + if slide.name in BROKEN_SLIDES: + continue + slides.append(slide) + # slides.extend(list(Path(SLIDES_PATH, folder).rglob("*.mrxs"))) + + # slides = list(Path(SLIDES_PATH).rglob("*.mrxs")) + # process_slide(slides[0]) + process_items(slides, process_item=process_slide) + print(f"Processed {len(slides)} slides from {folder} folder") + + +if __name__ == "__main__": + main() diff --git a/preprocessing/tiler.py b/preprocessing/tiler.py new file mode 100644 index 0000000..fb54ac8 --- /dev/null +++ b/preprocessing/tiler.py @@ -0,0 +1,120 @@ +from pathlib import Path +import mlflow +import ray +from rationai.tiling import tiling +from rationai.tiling.modules.masks import PyvipsMask +from rationai.tiling.modules.tile_sources import OpenSlideTileSource +from rationai.tiling.typing import TiledSlideMetadata, TileMetadata +from rationai.tiling.writers import save_mlflow_dataset +from sklearn.model_selection import train_test_split + + +SLIDES_PATH = "/mnt/data/scans/AI scans/Prostata/" +TISSUE_MASKS_PATH = "./data/tissue_masks" + + +# level avg_mpp_x avg_mpp_y +# 0 0.233876 0.234331 +# 1 0.467751 0.468661 +# 2 0.935503 0.937323 +# 3 1.871006 1.874646 +# 4 3.742012 3.749291 +# 5 7.484024 7.498583 +# 6 14.968047 14.997165 +# 7 29.936095 29.994331 +# 8 59.872189 59.988661 +# 9 119.744379 119.97732 +SlideMPP = 0.46 + +source = OpenSlideTileSource(mpp=SlideMPP, tile_extent=512, stride=256) + + +TISSUE_PERCENTAGE = 0.5 + + +class TissueMask(PyvipsMask[TileMetadata]): + def forward_tile( + self, tile_labels: TileMetadata, class_overlaps: dict[int, float] + ) -> TileMetadata | None: + if class_overlaps.get(0, 0) > TISSUE_PERCENTAGE: + return None + return tile_labels + + +tissue_mask = TissueMask( + tile_extent=source.tile_extent, absolute_roi_extent=256, relative_roi_offset=0 +) + + +@ray.remote +def handler(slide_path: Path) -> TiledSlideMetadata: + slide, tiles = source(slide_path) + + tissue_mask_path = Path(TISSUE_MASKS_PATH, slide_path.name[:-5] + ".tiff") + tiles = tissue_mask(tissue_mask_path, slide.extent, tiles) + + return slide, tiles + +BROKEN_SLIDES = { + 'P-2016_3829-04-1.mrxs', 'P-2016_3732-06-1.mrxs', 'P-2016_3732-03-1.mrxs', 'P-2016_3760-06-1.mrxs', 'P-2016_3629-13-1.mrxs', 'P-2016_3926-03-1.mrxs', + 'P-2016_3852-02-1.mrxs', 'P-2016_3988-07-1.mrxs', 'P-2016_3852-01-1.mrxs', + 'P-2016_3851-02-1.mrxs', 'P-2016_3629-12-1.mrxs', 'P-2016_3667-10-0.mrxs', 'P-2016_3606-04-1.mrxs', 'P-2016_3597-10-1.mrxs', 'P-2016_3988-10-1.mrxs', 'P-2016_3829-01-1.mrxs', 'P-2016_3926-02-1.mrxs', 'P-2019_3025-03-1.mrxs', + 'P-2016_3760-04-1.mrxs', 'P-2016_3732-04-1.mrxs', 'P-2016_3667-09-1.mrxs', 'P-2019_3292-06-1.mrxs', 'P-2016_3988-02-1.mrxs', 'P-2016_3667-11-0.mrxs', 'P-2016_3606-05-1.mrxs', 'P-2016_3851-09-1.mrxs', 'P-2016_3627-09-1.mrxs', 'P-2016_3606-03-1.mrxs', 'P-2016_3627-10-1.mrxs', 'P-2016_3852-03-1.mrxs', 'P-2016_3851-07-1.mrxs', 'P-2016_3829-03-1.mrxs', 'P-2016_3627-06-1.mrxs', 'P-2016_3597-09-1.mrxs', 'P-2016_3926-01-1.mrxs', 'P-2016_3629-11-1.mrxs', 'P-2016_3760-03-1.mrxs'} + +def main() -> None: + folders = [ + "archive tumor cases", + "archive negative cases", + "Prospective negative cases", + "Prospective test cases", + "Prospective tumor cases" + ] + + slides = [] + for folder in folders: + for slide in Path(SLIDES_PATH, folder).rglob("*.mrxs"): + if slide.name in BROKEN_SLIDES: + continue + slides.append(slide) + + slides, test_slides = train_test_split( + slides, test_size=0.2 + ) + train_slides, val_slides = train_test_split(slides, test_size=0.1) + + train_slides_df, train_tiles_df = tiling( + slides=train_slides, handler=handler) + val_slides_df, val_tiles_df = tiling( + slides=list(val_slides), handler=handler) + test_slides_df, test_tiles_df = tiling( + slides=list(test_slides), handler=handler) + + train_slides_df.to_csv("./data/datasets/train_slides.csv", index=False) + train_tiles_df.to_csv("./data/datasets/train_tiles.csv", index=False) + + val_slides_df.to_csv("./data/datasets/val_slides.csv", index=False) + val_tiles_df.to_csv("./data/datasets/val_tiles.csv", index=False) + + test_slides_df.to_csv("./data/datasets/test_slides.csv", index=False) + test_tiles_df.to_csv("./data/datasets/test_tiles.csv", index=False) + + mlflow.set_experiment(experiment_name="Stain Normalization") + with mlflow.start_run(run_name="Stain Normalization Dataset") as _: + save_mlflow_dataset( + slides=train_slides_df, + tiles=train_tiles_df, + dataset_name="Stain Normalization - train", + ) + save_mlflow_dataset( + slides=val_slides_df, tiles=val_tiles_df, dataset_name="Stain Normalization - val" + ) + save_mlflow_dataset( + slides=test_slides_df, + tiles=test_tiles_df, + dataset_name="Stain Normalization - test", + ) + + +if __name__ == "__main__": + # pass + main() diff --git a/pyproject.toml b/pyproject.toml index aa64ea2..64d0f5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,27 +1,43 @@ [project] -name = "rationai-staining" +name = "project-name" version = "0.1.0" -description = "" -authors = [{ name = "Tomáš Balák" }] +authors = [] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } -dependencies = ["numpy>=1.26.4", "pillow>=10.3.0", "scikit-image>=0.23.2"] +dependencies = [ + "torch>=2.4.0", + "lightning>=2.4.0", + "torchmetrics>=1.4.1", + "rationai-mlkit @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git", + "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", + "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", + "albumentations>=2.0.4", + "scikit-learn>=1.6.1", + "torchvision>=0.21.0", + "rationai-kube-jobs @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git", +] [tool.pdm.dev-dependencies] dev = ["mypy", "pre-commit", "ruff"] -test = ["pytest", "pytest-cov", "perlin-noise>=1.12"] -docs = ["mkdocs-material>=9.5.32", "mkdocstrings[python]>=0.25.2"] [tool.pdm.scripts] +mask_generate = "python preprocessing/mask_generator.py" +tiler = "python preprocessing/tiler.py" + +train = "python -m project_name mode=fit" +validate = "python -m project_name mode=validate" +test = "python -m project_name mode=test" +predict = "python -m project_name mode=predict" l = { composite = ["lint", "format", "mypy"] } -test = "pytest tests" lint = "ruff check --fix" format = "ruff format" mypy = "mypy ." -docs = "mkdocs serve" post_install = { composite = [ "pre-commit autoupdate", "pre-commit install", "pre-commit install --hook-type commit-msg", ] } + +[tool.pdm] +distribution = false diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 276b351..0000000 --- a/pytest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[pytest] -markers = - color_conversion: tests expected values and method behavior of the ColorConversion Enum - stain_separation: tests expected behavior of the stain separation functionality - stain_reconstruction: tests that applying color combination after color separation return yields roughly the same image - stain_estimator: tests stain estimation functionality \ No newline at end of file diff --git a/rationai/staining/__init__.py b/rationai/staining/__init__.py deleted file mode 100644 index 12ba09e..0000000 --- a/rationai/staining/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -from rationai.staining.convert_color import ( - ColorConversion, - ConversionType, - convert_color, -) -from rationai.staining.estimate_stain_vectors import estimate_stain_vectors -from rationai.staining.modify_and_reconstruct import modify_and_reconstruct - - -__all__ = [ - "ColorConversion", - "ConversionType", - "convert_color", - "estimate_stain_vectors", - "modify_and_reconstruct", -] diff --git a/rationai/staining/constants.py b/rationai/staining/constants.py deleted file mode 100644 index 46b81eb..0000000 --- a/rationai/staining/constants.py +++ /dev/null @@ -1,27 +0,0 @@ -QUPATH_H = (0.651, 0.701, 0.290) -""" -QuPath value for default Hematoxylin staining vector. - -Note: - QuPath uses this value by default, even in the H&DAB protocol. - However, this value does not resemble the actual color - of Hematoxylin present in H&DAB-stained slides. - It is therefore advised to use the `LIGHT_H` value when working with - the H&DAB protocol. -""" - -LIGHT_H = (0.849, 0.514, 0.124) -""" -Value for a light blue Hematoxylin staining vector -present in the H&DAB protocol. -""" - -QUPATH_E = (0.216, 0.801, 0.558) -""" -QuPath value for default Eosin staining vector. -""" - -QUPATH_DAB = (0.269, 0.568, 0.778) -""" -QuPath value for default DAB staining vector. -""" diff --git a/rationai/staining/convert_color.py b/rationai/staining/convert_color.py deleted file mode 100644 index 21ac72b..0000000 --- a/rationai/staining/convert_color.py +++ /dev/null @@ -1,197 +0,0 @@ -from collections.abc import Sequence -from enum import Enum, auto, unique -from typing import overload - -import numpy as np -from PIL.Image import Image -from skimage.color import combine_stains - -from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H -from rationai.staining.typing import ( - RGBArray, - StainArray, -) -from rationai.staining.utils import inv_mat, residual - - -@unique -class ConversionType(Enum): - """Enum representing different types of conversions.""" - - STAIN2RGB = auto() - RGB2STAIN = auto() - - -@unique -class ColorConversion(Enum): - """Enum representing different color conversions. - - Value of the enum is a tuple with deconvolution matrix and - the type of the conversion. - - Note: - Stain channels are denoted by their first letters - (H for hematoxylin, D for DAB, ...) and residual channel - is denoted by the letter R. - """ - - HER2RGB = ( - (QUPATH_H, QUPATH_E, residual(QUPATH_H, QUPATH_E)), - ConversionType.STAIN2RGB, - ) - """**Combines** `Hematoxylin`, `Eosin` and `Residual` channels **to RGB**.""" - - HDR2RGB = ( - (LIGHT_H, QUPATH_DAB, residual(LIGHT_H, QUPATH_DAB)), - ConversionType.STAIN2RGB, - ) - """**Combines** `Hematoxylin`, `DAB` and `Residual` channels **to RGB**.""" - - HDR2RGB_LEGACY = ( - (QUPATH_H, QUPATH_DAB, residual(QUPATH_H, QUPATH_DAB)), - ConversionType.STAIN2RGB, - ) - """**Combines** `Hematoxylin`, `DAB` and `Residual` channels **to RGB**. - - This conversion uses the Hematoxylin vector from QuPath, and it is no longer - recommended and is marked as legacy as it did not - provide expected results for staining detection and separation. - """ - - RGB2HDR = (inv_mat(HDR2RGB[0]), ConversionType.RGB2STAIN) - """**Separates RGB image** into `Hematoxylin`, `DAB` and `Residual` channels.""" - - RGB2HER = (inv_mat(HER2RGB[0]), ConversionType.RGB2STAIN) - """**Separates RGB image** into `Hematoxylin`, `Eosin` and `Residual` channels.""" - - RGB2HDR_LEGACY = (inv_mat(HDR2RGB_LEGACY[0]), ConversionType.RGB2STAIN) - """**Separates RGB image** into `Hematoxylin`, `DAB` and `Residual` channels. - - This conversion uses the Hematoxylin vector from QuPath, and it is no longer - recommended and is marked as legacy as it did not - provide expected results for staining detection and separation. - """ - - @property - def conv_type(self) -> ConversionType: - """Returns conversion type associated with the color conversion. - - Returns: - Conversion type associated with the color conversion. - """ - return self.value[1] - - @property - def matrix(self) -> StainArray: - """Returns the real form of the color deconvolution matrix. - - Returns: - Deconvolution matrix (3x3) represented by the color conversion - as a numpy array. - """ - return np.stack(self.value[0]) - - @property - def inverse(self) -> "ColorConversion": - """Returns the inverse color conversion. - - Returns: - Inverse color conversion (i. e., RGB2HER is inverse to HER2RGB). - """ - match self: - # H&E Protocol - case ColorConversion.RGB2HER: - return ColorConversion.HER2RGB - case ColorConversion.HER2RGB: - return ColorConversion.RGB2HER - - # H&DAB Protocol - case ColorConversion.RGB2HDR: - return ColorConversion.HDR2RGB - case ColorConversion.HDR2RGB: - return ColorConversion.RGB2HDR - - # Legacy H&DAB Protocol - case ColorConversion.RGB2HDR_LEGACY: - return ColorConversion.HDR2RGB_LEGACY - case ColorConversion.HDR2RGB_LEGACY: - return ColorConversion.RGB2HDR_LEGACY - - -def _separate_stains( - img: RGBArray | Image, rgb2stain: StainArray, keep_negative_values: bool = False -) -> StainArray: - values = np.maximum(np.asarray(img).astype(np.float64) / 255, 1e-6) - stains = (np.log(values) / np.log(1e-6)) @ rgb2stain - - if not keep_negative_values: - stains = np.maximum(stains, 0) - - return stains - - -@overload -def convert_color( - tile: RGBArray | Image, - conversion: ColorConversion, - keep_negative_values: bool = False, -) -> tuple[StainArray, ...]: ... - - -@overload -def convert_color( - tile: StainArray | Sequence[StainArray], - conversion: ColorConversion, - keep_negative_values: bool = False, -) -> RGBArray: ... - - -def convert_color( - tile: RGBArray | Image | StainArray | Sequence[StainArray], - conversion: ColorConversion, - keep_negative_values: bool = False, -) -> RGBArray | tuple[StainArray, ...]: - """Converts a tile into the specified color space. - - Based on the provided conversion enum, either color deconvolution - or stain channel combination is performed. - - Note: - Due to implementation details, it is **NOT GUARANTEED** that - `convert_tile(convert_tile(I, conv), conv.inverse) == I`. Difference between the - images can also vary depending on the used conversion. - - Args: - tile: Tile that should be converted. Can either be a RGB image or three stain - channels stacked along the last axis. Stain channels can be stacked using - the following code: - ```python - stacked_stains = np.stack([c0, c1, c2], axis=-1) - ``` - Here, `c[0-2]` are the individual stain channels. - - conversion: Desired color conversion. - - keep_negative_values: Decides if the negative values produced by color separation - should be kept. - - Returns: - Depending on the conversion, the result can either be a RGB image, - or a tuple of the separated stain channels. - """ - match conversion.conv_type: - case ConversionType.RGB2STAIN: - return tuple( - np.moveaxis( - _separate_stains(tile, conversion.matrix, keep_negative_values), # type: ignore[arg-type] - -1, - 0, - ) - ) - - case ConversionType.STAIN2RGB: - if isinstance(tile, Sequence): - tile = np.stack(tile, axis=-1) - - tile = np.asarray(tile, dtype=np.float64) - return (255 * combine_stains(tile, conversion.matrix)).astype(np.uint8) diff --git a/rationai/staining/estimate_stain_vectors.py b/rationai/staining/estimate_stain_vectors.py deleted file mode 100644 index 83f0540..0000000 --- a/rationai/staining/estimate_stain_vectors.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -from PIL.Image import Image - -from rationai.staining.typing import StainArray, Tile -from rationai.staining.utils import normalize - - -def estimate_stain_vectors( - img: Tile, i0: int = 240, alpha: int = 1, beta: float = 0.15 -) -> StainArray: - """Detects two most dominant staining vectors in the image. - - Args: - img: Stained image with three RGB channels. - i0: Transmitted light intensity. Defaults to 240. - alpha: Percentile offset for robust estimation. Defaults to 1. - beta: Threshold for transparent pixels in the OD-space. Defaults to 0.15. - - Returns: - Array with two most dominant color vectors. - - References: - Adapted from: `https://github.com/schaugf/HEnorm_python` - - Paper: A method for normalizing histology slides for quantitative analysis, - M Macenko, M Niethammer, JS Marron, D Borland, JT Woosley, G Xiaojun, - C Schmitt, NE Thomas, IEEE ISBI, 2009. dx.doi.org/10.1109/ISBI.2009.5193250 - """ - if isinstance(img, Image): - img = np.asarray(img) - - img = img.reshape((-1, 3)) - - # Calculate the optical density - od = -np.log((img.astype(np.float64) + 1) / i0) # (H*W, 3) - - # remove transparent pixels - od_hat = od[~np.any(od < beta, axis=-1)] - - if od_hat.size <= 6: - # Not enough stained pixels remained, return empty vectors - return np.full(shape=(2, 3), fill_value=np.nan) - - # Compute eigenvectors - _, eigvecs = np.linalg.eigh(np.cov(od_hat.T)) - - # Project on the plane spanned by the eigenvectors - # corresponding to the two largest eigenvalues. - t_hat = od_hat.dot(eigvecs[:, 1:3]) - - phi = np.arctan2(t_hat[:, 1], t_hat[:, 0]) - - min_phi = np.percentile(phi, alpha) - max_phi = np.percentile(phi, 100 - alpha) - - v_min = eigvecs[:, 1:3].dot(np.array([(np.cos(min_phi), np.sin(min_phi))]).T) - v_max = eigvecs[:, 1:3].dot(np.array([(np.cos(max_phi), np.sin(max_phi))]).T) - - # Make hematoxylin first and eosin second (heuristic) - if v_min[0] > v_max[0]: - return np.array((normalize(v_min[:, 0]), normalize(v_max[:, 0]))) - - return np.array((normalize(v_max[:, 0]), normalize(v_min[:, 0]))) diff --git a/rationai/staining/modify_and_reconstruct.py b/rationai/staining/modify_and_reconstruct.py deleted file mode 100644 index 10d3bab..0000000 --- a/rationai/staining/modify_and_reconstruct.py +++ /dev/null @@ -1,73 +0,0 @@ -import numpy as np -from skimage.color import combine_stains - -from rationai.staining.typing import ModifyFunction, RGBArray, StainTuple -from rationai.staining.utils.inv_mat import inv_mat -from rationai.staining.utils.residual import residual - - -def modify_and_reconstruct( - tile: RGBArray, - modify: ModifyFunction, - stain0: StainTuple, - stain1: StainTuple, - stain2: StainTuple | None = None, -) -> RGBArray: - """Modifies RGB tile in stain space and converts back to RGB. - - Args: - tile: Input RGB representation of the region. - modify: Function that takes three channels in stain space - and returns their modified versions. - stain0: First default color vector. - stain1: Second default color vector. - stain2: Third default color vector. If not provided, - a residual vector is computed from the first two. - - Returns: - Modified region in RGB space. - - Note: - - To ensure as precise reconstruction as possible, - **clipping of negative values is ommited** from stain separation. - - References: - Stain separation is adapted from skimage.color.separate_stains. - - Example: - ```python - import numpy as np - from skimage.data import immunohistochemistry - - from rationai.staining import modify_and_reconstruct - from rationai.staining.constants import QUPATH_DAB, QUPATH_H - - - def modify(c0, c1, c2): - # Remove second channel from the image - c1 = np.zeros_like(c1) - - return c0, c1, c2 - - - original = immunohistochemistry() - modified = modify_and_reconstruct(original, modify, QUPATH_H, QUPATH_DAB) - ``` - """ - if stain2 is None: - stain2 = residual(stain0, stain1) - - mat = (stain0, stain1, stain2) - - stain2rgb = np.stack(mat) - rgb2stain = np.stack(inv_mat(mat)) - - values = np.maximum(tile.astype(np.float64) / 255, 1e-6) - log_adjust = np.log(1e-6) - - stains = (np.log(values) / log_adjust) @ rgb2stain - c0, c1, c2 = tuple(np.moveaxis(stains, -1, 0)) - - modified_stains = np.stack(modify(c0, c1, c2), axis=-1) - - return (255 * combine_stains(modified_stains, stain2rgb)).astype(np.uint8) diff --git a/rationai/staining/scripts/remove_red_stain.py b/rationai/staining/scripts/remove_red_stain.py deleted file mode 100644 index f413265..0000000 --- a/rationai/staining/scripts/remove_red_stain.py +++ /dev/null @@ -1,38 +0,0 @@ -from pathlib import Path -from typing import TypeAlias - -import numpy as np -from numpy.typing import NDArray -from PIL import Image - -from rationai.staining.modify_and_reconstruct import modify_and_reconstruct - - -Channel: TypeAlias = NDArray[np.float64] - - -DIRECTORY_PATH = "/mnt/data/Projects/MOU/Bad_scans/stain separation/" -FILES = Path(DIRECTORY_PATH).glob("*.JPG") - -# STAIN DEFINITIONS -HEMATOXYLIN = (0.849, 0.514, 0.124) -DAB = (0.262, 0.631, 0.730) -RED = (0.128, 0.875, 0.466) - - -def modify(c0: Channel, c1: Channel, c2: Channel) -> tuple[Channel, Channel, Channel]: - c2 = np.zeros_like(c2) - - return c0, c1, c2 - - -def main() -> None: - for file in FILES: - img = np.asarray(Image.open(file).convert("RGB")) - modified = modify_and_reconstruct(img, modify, HEMATOXYLIN, DAB, RED) - - Image.fromarray(modified).save(f"{file.stem}.png") - - -if __name__ == "__main__": - main() diff --git a/rationai/staining/typing.py b/rationai/staining/typing.py deleted file mode 100644 index 66f443f..0000000 --- a/rationai/staining/typing.py +++ /dev/null @@ -1,47 +0,0 @@ -from collections.abc import Callable -from typing import TypeAlias - -from numpy import float64, uint8 -from numpy.typing import NDArray -from PIL.Image import Image - - -ModifyFunction: TypeAlias = Callable[ - [NDArray[float64], NDArray[float64], NDArray[float64]], - tuple[NDArray[float64], NDArray[float64], NDArray[float64]], -] -""" -Type definition for function that modifies stain channels. - -The function takes three arrays in stain space and returns their modified versions. -""" - -Tile: TypeAlias = NDArray[float64 | uint8] | Image -""" -Type definition for a single tile. -""" - -StainArray: TypeAlias = NDArray[float64] -""" -Type definition for an array of stain values. -""" - -StainChannels: TypeAlias = tuple[StainArray, StainArray, StainArray] -""" -Type definition for all three deconvoluted stain channels. -""" - -StainTuple: TypeAlias = tuple[float, float, float] -""" -Type definition for a tuple of stain values. -""" - -StainTupleMatrix: TypeAlias = tuple[StainTuple, StainTuple, StainTuple] -""" -Type definition for a stain matrix represented by a tuple of tuples. -""" - -RGBArray: TypeAlias = NDArray[uint8] -""" -Type definition for an array of RGB values. -""" diff --git a/rationai/staining/utils/__init__.py b/rationai/staining/utils/__init__.py deleted file mode 100644 index ca302ed..0000000 --- a/rationai/staining/utils/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from rationai.staining.utils.inv_mat import inv_mat -from rationai.staining.utils.normalize import normalize -from rationai.staining.utils.residual import residual - - -__all__ = ["inv_mat", "normalize", "residual"] diff --git a/rationai/staining/utils/inv_mat.py b/rationai/staining/utils/inv_mat.py deleted file mode 100644 index 4ec3419..0000000 --- a/rationai/staining/utils/inv_mat.py +++ /dev/null @@ -1,8 +0,0 @@ -import numpy as np - -from rationai.staining.typing import StainTupleMatrix - - -def inv_mat(matrix: StainTupleMatrix) -> StainTupleMatrix: - mat = np.linalg.inv(np.stack(matrix)) - return tuple(tuple(row) for row in mat) # type: ignore [return-value] diff --git a/rationai/staining/utils/normalize.py b/rationai/staining/utils/normalize.py deleted file mode 100644 index d0acb37..0000000 --- a/rationai/staining/utils/normalize.py +++ /dev/null @@ -1,9 +0,0 @@ -from numpy import float64 -from numpy.linalg import norm -from numpy.typing import NDArray - - -def normalize(x: NDArray[float64]) -> NDArray[float64]: - """Normalizes a given vector to unit length.""" - n = norm(x) - return x if n == 0 else x / n diff --git a/rationai/staining/utils/residual.py b/rationai/staining/utils/residual.py deleted file mode 100644 index a031289..0000000 --- a/rationai/staining/utils/residual.py +++ /dev/null @@ -1,12 +0,0 @@ -import numpy as np -from numpy import float64 - -from rationai.staining.typing import StainTuple -from rationai.staining.utils.normalize import normalize - - -def residual(c0: StainTuple, c1: StainTuple) -> StainTuple: - c0_arr = np.array(c0, dtype=float64) - c1_arr = np.array(c1, dtype=float64) - - return tuple(np.round(normalize(np.cross(c0_arr, c1_arr)), decimals=3)) diff --git a/stain_normalization/__init__.py b/stain_normalization/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stain_normalization/data/__init__.py b/stain_normalization/data/__init__.py new file mode 100644 index 0000000..48b179a --- /dev/null +++ b/stain_normalization/data/__init__.py @@ -0,0 +1,4 @@ +from stain_normalization.data.data_module import DataModule + + +__all__ = ["DataModule"] diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py new file mode 100644 index 0000000..40147f6 --- /dev/null +++ b/stain_normalization/data/data_module.py @@ -0,0 +1,51 @@ +from collections.abc import Iterable + +from hydra.utils import instantiate +from lightning import LightningDataModule +from omegaconf import DictConfig +from torch.utils.data import DataLoader + +from stain_normalization.typing import Input + + +class DataModule(LightningDataModule): + def __init__( + self, batch_size: int, num_workers: int = 0, **datasets: DictConfig + ) -> None: + super().__init__() + self.batch_size = batch_size + self.num_workers = num_workers + self.datasets = datasets + + def setup(self, stage: str) -> None: + match stage: + case "fit": + self.train = instantiate(self.datasets["train"]) + self.val = instantiate(self.datasets["val"]) + case "validate": + self.val = instantiate(self.datasets["val"]) + case "test": + self.test = instantiate(self.datasets["test"]) + + def train_dataloader(self) -> Iterable[Input]: + return DataLoader( + self.train, + batch_size=self.batch_size, + shuffle=True, + drop_last=True, + num_workers=self.num_workers, + persistent_workers=self.num_workers > 0, + ) + + def val_dataloader(self) -> Iterable[Input]: + return DataLoader( + self.val, + batch_size=self.batch_size, + num_workers=self.num_workers, + persistent_workers=self.num_workers > 0, + ) + + def test_dataloader(self) -> Iterable[Input]: + return DataLoader( + self.test, batch_size=self.batch_size, num_workers=self.num_workers + ) diff --git a/stain_normalization/data/datasets/__init__.py b/stain_normalization/data/datasets/__init__.py new file mode 100644 index 0000000..32125cf --- /dev/null +++ b/stain_normalization/data/datasets/__init__.py @@ -0,0 +1,4 @@ +from stain_normalization.data.datasets.stain_normalization import StainNormalization, StainNormalizationPredict + + +__all__ = ["StainNormalization", "StainNormalizationPredict"] diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py new file mode 100644 index 0000000..e2468c3 --- /dev/null +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -0,0 +1,114 @@ +from collections.abc import Iterable + +import pandas as pd +from albumentations import TransformType +from albumentations.pytorch import ToTensorV2 +from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset +from torch.utils.data import Dataset + +from stain_normalization.typing import Metadata, PredictSample, Sample + + +class StainNormalization(MetaTiledSlides[Sample]): + def __init__( + self, + uris: Iterable[str], + modify:TransformType, + transforms: TransformType | None = None, + + ) -> None: + self.modify = modify + self.transforms = transforms + super().__init__(uris=uris) + + def generate_datasets(self) -> Iterable[Dataset[Sample]]: + return ( + _StainNormalizationSlideTiles( + slide, + tiles=self.filter_tiles_by_slide(slide["id"]), + include_target=True, + modify=self.modify, + transforms=self.transforms, + ) + for _, slide in self.slides.iterrows() + ) + + +class StainNormalizationPredict(MetaTiledSlides[PredictSample]): + def __init__( + self, + uris: Iterable[str], + modify:TransformType, + transforms: TransformType | None = None, + + ) -> None: + self.modify = modify + self.transforms = transforms + super().__init__(uris=uris) + + def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: + return ( + _StainNormalizationSlideTiles( + slide, + tiles=self.filter_tiles_by_slide(slide["id"]), + include_target=False, + modify=self.modify, + transforms=self.transforms, + ) + for _, slide in self.slides.iterrows() + ) + + +class _StainNormalizationSlideTiles(Dataset[Sample | PredictSample]): + def __init__( + self, + slide_metadata: pd.Series, + tiles: pd.DataFrame, + include_target: bool, + transforms: TransformType | None = None, + modify:TransformType | None = None, + ) -> None: + super().__init__() + self.slide_tiles = OpenSlideTilesDataset( + slide_path=slide_metadata.path, + level=slide_metadata.level, + tile_extent_x=slide_metadata.tile_extent_x, + tile_extent_y=slide_metadata.tile_extent_y, + tiles=tiles, + ) + self.transforms = transforms + self.include_target = include_target + self.to_tensor = ToTensorV2() + self.modify = modify + + def __len__(self) -> int: + return len(self.slide_tiles) + + def __getitem__(self, idx: int) -> Sample | PredictSample: + original_image = self.slide_tiles[idx] + + + if self.transforms is not None: + original_image = self.transforms(image=original_image)["image"] + + modified_image = self.modify(original_image)["image"] + + # modification_name = "Original" + # if self.modify: + # out = self.modify(original_image) + # modified_image = out["image"] + # modification_name = out["modification_name"] + # metadata = Metadata( + # slide=self.slide_tiles.slide_path.stem, + # x=self.slide_tiles.tiles.iloc[idx]["x"], + # y=self.slide_tiles.tiles.iloc[idx]["y"], + # modification=modification_name + # ) + + original_image = self.to_tensor(image=original_image)["image"] + modified_image = self.to_tensor(image=modified_image)["image"] + + if self.include_target: + return modified_image, original_image + + return modified_image diff --git a/stain_normalization/data/transformation/__init__.py b/stain_normalization/data/transformation/__init__.py new file mode 100644 index 0000000..5e28fc7 --- /dev/null +++ b/stain_normalization/data/transformation/__init__.py @@ -0,0 +1,7 @@ +from stain_normalization.data.transformation.hed_factor import HEDFactor +from stain_normalization.data.transformation.exposure_adjustment import ExposureAdjustment +from stain_normalization.data.transformation.hue_shift import HueShift +from stain_normalization.data.transformation.combiend_modification import CombinedModifications + +__all__ = ["HEDFactor", "ExposureAdjustment", "HueShift", "CombinedModifications"] + diff --git a/stain_normalization/data/transformation/combiend_modification.py b/stain_normalization/data/transformation/combiend_modification.py new file mode 100644 index 0000000..d893f3f --- /dev/null +++ b/stain_normalization/data/transformation/combiend_modification.py @@ -0,0 +1,23 @@ +import numpy as np +from albumentations import ImageOnlyTransform +from skimage import exposure + + +class CombinedModifications(ImageOnlyTransform): + def __init__(self, intensity_range=(0.4, 1.5), brightness_range=(-0.4, 0.4), always_apply=True, p=1.0): + super().__init__(always_apply, p) + self.intensity_range = intensity_range + self.brightness_range = brightness_range + + def apply(self, img, **params): + def modify_channel(channel, intensity_range, brightness_range): + intensity_scale = np.random.uniform(*intensity_range) + channel = channel * intensity_scale + brightness_shift = np.random.uniform(*brightness_range) + channel = exposure.adjust_gamma(channel, gamma=1 + brightness_shift) + return np.clip(channel, 0, 1) + + h = modify_channel(img[:, :, 0], self.intensity_range, self.brightness_range) + e = modify_channel(img[:, :, 1], self.intensity_range, self.brightness_range) + d = img[:, :, 2] # Skip modification for D channel + return np.stack((h, e, d), axis=-1) \ No newline at end of file diff --git a/stain_normalization/data/transformation/exposure_adjustment.py b/stain_normalization/data/transformation/exposure_adjustment.py new file mode 100644 index 0000000..71af622 --- /dev/null +++ b/stain_normalization/data/transformation/exposure_adjustment.py @@ -0,0 +1,17 @@ +import numpy as np +from albumentations import ImageOnlyTransform + + +class ExposureAdjustment(ImageOnlyTransform): + def __init__(self, brightness_range: tuple[float, float] = (0.8, 1.2), always_apply: bool = True, p: float = 1): + super().__init__(always_apply, p) + self.brightness_range = brightness_range + + def apply(self, img, **params): + brightness_factor = np.random.uniform(*self.brightness_range) + h, e, d = img[:, :, 0], img[:, :, 1], img[:, :, 2] + h = np.clip(h * brightness_factor, 0, 1) + e = np.clip(e * brightness_factor, 0, 1) + d = np.clip(d * brightness_factor, 0, 1) + return np.stack((h, e, d), axis=-1) + diff --git a/stain_normalization/data/transformation/hed_factor.py b/stain_normalization/data/transformation/hed_factor.py new file mode 100644 index 0000000..13d668b --- /dev/null +++ b/stain_normalization/data/transformation/hed_factor.py @@ -0,0 +1,27 @@ +import numpy as np +from albumentations import ImageOnlyTransform +from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed + +class HEDFactor(ImageOnlyTransform): + def __init__(self, + h_range: tuple[float, float] = (0.8, 1.2), + e_range: tuple[float, float] = (0.8, 1.2), + always_apply: bool = True, + p: float = 1.0): + super().__init__(always_apply, p) + self.h_range = h_range + self.e_range = e_range + + def apply(self, img, **params): + h_factor = np.random.uniform(*self.h_range) + e_factor = np.random.uniform(*self.e_range) + + return self.multiply_channels(img, e_factor, h_factor) + + def multiply_channels(self, image, e_factor=1.1, h_factor=1.1,): + hed_image = separate_stains(image, hed_from_rgb) + h = hed_image[:, :, 0] * h_factor + e = hed_image[:, :, 1] * e_factor + d = hed_image[:, :, 2] + modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) + return modified_rgb diff --git a/stain_normalization/data/transformation/hue_shift.py b/stain_normalization/data/transformation/hue_shift.py new file mode 100644 index 0000000..b6708eb --- /dev/null +++ b/stain_normalization/data/transformation/hue_shift.py @@ -0,0 +1,34 @@ + + +import numpy as np +from albumentations import ImageOnlyTransform +from skimage.color import ( + rgb2hsv, hsv2rgb, + rgb2hed, hed2rgb +) + + +class HueShift(ImageOnlyTransform): + def __init__(self, hue_shift_range: tuple[float, float] = (0.0, 1.0), always_apply: bool = True, p: float = 1): + super().__init__(always_apply, p) + self.hue_shift_range = hue_shift_range + + def apply(self, img, **params): + hue_shift = np.random.uniform(*self.hue_shift_range) + + h, e, d = img[:, :, 0], img[:, :, 1], img[:, :, 2] + h_mod = np.clip(h * e, 0, 1) + e_mod = np.clip(e * 1, 0, 1) + d_mod = np.clip(d * 1, 0, 1) + + hed_mod = np.stack((h_mod, e_mod, d_mod), axis=-1) + + rgb_image = hed2rgb(hed_mod) + hsv_image = rgb2hsv(rgb_image) + + # Apply the random hue shift + hsv_image[:, :, 0] = (hsv_image[:, :, 0] + hue_shift) % 1.0 + + modified_rgb = hsv2rgb(hsv_image) + return rgb2hed(modified_rgb) + diff --git a/stain_normalization/main.py b/stain_normalization/main.py new file mode 100644 index 0000000..24659aa --- /dev/null +++ b/stain_normalization/main.py @@ -0,0 +1,35 @@ +from random import randint + +import hydra +from lightning import seed_everything +from lightning.pytorch.loggers import Logger +from omegaconf import DictConfig, OmegaConf +from rationai.mlkit import Trainer, autolog + +from stain_normalization.data import DataModule +from stain_normalization.stain_normalization_model import StainNormalizationModel + + +OmegaConf.register_new_resolver( + "random_seed", lambda: randint(0, 2**31), use_cache=True +) + + +@hydra.main(config_path="../configs", config_name="default", version_base=None) +@autolog +def main(config: DictConfig, logger: Logger | None) -> None: + seed_everything(config.seed, workers=True) + + data = hydra.utils.instantiate( + config.data, + _recursive_=False, # to avoid instantiating all the datasets + _target_=DataModule, + ) + model = hydra.utils.instantiate(config.model, _target_=StainNormalizationModel) + + trainer = hydra.utils.instantiate(config.trainer, _target_=Trainer, logger=logger) + getattr(trainer, config.mode)(model, datamodule=data, ckpt_path=config.checkpoint) + + +if __name__ == "__main__": + main() # pylint: disable=no-value-for-parameter diff --git a/stain_normalization/modeling/__init__.py b/stain_normalization/modeling/__init__.py new file mode 100644 index 0000000..6e52155 --- /dev/null +++ b/stain_normalization/modeling/__init__.py @@ -0,0 +1,3 @@ +from . import metrics +from .l1ssim_loss import L1SSIMLoss +__all__ = ["L1SSIMLoss", "metrics"] \ No newline at end of file diff --git a/stain_normalization/modeling/backbone/__init__.py b/stain_normalization/modeling/backbone/__init__.py new file mode 100644 index 0000000..68da66e --- /dev/null +++ b/stain_normalization/modeling/backbone/__init__.py @@ -0,0 +1,5 @@ +from stain_normalization.modeling.backbone.resnet50 import resnet50 +from stain_normalization.modeling.backbone.vgg16 import vgg16 + + +__all__ = ["resnet50", "vgg16"] \ No newline at end of file diff --git a/stain_normalization/modeling/backbone/resnet50.py b/stain_normalization/modeling/backbone/resnet50.py new file mode 100644 index 0000000..7705385 --- /dev/null +++ b/stain_normalization/modeling/backbone/resnet50.py @@ -0,0 +1,7 @@ +import torchvision +from torch import nn + + +def resnet50(weights: str | None = None) -> nn.Module: + resnet = torchvision.models.resnet50(weights=weights) + return nn.Sequential(*(list(resnet.children())[:-2])) diff --git a/stain_normalization/modeling/backbone/vgg16.py b/stain_normalization/modeling/backbone/vgg16.py new file mode 100644 index 0000000..b621ed7 --- /dev/null +++ b/stain_normalization/modeling/backbone/vgg16.py @@ -0,0 +1,6 @@ +from torch import nn +from torchvision + +def vgg16(weights: str | None = None) -> nn.Module: + return torchvision.models.vgg16(weights=weights).features + diff --git a/stain_normalization/modeling/decode_head/__init__.py b/stain_normalization/modeling/decode_head/__init__.py new file mode 100644 index 0000000..3f19fab --- /dev/null +++ b/stain_normalization/modeling/decode_head/__init__.py @@ -0,0 +1,4 @@ +from stain_normalization.modeling.decode_head.unet import UNetDecoder + + +__all__ = ["UNetDecoder"] \ No newline at end of file diff --git a/stain_normalization/modeling/decode_head/unet.py b/stain_normalization/modeling/decode_head/unet.py new file mode 100644 index 0000000..57052aa --- /dev/null +++ b/stain_normalization/modeling/decode_head/unet.py @@ -0,0 +1,35 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +class UNetDecoder(nn.Module): + def __init__(self, in_channels=2048, out_channels=3): + super(UNetDecoder, self).__init__() + + # First upsampling block + self.upconv1 = nn.ConvTranspose2d(in_channels, 1024, kernel_size=2, stride=2) + self.conv1 = nn.Conv2d(1024, 512, kernel_size=3, padding=1) + + # Second upsampling block + self.upconv2 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2) + self.conv2 = nn.Conv2d(256, 128, kernel_size=3, padding=1) + + # Third upsampling block + self.upconv3 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2) + self.conv3 = nn.Conv2d(64, 64, kernel_size=3, padding=1) + + # Fourth upsampling block + self.upconv4 = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2) + self.conv4 = nn.Conv2d(32, 16, kernel_size=3, padding=1) + + # Final upsampling to match 512x512 resolution + self.upconv5 = nn.ConvTranspose2d(16, 8, kernel_size=2, stride=2) + self.conv5 = nn.Conv2d(8, out_channels, kernel_size=1) # 3-channel RGB output + + def forward(self, x): + x = F.relu(self.conv1(self.upconv1(x))) + x = F.relu(self.conv2(self.upconv2(x))) + x = F.relu(self.conv3(self.upconv3(x))) + x = F.relu(self.conv4(self.upconv4(x))) + x = self.conv5(self.upconv5(x)) # No activation; apply outside + return x diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py new file mode 100644 index 0000000..16cf95d --- /dev/null +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -0,0 +1,75 @@ +import torch.nn.functional as F +import torch +import torch.nn as nn +from torch.autograd import Variable +from math import exp + + +class L1SSIMLoss(nn.Module): + def __init__(self, lambda_dssim: float = 0.5): + super().__init__() + self.lambda_dssim = lambda_dssim + + def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: + + Ll1 = F.l1_loss(image, target_image, reduction='mean') + + ssim_loss = 1.0 - ssim(image, target_image) + + total_loss = (1.0 - self.lambda_dssim) * Ll1 + \ + self.lambda_dssim * ssim_loss + return total_loss + + + +def gaussian(window_size, sigma): + gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / + float(2 * sigma ** 2)) for x in range(window_size)]) + return gauss / gauss.sum() + + +def create_window(window_size, channel): + _1D_window = gaussian(window_size, 1.5).unsqueeze(1) + _2D_window = _1D_window.mm( + _1D_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable(_2D_window.expand( + channel, 1, window_size, window_size).contiguous()) + return window + + +def ssim(img1, img2, window_size=11, size_average=True): + channel = img1.size(-3) + window = create_window(window_size, channel) + + if img1.is_cuda: + window = window.cuda(img1.get_device()) + window = window.type_as(img1) + + return _ssim(img1, img2, window, window_size, channel, size_average) + + +def _ssim(img1, img2, window, window_size, channel, size_average=True): + mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) + mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, + padding=window_size // 2, groups=channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, + padding=window_size // 2, groups=channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, + padding=window_size // 2, groups=channel) - mu1_mu2 + + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / \ + ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + + if size_average: + return ssim_map.mean() + else: + return ssim_map.mean(1).mean(1).mean(1) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py new file mode 100644 index 0000000..19e626f --- /dev/null +++ b/stain_normalization/stain_normalization_model.py @@ -0,0 +1,68 @@ +from collections import defaultdict + +import torch +from lightning import LightningModule +from torch import Tensor, nn +from torch.optim.optimizer import Optimizer +from stain_normalization.modeling import L1SSIMLoss +from stain_normalization.typing import Input, Outputs +from torch.optim import Adam +from torch.optim.optimizer import Optimizer +from torchmetrics import PeakSignalNoiseRatio,StructuralSimilarityIndexMeasure, MetricCollection + +class StainNormalizationModel(LightningModule): + def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: + super().__init__() + self.backbone = backbone + self.decode_head = decode_head + self.criterion = L1SSIMLoss() + + self.val_metrics = MetricCollection( + { + "ssim": StructuralSimilarityIndexMeasure(), + "psnr": PeakSignalNoiseRatio() + } + ) + self.test_metrics = self.val_metrics.clone(prefix="test/") + self.val_metrics.prefix = "validation/" + + def forward(self, x: Input) -> Outputs: + features = self.backbone(x) + return self.decode_head(features) + + def training_step(self, batch: Input) -> Tensor: + inputs, targets = batch + outputs = self(inputs) + + loss = self.criterion(outputs, targets) + self.log("train/loss", loss, on_step=True, prog_bar=True) + + return loss + + def validation_step(self, batch: Input) -> None: + inputs, targets = batch + outputs = self(inputs) + + loss = self.criterion(outputs, targets) + self.log("validation/loss", loss, on_step=False, on_epoch=True) + self.val_metrics.update(outputs, targets) + self.log_dict( + self.val_metrics, + batch_size=len(inputs), + on_epoch=True, + ) + + + def test_step(self, batch: Input) -> None: + inputs, targets = batch + outputs = self(inputs) + self.test_metrics.update(outputs, targets) + self.log_dict( + self.test_metrics, + batch_size=len(inputs), + on_epoch=True, + ) + + + def configure_optimizers(self) -> Optimizer: + return Adam(self.parameters(), lr=1e-4) diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py new file mode 100644 index 0000000..0216ae3 --- /dev/null +++ b/stain_normalization/typing.py @@ -0,0 +1,20 @@ +from typing import TypeAlias, TypedDict + +from torch import Tensor + +# class Metadata(TypedDict): +# slide: str +# x: int +# y: int +# transormation: str +# PredictSample: TypeAlias = tuple[Tensor, Metadata] +# Sample: TypeAlias = tuple[Tensor, Tensor, Metadata] + +PredictSample: TypeAlias = tuple[Tensor] +Sample: TypeAlias = tuple[Tensor, Tensor] + +Input: TypeAlias = Sample + +Outputs: TypeAlias = Tensor + + diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 6479e1f..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,51 +0,0 @@ -import numpy as np -import pytest -from numpy.typing import NDArray -from PIL import Image -from skimage.color import rgb2lab - -from rationai.staining.typing import RGBArray, StainArray - - -def stain2lab(stain: StainArray) -> NDArray[np.float64]: - """Converts a pixel in stain space to LAB space.""" - stain = np.maximum(stain, 1e-6) - rgb = np.exp(stain) - - return rgb2lab(rgb) - - -@pytest.fixture -def white() -> RGBArray: - """Returns an array with all-white RBG image of size (512, 512).""" - return np.full(shape=(512, 512, 3), dtype=np.uint8, fill_value=255) - - -@pytest.fixture -def black() -> RGBArray: - """Returns an array with all-black RBG image of size (512, 512).""" - return np.full(shape=(512, 512, 3), dtype=np.uint8, fill_value=0) - - -@pytest.fixture -def sample1_original() -> RGBArray: - """Returns original of the sample1 image.""" - return np.asarray(Image.open("tests/data/sample1/original.jpg")) - - -@pytest.fixture -def sample1_hematoxylin() -> NDArray[np.uint8]: - """Returns hematoxylin channel of the sample1 image (created by QuPath).""" - return np.asarray(Image.open("tests/data/sample1/hematoxylin.png")) - - -@pytest.fixture -def sample1_eosin() -> NDArray[np.uint8]: - """Returns eosin channel of the sample1 image (created by QuPath).""" - return np.asarray(Image.open("tests/data/sample1/eosin.png")) - - -@pytest.fixture -def sample1_residual() -> NDArray[np.uint8]: - """Returns residual channel of the sample1 image (created by QuPath).""" - return np.asarray(Image.open("tests/data/sample1/residual.png")) diff --git a/tests/data/generated/h_dab.png b/tests/data/generated/h_dab.png deleted file mode 100644 index 973134f479e972613496c065dbafc4bf5f59431f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14855 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 diff --git a/tests/data/generated/h_dab_legacy.png b/tests/data/generated/h_dab_legacy.png deleted file mode 100644 index 270e45f78e889780ffde33bf52159f12b7a5f2bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14366 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 diff --git a/tests/data/generated/h_e.png b/tests/data/generated/h_e.png deleted file mode 100644 index 951b6697b379c00ca08849f1a59bcad3eb42136b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14366 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 diff --git a/tests/data/sample1/eosin.png b/tests/data/sample1/eosin.png deleted file mode 100644 index dbbc43e1f89585ce9131b62cd408bfda68fb7c76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183161 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

    u=Q|CJeHjO9#3ae8&I170Leij+2Yt_Z60Pl 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ðd36n2EjZ-UN$)p6e&HA65pPz`p!x#VGw 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%0D!$GQYU4*;Z`bAoerYjA`A>BV4s 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 IM6N<$g7Ww23IG5A diff --git a/tests/data/sample1/original.jpg b/tests/data/sample1/original.jpg deleted file mode 100644 index 41a0c97bcee644e2ad1ca46101bbf8d14e30cb1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83398 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 NDArray[np.float64]: - low, high = np.min(x), np.max(x) - - return (x - low) * (up - down) / (high - low) + down - - -def _noise_array( - size: int, params: list[tuple[int | None, float]] -) -> NDArray[np.float64]: - result = np.zeros(shape=(size, size), dtype=np.float64) - - for seed, octaves in params: - noise = PerlinNoise(octaves=octaves, seed=seed) - - arr = np.array( - [[noise([i / size, j / size]) for j in range(size)] for i in range(size)], - dtype=np.float64, - ) - arr = _stretch(arr, -1, 1) - result += arr - - result[result < 0] = 1 - result[(result >= 0) & (result < 0.5)] = 2 - result[(result >= 0.5) & (result < 0.85)] = 3 - result[(result >= 0.85) & (result < 1)] = 4 - - return result - - -def artificial_image(c0: RGBArray, c1: RGBArray, conv: ColorConversion) -> RGBArray: - noise = _noise_array(size=512, params=[(None, 10), (None, 4)]) - - c0_pure = convert_color(c0, conv)[0] - c1_pure = convert_color(c1, conv)[1] - - c0_noise = np.where((noise == 3) | (noise == 4), c0_pure, 0) - c1_noise = np.where((noise >= 2) & (noise < 4), c1_pure, 0) - - img = np.stack([c0_noise, c1_noise, ZEROS], axis=-1) - - return np.asarray(convert_color(img, conv.inverse), dtype=np.uint8) - - -def main() -> None: - h_e = artificial_image(H_RGB, E_RGB, ColorConversion.RGB2HER) - Image.fromarray(h_e).save("tests/data/generated/h_e.png") - - h_dab_legacy = artificial_image(H_RGB, DAB_RGB, ColorConversion.RGB2HDR_LEGACY) - Image.fromarray(h_dab_legacy).save("tests/data/generated/h_dab_legacy.png") - - h_dab = artificial_image(LIGHT_H_RGB, DAB_RGB, ColorConversion.RGB2HDR) - Image.fromarray(h_dab).save("tests/data/generated/h_dab.png") - - -if __name__ == "__main__": - main() diff --git a/tests/test_color_conversion.py b/tests/test_color_conversion.py deleted file mode 100644 index 302d421..0000000 --- a/tests/test_color_conversion.py +++ /dev/null @@ -1,32 +0,0 @@ -import numpy as np -import pytest - -from rationai.staining import ColorConversion -from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H -from rationai.staining.typing import StainTuple -from rationai.staining.utils import residual - - -@pytest.mark.parametrize( - "conversion", - ColorConversion, - ids=(conversion.name for conversion in ColorConversion), -) -def test_inverse_conversion(conversion: ColorConversion) -> None: - original = conversion.matrix - inverse = conversion.inverse.matrix - - assert np.all(np.isclose(original, np.linalg.inv(inverse))) - - -STAINS = [ - # Expected values are taken from QuPath - (QUPATH_H, QUPATH_E, (0.316, -0.598, 0.737)), - (LIGHT_H, QUPATH_DAB, (0.418, -0.796, 0.437)), - (QUPATH_H, QUPATH_DAB, (0.633, -0.713, 0.302)), -] - - -@pytest.mark.parametrize("s0,s1,expected", STAINS, ids=["H&E", "H&DAB", "H&DAB_LEGACY"]) -def test_residual(s0: StainTuple, s1: StainTuple, expected: StainTuple) -> None: - assert np.all(np.isclose(residual(s0, s1), expected, atol=0.001)) diff --git a/tests/test_modify_and_reconstruct.py b/tests/test_modify_and_reconstruct.py deleted file mode 100644 index f9c2a86..0000000 --- a/tests/test_modify_and_reconstruct.py +++ /dev/null @@ -1,61 +0,0 @@ -import numpy as np -import pytest -from numpy.typing import NDArray -from skimage.data import immunohistochemistry -from skimage.metrics import structural_similarity - -from rationai.staining import modify_and_reconstruct -from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H -from rationai.staining.typing import ModifyFunction, RGBArray, StainTuple - - -C = NDArray[np.float64] - - -def _no_change(c0: C, c1: C, c2: C) -> tuple[C, C, C]: - return c0, c1, c2 - - -IMAGES_AND_STAINS = [ - ( - immunohistochemistry(), - _no_change, - LIGHT_H, - QUPATH_DAB, - None, - ), - ( - "sample1_original", - _no_change, - QUPATH_H, - QUPATH_E, - None, - ), -] - -TEST_IDS = ["skimage-default; no change", "Sample1; no change"] - - -@pytest.mark.parametrize( - "original,modify,stain0,stain1,stain2", IMAGES_AND_STAINS, ids=TEST_IDS -) -def test_modify_and_reconstruct( - original: RGBArray | str, - modify: ModifyFunction, - stain0: StainTuple, - stain1: StainTuple, - stain2: StainTuple, - request: pytest.FixtureRequest, -) -> None: - if isinstance(original, str): - original = request.getfixturevalue(original) - - reconstructed = modify_and_reconstruct( - tile=original, # type: ignore[arg-type] - modify=modify, - stain0=stain0, - stain1=stain1, - stain2=stain2, - ) - - assert structural_similarity(original, reconstructed, channel_axis=-1) > 0.99 diff --git a/tests/test_stain_estimator.py b/tests/test_stain_estimator.py deleted file mode 100644 index 83e390e..0000000 --- a/tests/test_stain_estimator.py +++ /dev/null @@ -1,121 +0,0 @@ -from pathlib import Path -from typing import Any - -import numpy as np -import pytest -from conftest import stain2lab -from numpy.typing import NDArray -from PIL import Image -from skimage.color import deltaE_ciede2000 -from skimage.data import immunohistochemistry -from skimage.filters import gaussian - -from rationai.staining import ColorConversion, convert_color, estimate_stain_vectors -from rationai.staining.constants import LIGHT_H, QUPATH_DAB, QUPATH_E, QUPATH_H -from rationai.staining.typing import StainArray, Tile - - -ZEROS = np.zeros(shape=(512, 512), dtype=np.float64) - - -H_RGB = np.array([88, 76, 180], dtype=np.uint8) # from QuPath -E_RGB = np.array([199, 50, 112], dtype=np.uint8) # from QuPath -DAB_RGB = np.array([186, 110, 56], dtype=np.uint8) # from QuPath - - -NANS = np.full(shape=(3), fill_value=np.nan) - -GENERATED_DIR = Path("tests/data/generated") - - -def _blur(img: NDArray[np.uint8], sigma: float) -> NDArray[np.uint8]: - result = np.empty_like(img) - channels = [img[..., 0], img[..., 1], img[..., 2]] - - for i, c in enumerate(channels): - result[..., i] = (255 * gaussian(c, sigma=sigma)).astype(np.uint8) - - return result - - -# Input, first expected stain, second expected stain -DATA = [ - ( - immunohistochemistry(), - QUPATH_H, - QUPATH_DAB, - ), - ( - np.asarray(Image.open(GENERATED_DIR / "h_e.png")), - QUPATH_H, - QUPATH_E, - ), - ( - np.asarray(Image.open(GENERATED_DIR / "h_dab.png")), - LIGHT_H, - QUPATH_DAB, - ), - ( - np.asarray(Image.open(GENERATED_DIR / "h_dab_legacy.png")), - QUPATH_H, - QUPATH_DAB, - ), - ( - _blur(np.asarray(Image.open(GENERATED_DIR / "h_e.png")), sigma=5), - QUPATH_H, - QUPATH_E, - ), - ( - _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab.png")), sigma=5), - LIGHT_H, - QUPATH_DAB, - ), - ( - _blur(np.asarray(Image.open(GENERATED_DIR / "h_dab_legacy.png")), sigma=5), - QUPATH_H, - QUPATH_DAB, - ), - ( - convert_color(np.stack([ZEROS] * 3, axis=-1), ColorConversion.HER2RGB), - NANS, - NANS, - ), -] - -IDS = [ - "Default skimage image H&DAB_LEGACY", - "Artificial H&E", - "Artificial H&DAB", - "Artificial H&DAB_LEGACY", - "Blurred Artificial H&E", - "Blurred Artificial H&DAB", - "Blurred Artificial H&DAB_LEGACY", - "Empty Image", -] - - -@pytest.mark.parametrize("img,expected1,expected2", DATA, ids=IDS) -class TestStainEstimator: - @staticmethod - def _both_nan(x: NDArray[Any], y: NDArray[Any]) -> bool: - return bool(np.isnan(x).all()) and bool(np.isnan(y).all()) - - def test_estimation_vector_similarity( - self, img: Tile, expected1: StainArray, expected2: StainArray - ) -> None: - stain1, stain2 = estimate_stain_vectors(img) - - assert np.dot(stain1, expected1) > 0.97 or self._both_nan(stain1, expected1) - assert np.dot(stain2, expected2) > 0.97 or self._both_nan(stain2, expected2) - - def test_estimation_color_difference( - self, img: Tile, expected1: StainArray, expected2: StainArray - ) -> None: - stain1, stain2 = estimate_stain_vectors(img) - delta = deltaE_ciede2000 - - stain1, stain2 = stain2lab(stain1), stain2lab(stain2) - expected1, expected2 = stain2lab(expected1), stain2lab(expected2) - - assert delta(stain1, expected1) < 15 or self._both_nan(stain1, expected1) - assert delta(stain2, expected2) < 15 or self._both_nan(stain2, expected2) diff --git a/tests/test_stain_reconstruction.py b/tests/test_stain_reconstruction.py deleted file mode 100644 index 323a764..0000000 --- a/tests/test_stain_reconstruction.py +++ /dev/null @@ -1,44 +0,0 @@ -import numpy as np -import pytest -from skimage.data import immunohistochemistry -from skimage.metrics import structural_similarity - -from rationai.staining import ColorConversion, convert_color -from rationai.staining.typing import RGBArray - - -IMAGES_AND_CONVS = [ - ( - immunohistochemistry(), - ColorConversion.RGB2HDR, - ), - ( - immunohistochemistry(), - ColorConversion.RGB2HDR_LEGACY, - ), - ( - "sample1_original", - ColorConversion.RGB2HER, - ), -] - -TEST_IDS = ["skimage-default; H&DAB", "skimage-default; H&DAB_LEGACY", "Sample1; H&E"] - - -@pytest.mark.parametrize("original,conv", IMAGES_AND_CONVS, ids=TEST_IDS) -def test_structural_similarity( - original: RGBArray | str, conv: ColorConversion, request: pytest.FixtureRequest -) -> None: - """For reconstruction, only structural similarity is tested. - - Due to implementation details, the reconsturction is not idempotent, - and some bigger color shifts can occur in some conversions. - Therefore, the color similarity cannot be reliably tested. - """ - if isinstance(original, str): - original = request.getfixturevalue(original) - - c0, c1, c2 = convert_color(original, conv) # type: ignore[arg-type] - reconstructed = convert_color(np.stack([c0, c1, c2], axis=-1), conv.inverse) - - assert structural_similarity(original, reconstructed, channel_axis=-1) > 0.95 diff --git a/tests/test_stain_separation.py b/tests/test_stain_separation.py deleted file mode 100644 index ecca7d8..0000000 --- a/tests/test_stain_separation.py +++ /dev/null @@ -1,53 +0,0 @@ -import numpy as np -import pytest -from numpy.typing import NDArray -from skimage.metrics import structural_similarity - -from rationai.staining import ColorConversion, convert_color -from rationai.staining.typing import RGBArray, StainArray - - -RGB_CONVERSIONS = [ - ColorConversion.RGB2HER, - ColorConversion.RGB2HDR, - ColorConversion.RGB2HDR_LEGACY, -] -RGB_NAMES = [c.name for c in RGB_CONVERSIONS] - - -@pytest.mark.parametrize("conversion", RGB_CONVERSIONS, ids=RGB_NAMES) -def test_black_image(black: RGBArray, conversion: ColorConversion) -> None: - c0, c1, c2 = convert_color(black, conversion) - - rgb2stain = np.stack(conversion.value[0]) - expected_values = np.sum(rgb2stain, axis=0) - - assert np.all(c0 == expected_values[0]) - assert np.all(c1 == expected_values[1]) - assert np.all(c2 == expected_values[2]) - - -@pytest.mark.parametrize("conversion", RGB_CONVERSIONS, ids=RGB_NAMES) -def test_white_image(white: RGBArray, conversion: ColorConversion) -> None: - c0, c1, c2 = convert_color(white, conversion) - - assert np.all(c0 == 0) - assert np.all(c1 == 0) - assert np.all(c2 == 0) - - -def test_real_sample1_image( - sample1_original: RGBArray, - sample1_hematoxylin: StainArray, - sample1_eosin: StainArray, - sample1_residual: StainArray, -) -> None: - h, e, r = convert_color(sample1_original, ColorConversion.RGB2HER) - - assert structural_similarity(_prepare(h), sample1_hematoxylin) > 0.95 - assert structural_similarity(_prepare(e), sample1_eosin) > 0.95 - assert structural_similarity(_prepare(r), sample1_residual) > 0.95 - - -def _prepare(c: NDArray[np.float64]) -> NDArray[np.uint8]: - return (255 * (c / np.max(c))).astype(np.uint8) From 844d765ff95ae82a4297f833ffe1d2cde28e8554 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 00:56:57 +0000 Subject: [PATCH 27/79] fix: transformations inputs --- configs/data/modify/test.yaml | 14 ++++---- configs/data/modify/train.yaml | 14 ++++---- configs/data/transforms/train.yaml | 11 +----- configs/default.yaml | 4 +-- .../data/transformation/__init__.py | 4 +-- .../transformation/combiend_modification.py | 16 +++++---- .../transformation/exposure_adjustment.py | 10 ++++-- .../data/transformation/hed_factor.py | 2 +- .../data/transformation/hue_shift.py | 34 ------------------ .../data/transformation/hvs_modification.py | 35 +++++++++++++++++++ 10 files changed, 74 insertions(+), 70 deletions(-) delete mode 100644 stain_normalization/data/transformation/hue_shift.py create mode 100644 stain_normalization/data/transformation/hvs_modification.py diff --git a/configs/data/modify/test.yaml b/configs/data/modify/test.yaml index c8d3ae7..d69792c 100644 --- a/configs/data/modify/test.yaml +++ b/configs/data/modify/test.yaml @@ -1,12 +1,14 @@ _target_: albumentations.OneOf transforms: - - _target_: stain_normalization.data.transformation.HED + - _target_: stain_normalization.data.transformation.HEDFactor h_range: [0.8, 1.2] e_range: [0.8, 1.2] - _target_: stain_normalization.data.transformation.ExposureAdjustment brightness_range: [0.8, 1.2] - - _target_: UnnaturalColorModification - hue_shift_range: [0.2, 1.0] - - _target_: CombinedModifications - brightness_range: [-0.4, 0.4] - intensity_range: [0.65, 1.35] \ No newline at end of file + - _target_: stain_normalization.data.transformation.HVSModification + hue_shift_range: [-0.4, 0.4] + saturation_range: [0.8, 1.5] + value_range: [0.8, 1.3] + - _target_: stain_normalization.data.transformation.CombinedModifications + intensity_range: [0.65, 1.35] + brightness_range: [-0.4, 0.4] \ No newline at end of file diff --git a/configs/data/modify/train.yaml b/configs/data/modify/train.yaml index c8d3ae7..d69792c 100644 --- a/configs/data/modify/train.yaml +++ b/configs/data/modify/train.yaml @@ -1,12 +1,14 @@ _target_: albumentations.OneOf transforms: - - _target_: stain_normalization.data.transformation.HED + - _target_: stain_normalization.data.transformation.HEDFactor h_range: [0.8, 1.2] e_range: [0.8, 1.2] - _target_: stain_normalization.data.transformation.ExposureAdjustment brightness_range: [0.8, 1.2] - - _target_: UnnaturalColorModification - hue_shift_range: [0.2, 1.0] - - _target_: CombinedModifications - brightness_range: [-0.4, 0.4] - intensity_range: [0.65, 1.35] \ No newline at end of file + - _target_: stain_normalization.data.transformation.HVSModification + hue_shift_range: [-0.4, 0.4] + saturation_range: [0.8, 1.5] + value_range: [0.8, 1.3] + - _target_: stain_normalization.data.transformation.CombinedModifications + intensity_range: [0.65, 1.35] + brightness_range: [-0.4, 0.4] \ No newline at end of file diff --git a/configs/data/transforms/train.yaml b/configs/data/transforms/train.yaml index 81162f1..4cec39f 100644 --- a/configs/data/transforms/train.yaml +++ b/configs/data/transforms/train.yaml @@ -4,13 +4,4 @@ transforms: p: 1.0 - _target_: albumentations.Flip p: 0.75 - - _target_: albumentations.RandomGamma - p: 0.5 - - _target_: albumentations.RandomBrightnessContrast - p: 0.5 - - _target_: albumentations.HueSaturationValue - p: 0.5 - - _target_: albumentations.Normalize - mean: [198.9923, 156.7051, 185.0198] - std: [36.8293, 46.7353, 35.8960] - max_pixel_value: 1 + diff --git a/configs/default.yaml b/configs/default.yaml index 79092e5..42230e2 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -29,8 +29,8 @@ data: metadata: user: xlopatka - experiment_name: Stain Normalization - run_name: Test Stain Normalization + experiment_name: Stain-Normalization + run_name: Testing #First Train Stain Normalization description: Testing Stain Normalization hyperparams: {} diff --git a/stain_normalization/data/transformation/__init__.py b/stain_normalization/data/transformation/__init__.py index 5e28fc7..b817f7b 100644 --- a/stain_normalization/data/transformation/__init__.py +++ b/stain_normalization/data/transformation/__init__.py @@ -1,7 +1,7 @@ from stain_normalization.data.transformation.hed_factor import HEDFactor from stain_normalization.data.transformation.exposure_adjustment import ExposureAdjustment -from stain_normalization.data.transformation.hue_shift import HueShift +from stain_normalization.data.transformation.hvs_modification import HVSModification from stain_normalization.data.transformation.combiend_modification import CombinedModifications -__all__ = ["HEDFactor", "ExposureAdjustment", "HueShift", "CombinedModifications"] +__all__ = ["HEDFactor", "ExposureAdjustment", "HVSModification", "CombinedModifications"] diff --git a/stain_normalization/data/transformation/combiend_modification.py b/stain_normalization/data/transformation/combiend_modification.py index d893f3f..610ebcb 100644 --- a/stain_normalization/data/transformation/combiend_modification.py +++ b/stain_normalization/data/transformation/combiend_modification.py @@ -1,6 +1,7 @@ import numpy as np from albumentations import ImageOnlyTransform from skimage import exposure +from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed class CombinedModifications(ImageOnlyTransform): @@ -9,15 +10,18 @@ def __init__(self, intensity_range=(0.4, 1.5), brightness_range=(-0.4, 0.4), alw self.intensity_range = intensity_range self.brightness_range = brightness_range - def apply(self, img, **params): + def apply(self, hed_img, **params): def modify_channel(channel, intensity_range, brightness_range): intensity_scale = np.random.uniform(*intensity_range) channel = channel * intensity_scale brightness_shift = np.random.uniform(*brightness_range) channel = exposure.adjust_gamma(channel, gamma=1 + brightness_shift) return np.clip(channel, 0, 1) - - h = modify_channel(img[:, :, 0], self.intensity_range, self.brightness_range) - e = modify_channel(img[:, :, 1], self.intensity_range, self.brightness_range) - d = img[:, :, 2] # Skip modification for D channel - return np.stack((h, e, d), axis=-1) \ No newline at end of file + + hed_image = separate_stains(hed_img, hed_from_rgb) + h = modify_channel(hed_image[:, :, 0], self.intensity_range, self.brightness_range) + e = modify_channel(hed_image[:, :, 1], self.intensity_range, self.brightness_range) + d = hed_image[:, :, 2] # Skip modification for D channel + + modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) + return modified_rgb \ No newline at end of file diff --git a/stain_normalization/data/transformation/exposure_adjustment.py b/stain_normalization/data/transformation/exposure_adjustment.py index 71af622..4cc9a41 100644 --- a/stain_normalization/data/transformation/exposure_adjustment.py +++ b/stain_normalization/data/transformation/exposure_adjustment.py @@ -1,5 +1,6 @@ import numpy as np from albumentations import ImageOnlyTransform +from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed class ExposureAdjustment(ImageOnlyTransform): @@ -8,10 +9,13 @@ def __init__(self, brightness_range: tuple[float, float] = (0.8, 1.2), always_ap self.brightness_range = brightness_range def apply(self, img, **params): + hed_img = separate_stains(img, hed_from_rgb) + brightness_factor = np.random.uniform(*self.brightness_range) - h, e, d = img[:, :, 0], img[:, :, 1], img[:, :, 2] + h, e, d = hed_img[:, :, 0], hed_img[:, :, 1], hed_img[:, :, 2] h = np.clip(h * brightness_factor, 0, 1) e = np.clip(e * brightness_factor, 0, 1) d = np.clip(d * brightness_factor, 0, 1) - return np.stack((h, e, d), axis=-1) - + + modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) + return modified_rgb diff --git a/stain_normalization/data/transformation/hed_factor.py b/stain_normalization/data/transformation/hed_factor.py index 13d668b..80af22d 100644 --- a/stain_normalization/data/transformation/hed_factor.py +++ b/stain_normalization/data/transformation/hed_factor.py @@ -12,7 +12,7 @@ def __init__(self, self.h_range = h_range self.e_range = e_range - def apply(self, img, **params): + def apply(self, img, **params): h_factor = np.random.uniform(*self.h_range) e_factor = np.random.uniform(*self.e_range) diff --git a/stain_normalization/data/transformation/hue_shift.py b/stain_normalization/data/transformation/hue_shift.py deleted file mode 100644 index b6708eb..0000000 --- a/stain_normalization/data/transformation/hue_shift.py +++ /dev/null @@ -1,34 +0,0 @@ - - -import numpy as np -from albumentations import ImageOnlyTransform -from skimage.color import ( - rgb2hsv, hsv2rgb, - rgb2hed, hed2rgb -) - - -class HueShift(ImageOnlyTransform): - def __init__(self, hue_shift_range: tuple[float, float] = (0.0, 1.0), always_apply: bool = True, p: float = 1): - super().__init__(always_apply, p) - self.hue_shift_range = hue_shift_range - - def apply(self, img, **params): - hue_shift = np.random.uniform(*self.hue_shift_range) - - h, e, d = img[:, :, 0], img[:, :, 1], img[:, :, 2] - h_mod = np.clip(h * e, 0, 1) - e_mod = np.clip(e * 1, 0, 1) - d_mod = np.clip(d * 1, 0, 1) - - hed_mod = np.stack((h_mod, e_mod, d_mod), axis=-1) - - rgb_image = hed2rgb(hed_mod) - hsv_image = rgb2hsv(rgb_image) - - # Apply the random hue shift - hsv_image[:, :, 0] = (hsv_image[:, :, 0] + hue_shift) % 1.0 - - modified_rgb = hsv2rgb(hsv_image) - return rgb2hed(modified_rgb) - diff --git a/stain_normalization/data/transformation/hvs_modification.py b/stain_normalization/data/transformation/hvs_modification.py new file mode 100644 index 0000000..21e36d5 --- /dev/null +++ b/stain_normalization/data/transformation/hvs_modification.py @@ -0,0 +1,35 @@ + + +import numpy as np +from albumentations import ImageOnlyTransform +from skimage.color import rgb2hsv, hsv2rgb + + +class HVSModification(ImageOnlyTransform): + def __init__( + self, + hue_shift_range: tuple[float, float] = (-0.2, 0.2), + saturation_range: tuple[float, float] = (0.8, 1.5), + value_range: tuple[float, float] = (0.8, 1.3), + always_apply: bool = True, + p: float = 1.0 + ): + + super().__init__(always_apply, p) + self.hue_shift_range = hue_shift_range + self.saturation_range = saturation_range + self.value_range = value_range + + def apply(self, img, **params): + hue_shift = np.random.uniform(*self.hue_shift_range) + saturation_scale = np.random.uniform(*self.saturation_range) + value_scale = np.random.uniform(*self.value_range) + + hsv_image = rgb2hsv(img) + hsv_image[:, :, 0] = (hsv_image[:, :, 0] + hue_shift) % 1.0 + hsv_image[:, :, 1] = np.clip(hsv_image[:, :, 1] * saturation_scale, 0, 1) + hsv_image[:, :, 2] = np.clip(hsv_image[:, :, 2] * value_scale, 0, 1) + + modified_rgb = hsv2rgb(hsv_image) + + return modified_rgb \ No newline at end of file From fc427f83425a9ed346d4fcecc759ba2dc55970e8 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 00:57:48 +0000 Subject: [PATCH 28/79] chore: added data link --- configs/data/datasets/stain_normalization/test.yaml | 2 +- configs/data/datasets/stain_normalization/train.yaml | 4 ++-- configs/data/datasets/stain_normalization/val.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml index 311cda0..78dabba 100644 --- a/configs/data/datasets/stain_normalization/test.yaml +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -3,4 +3,4 @@ defaults: - /data/modify@modify: test _target_: stain_normalization.data.datasets.StainNormalization -uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test/tiles.parquet"] +uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test"] diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml index 3d99dad..5a7feec 100644 --- a/configs/data/datasets/stain_normalization/train.yaml +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -1,6 +1,6 @@ defaults: - - /data/transforms@transforms: train + # - /data/transforms@transforms: train - /data/modify@modify: train _target_: stain_normalization.data.datasets.StainNormalization -uris: ["mlflow-artifacts:"] +uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - train"] diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index 53e608c..142cfb8 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -3,5 +3,5 @@ defaults: - /data/modify@modify: test _target_: stain_normalization.data.datasets.StainNormalization -uris: ["mlflow-artifacts:"] +uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - val"] From f039733acbc0058923a4cadb66113780362847c3 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 01:05:35 +0000 Subject: [PATCH 29/79] fix: resolve issues before job run --- configs/data/transforms/train copy.yaml | 16 + configs/model/decode_head/unet2048.yaml | 1 - configs/model/decode_head/unet512.yaml | 1 - job.py | 18 + pdm.lock | 2599 ++++++++++++----- pyproject.toml | 35 +- stain_normalization/{main.py => __main__.py} | 0 .../data/datasets/stain_normalization.py | 22 +- stain_normalization/modeling/__init__.py | 1 - .../modeling/backbone/vgg16.py | 2 +- .../stain_normalization_model.py | 8 +- 11 files changed, 1863 insertions(+), 840 deletions(-) create mode 100644 configs/data/transforms/train copy.yaml create mode 100644 job.py rename stain_normalization/{main.py => __main__.py} (100%) diff --git a/configs/data/transforms/train copy.yaml b/configs/data/transforms/train copy.yaml new file mode 100644 index 0000000..81162f1 --- /dev/null +++ b/configs/data/transforms/train copy.yaml @@ -0,0 +1,16 @@ +_target_: albumentations.Compose +transforms: + - _target_: albumentations.RandomRotate90 + p: 1.0 + - _target_: albumentations.Flip + p: 0.75 + - _target_: albumentations.RandomGamma + p: 0.5 + - _target_: albumentations.RandomBrightnessContrast + p: 0.5 + - _target_: albumentations.HueSaturationValue + p: 0.5 + - _target_: albumentations.Normalize + mean: [198.9923, 156.7051, 185.0198] + std: [36.8293, 46.7353, 35.8960] + max_pixel_value: 1 diff --git a/configs/model/decode_head/unet2048.yaml b/configs/model/decode_head/unet2048.yaml index 1936549..00a4921 100644 --- a/configs/model/decode_head/unet2048.yaml +++ b/configs/model/decode_head/unet2048.yaml @@ -1,5 +1,4 @@ decode_head: _target_: stain_normalization.modeling.decode_head.UNetDecoder in_channels: 2048 - weights: null diff --git a/configs/model/decode_head/unet512.yaml b/configs/model/decode_head/unet512.yaml index d3461f1..531bf9f 100644 --- a/configs/model/decode_head/unet512.yaml +++ b/configs/model/decode_head/unet512.yaml @@ -1,5 +1,4 @@ decode_head: _target_: stain_normalization.modeling.decode_head.UNetDecoder in_channels: 512 - weights: null diff --git a/job.py b/job.py new file mode 100644 index 0000000..20b4bf4 --- /dev/null +++ b/job.py @@ -0,0 +1,18 @@ +from kube_jobs import Storage, submit_job + + +submit_job( + job_name="some name", + username="your name", + cpu=10, + memory="128Gi", + gpu="A40", + script=[ + "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/... workdir", + "cd workdir", + "git checkout develop", + "pdm sync --skip=post_install", + "pdm fit model/backbone=resnet18", + ], + storage=Storage(mou=True), +) diff --git a/pdm.lock b/pdm.lock index 395416d..57e651c 100644 --- a/pdm.lock +++ b/pdm.lock @@ -3,78 +3,104 @@ [metadata] groups = ["default", "dev"] -strategy = [] -lock_version = "4.4" -content_hash = "sha256:24e67ec88809826b854439f3edd657a4285070b448d3ae0add27a80782d3b633" +strategy = ["inherit_metadata"] +lock_version = "4.5.0" +content_hash = "sha256:b6548b53106f41b522b88929821234d14bbde40c39c47dafe1e38851ca0ec4e9" + +[[metadata.targets]] +requires_python = ">=3.11" [[package]] name = "aiohappyeyeballs" -version = "2.3.6" -requires_python = ">=3.8" +version = "2.5.0" +requires_python = ">=3.9" summary = "Happy Eyeballs for asyncio" +groups = ["default"] files = [ - {file = "aiohappyeyeballs-2.3.6-py3-none-any.whl", hash = "sha256:15dca2611fa78442f1cb54cf07ffb998573f2b4fbeab45ca8554c045665c896b"}, - {file = "aiohappyeyeballs-2.3.6.tar.gz", hash = "sha256:88211068d2a40e0436033956d7de3926ff36d54776f8b1022d6b21320cadae79"}, + {file = "aiohappyeyeballs-2.5.0-py3-none-any.whl", hash = "sha256:0850b580748c7071db98bffff6d4c94028d0d3035acc20fd721a0ce7e8cac35d"}, + {file = "aiohappyeyeballs-2.5.0.tar.gz", hash = "sha256:18fde6204a76deeabc97c48bdd01d5801cfda5d6b9c8bbeb1aaaee9d648ca191"}, ] [[package]] name = "aiohttp" -version = "3.10.3" -requires_python = ">=3.8" +version = "3.11.13" +requires_python = ">=3.9" summary = "Async http client/server framework (asyncio)" +groups = ["default"] dependencies = [ "aiohappyeyeballs>=2.3.0", "aiosignal>=1.1.2", + "async-timeout<6.0,>=4.0; python_version < \"3.11\"", "attrs>=17.3.0", "frozenlist>=1.1.1", "multidict<7.0,>=4.5", - "yarl<2.0,>=1.0", -] -files = [ - {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e021c4c778644e8cdc09487d65564265e6b149896a17d7c0f52e9a088cc44e1b"}, - {file = "aiohttp-3.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24fade6dae446b183e2410a8628b80df9b7a42205c6bfc2eff783cbeedc224a2"}, - {file = "aiohttp-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bc8e9f15939dacb0e1f2d15f9c41b786051c10472c7a926f5771e99b49a5957f"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5a9ec959b5381271c8ec9310aae1713b2aec29efa32e232e5ef7dcca0df0279"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a5d0ea8a6467b15d53b00c4e8ea8811e47c3cc1bdbc62b1aceb3076403d551f"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9ed607dbbdd0d4d39b597e5bf6b0d40d844dfb0ac6a123ed79042ef08c1f87e"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3e66d5b506832e56add66af88c288c1d5ba0c38b535a1a59e436b300b57b23e"}, - {file = "aiohttp-3.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fda91ad797e4914cca0afa8b6cccd5d2b3569ccc88731be202f6adce39503189"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:61ccb867b2f2f53df6598eb2a93329b5eee0b00646ee79ea67d68844747a418e"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d881353264e6156f215b3cb778c9ac3184f5465c2ece5e6fce82e68946868ef"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b031ce229114825f49cec4434fa844ccb5225e266c3e146cb4bdd025a6da52f1"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5337cc742a03f9e3213b097abff8781f79de7190bbfaa987bd2b7ceb5bb0bdec"}, - {file = "aiohttp-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab3361159fd3dcd0e48bbe804006d5cfb074b382666e6c064112056eb234f1a9"}, - {file = "aiohttp-3.10.3-cp311-cp311-win32.whl", hash = "sha256:05d66203a530209cbe40f102ebaac0b2214aba2a33c075d0bf825987c36f1f0b"}, - {file = "aiohttp-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:70b4a4984a70a2322b70e088d654528129783ac1ebbf7dd76627b3bd22db2f17"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:166de65e2e4e63357cfa8417cf952a519ac42f1654cb2d43ed76899e2319b1ee"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7084876352ba3833d5d214e02b32d794e3fd9cf21fdba99cff5acabeb90d9806"}, - {file = "aiohttp-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d98c604c93403288591d7d6d7d6cc8a63459168f8846aeffd5b3a7f3b3e5e09"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d73b073a25a0bb8bf014345374fe2d0f63681ab5da4c22f9d2025ca3e3ea54fc"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8da6b48c20ce78f5721068f383e0e113dde034e868f1b2f5ee7cb1e95f91db57"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a9dcdccf50284b1b0dc72bc57e5bbd3cc9bf019060dfa0668f63241ccc16aa7"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56fb94bae2be58f68d000d046172d8b8e6b1b571eb02ceee5535e9633dcd559c"}, - {file = "aiohttp-3.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf75716377aad2c718cdf66451c5cf02042085d84522aec1f9246d3e4b8641a6"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6c51ed03e19c885c8e91f574e4bbe7381793f56f93229731597e4a499ffef2a5"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b84857b66fa6510a163bb083c1199d1ee091a40163cfcbbd0642495fed096204"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c124b9206b1befe0491f48185fd30a0dd51b0f4e0e7e43ac1236066215aff272"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3461d9294941937f07bbbaa6227ba799bc71cc3b22c40222568dc1cca5118f68"}, - {file = "aiohttp-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08bd0754d257b2db27d6bab208c74601df6f21bfe4cb2ec7b258ba691aac64b3"}, - {file = "aiohttp-3.10.3-cp312-cp312-win32.whl", hash = "sha256:7f9159ae530297f61a00116771e57516f89a3de6ba33f314402e41560872b50a"}, - {file = "aiohttp-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:e1128c5d3a466279cb23c4aa32a0f6cb0e7d2961e74e9e421f90e74f75ec1edf"}, - {file = "aiohttp-3.10.3.tar.gz", hash = "sha256:21650e7032cc2d31fc23d353d7123e771354f2a3d5b05a5647fc30fea214e696"}, + "propcache>=0.2.0", + "yarl<2.0,>=1.17.0", +] +files = [ + {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b35aab22419ba45f8fc290d0010898de7a6ad131e468ffa3922b1b0b24e9d2e"}, + {file = "aiohttp-3.11.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81cba651db8795f688c589dd11a4fbb834f2e59bbf9bb50908be36e416dc760"}, + {file = "aiohttp-3.11.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f55d0f242c2d1fcdf802c8fabcff25a9d85550a4cf3a9cf5f2a6b5742c992839"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4bea08a6aad9195ac9b1be6b0c7e8a702a9cec57ce6b713698b4a5afa9c2e33"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6070bcf2173a7146bb9e4735b3c62b2accba459a6eae44deea0eb23e0035a23"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:718d5deb678bc4b9d575bfe83a59270861417da071ab44542d0fcb6faa686636"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f6b2c5b4a4d22b8fb2c92ac98e0747f5f195e8e9448bfb7404cd77e7bfa243f"}, + {file = "aiohttp-3.11.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:747ec46290107a490d21fe1ff4183bef8022b848cf9516970cb31de6d9460088"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:01816f07c9cc9d80f858615b1365f8319d6a5fd079cd668cc58e15aafbc76a54"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a08ad95fcbd595803e0c4280671d808eb170a64ca3f2980dd38e7a72ed8d1fea"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c97be90d70f7db3aa041d720bfb95f4869d6063fcdf2bb8333764d97e319b7d0"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ab915a57c65f7a29353c8014ac4be685c8e4a19e792a79fe133a8e101111438e"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:35cda4e07f5e058a723436c4d2b7ba2124ab4e0aa49e6325aed5896507a8a42e"}, + {file = "aiohttp-3.11.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:af55314407714fe77a68a9ccaab90fdb5deb57342585fd4a3a8102b6d4370080"}, + {file = "aiohttp-3.11.13-cp311-cp311-win32.whl", hash = "sha256:42d689a5c0a0c357018993e471893e939f555e302313d5c61dfc566c2cad6185"}, + {file = "aiohttp-3.11.13-cp311-cp311-win_amd64.whl", hash = "sha256:b73a2b139782a07658fbf170fe4bcdf70fc597fae5ffe75e5b67674c27434a9f"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2eabb269dc3852537d57589b36d7f7362e57d1ece308842ef44d9830d2dc3c90"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b77ee42addbb1c36d35aca55e8cc6d0958f8419e458bb70888d8c69a4ca833d"}, + {file = "aiohttp-3.11.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55789e93c5ed71832e7fac868167276beadf9877b85697020c46e9a75471f55f"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c929f9a7249a11e4aa5c157091cfad7f49cc6b13f4eecf9b747104befd9f56f2"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d33851d85537bbf0f6291ddc97926a754c8f041af759e0aa0230fe939168852b"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9229d8613bd8401182868fe95688f7581673e1c18ff78855671a4b8284f47bcb"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669dd33f028e54fe4c96576f406ebb242ba534dd3a981ce009961bf49960f117"}, + {file = "aiohttp-3.11.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1b20a1ace54af7db1f95af85da530fe97407d9063b7aaf9ce6a32f44730778"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5724cc77f4e648362ebbb49bdecb9e2b86d9b172c68a295263fa072e679ee69d"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:aa36c35e94ecdb478246dd60db12aba57cfcd0abcad43c927a8876f25734d496"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9b5b37c863ad5b0892cc7a4ceb1e435e5e6acd3f2f8d3e11fa56f08d3c67b820"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e06cf4852ce8c4442a59bae5a3ea01162b8fcb49ab438d8548b8dc79375dad8a"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5194143927e494616e335d074e77a5dac7cd353a04755330c9adc984ac5a628e"}, + {file = "aiohttp-3.11.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afcb6b275c2d2ba5d8418bf30a9654fa978b4f819c2e8db6311b3525c86fe637"}, + {file = "aiohttp-3.11.13-cp312-cp312-win32.whl", hash = "sha256:7104d5b3943c6351d1ad7027d90bdd0ea002903e9f610735ac99df3b81f102ee"}, + {file = "aiohttp-3.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:47dc018b1b220c48089b5b9382fbab94db35bef2fa192995be22cbad3c5730c8"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9862d077b9ffa015dbe3ce6c081bdf35135948cb89116e26667dd183550833d1"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbfef0666ae9e07abfa2c54c212ac18a1f63e13e0760a769f70b5717742f3ece"}, + {file = "aiohttp-3.11.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a1f7d857c4fcf7cabb1178058182c789b30d85de379e04f64c15b7e88d66fb"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba40b7ae0f81c7029583a338853f6607b6d83a341a3dcde8bed1ea58a3af1df9"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5b95787335c483cd5f29577f42bbe027a412c5431f2f80a749c80d040f7ca9f"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7d474c5c1f0b9405c1565fafdc4429fa7d986ccbec7ce55bc6a330f36409cad"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e83fb1991e9d8982b3b36aea1e7ad27ea0ce18c14d054c7a404d68b0319eebb"}, + {file = "aiohttp-3.11.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4586a68730bd2f2b04a83e83f79d271d8ed13763f64b75920f18a3a677b9a7f0"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fe4eb0e7f50cdb99b26250d9328faef30b1175a5dbcfd6d0578d18456bac567"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2a8a6bc19818ac3e5596310ace5aa50d918e1ebdcc204dc96e2f4d505d51740c"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f27eec42f6c3c1df09cfc1f6786308f8b525b8efaaf6d6bd76c1f52c6511f6a"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2a4a13dfbb23977a51853b419141cd0a9b9573ab8d3a1455c6e63561387b52ff"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:02876bf2f69b062584965507b07bc06903c2dc93c57a554b64e012d636952654"}, + {file = "aiohttp-3.11.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b992778d95b60a21c4d8d4a5f15aaab2bd3c3e16466a72d7f9bfd86e8cea0d4b"}, + {file = "aiohttp-3.11.13-cp313-cp313-win32.whl", hash = "sha256:507ab05d90586dacb4f26a001c3abf912eb719d05635cbfad930bdbeb469b36c"}, + {file = "aiohttp-3.11.13-cp313-cp313-win_amd64.whl", hash = "sha256:5ceb81a4db2decdfa087381b5fc5847aa448244f973e5da232610304e199e7b2"}, + {file = "aiohttp-3.11.13.tar.gz", hash = "sha256:8ce789231404ca8fff7f693cdce398abf6d90fd5dae2b1847477196c243b1fbb"}, ] [[package]] name = "aiosignal" -version = "1.3.1" -requires_python = ">=3.7" +version = "1.3.2" +requires_python = ">=3.9" summary = "aiosignal: a list of registered asynchronous callbacks" +groups = ["default"] dependencies = [ "frozenlist>=1.1.0", ] files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, + {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, + {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, ] [[package]] @@ -82,11 +108,13 @@ name = "albucore" version = "0.0.23" requires_python = ">=3.9" summary = "High-performance image processing functions for deep learning and computer vision." +groups = ["default"] dependencies = [ "numpy>=1.24.4", "opencv-python-headless>=4.9.0.80", "simsimd>=5.9.2", "stringzilla>=3.10.4", + "typing-extensions>=4.9.0; python_version < \"3.10\"", ] files = [ {file = "albucore-0.0.23-py3-none-any.whl", hash = "sha256:99274ac0c15a1a7d9a726df9d54d5ab70d9d0c189e2a935399dba3d4bafad415"}, @@ -95,44 +123,39 @@ files = [ [[package]] name = "albumentations" -version = "2.0.4" +version = "2.0.5" requires_python = ">=3.9" -summary = "Fast, flexible, and advanced augmentation library for deep learning, computer vision, and medical imaging. Albumentations offers a wide range of transformations for both 2D (images, masks, bboxes, keypoints) and 3D (volumes, volumetric masks) data, with optimized performance and seamless integration into ML workflows." +summary = "Fast, flexible, and advanced augmentation library for deep learning, computer vision, and medical imaging. Albumentations offers a wide range of transformations for both 2D (images, masks, bboxes, keypoints) and 3D (volumes, volumetric masks, keypoints) data, with optimized performance and seamless integration into ML workflows." +groups = ["default"] dependencies = [ "PyYAML", "albucore==0.0.23", + "eval-type-backport; python_version < \"3.10\"", "numpy>=1.24.4", "opencv-python-headless>=4.9.0.80", "pydantic>=2.9.2", "scipy>=1.10.0", + "typing-extensions>=4.9.0; python_version < \"3.10\"", ] files = [ - {file = "albumentations-2.0.4-py3-none-any.whl", hash = "sha256:1d60b62527d34bb8791fad90f6faeeb065ecc5cb4577ff85614f022d56183010"}, - {file = "albumentations-2.0.4.tar.gz", hash = "sha256:4f0cd22576fba8030fc99f1ccacee1452a1880ac2a9ce0882f0d93e5477d5c70"}, + {file = "albumentations-2.0.5-py3-none-any.whl", hash = "sha256:1fc253942d34dd7c07652bf6511049c8bb7d522baec7f1fe355df16293c3c7b6"}, + {file = "albumentations-2.0.5.tar.gz", hash = "sha256:e19e1c0f14c903c3c230f3d83f14814b84f1180393189bf96779f653031f3278"}, ] [[package]] name = "alembic" -version = "1.13.2" -requires_python = ">=3.8" +version = "1.15.1" +requires_python = ">=3.9" summary = "A database migration tool for SQLAlchemy." +groups = ["default"] dependencies = [ "Mako", - "SQLAlchemy>=1.3.0", - "typing-extensions>=4", -] -files = [ - {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, - {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, + "SQLAlchemy>=1.4.0", + "typing-extensions>=4.12", ] - -[[package]] -name = "aniso8601" -version = "9.0.1" -summary = "A library for parsing ISO 8601 strings." files = [ - {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"}, - {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"}, + {file = "alembic-1.15.1-py3-none-any.whl", hash = "sha256:197de710da4b3e91cf66a826a5b31b5d59a127ab41bd0fc42863e2902ce2bbbe"}, + {file = "alembic-1.15.1.tar.gz", hash = "sha256:e1a1c738577bca1f27e68728c910cd389b9a92152ff91d902da649c192e30c49"}, ] [[package]] @@ -140,6 +163,10 @@ name = "annotated-types" version = "0.7.0" requires_python = ">=3.8" summary = "Reusable constraint types to use with typing.Annotated" +groups = ["default"] +dependencies = [ + "typing-extensions>=4.0.0; python_version < \"3.9\"", +] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -149,48 +176,56 @@ files = [ name = "antlr4-python3-runtime" version = "4.9.3" summary = "ANTLR 4.9.3 runtime for Python 3.7" +groups = ["default"] +dependencies = [ + "typing; python_version < \"3.5\"", +] files = [ {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, ] [[package]] name = "attrs" -version = "24.2.0" -requires_python = ">=3.7" +version = "25.1.0" +requires_python = ">=3.8" summary = "Classes Without Boilerplate" +groups = ["default"] files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, + {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, + {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, ] [[package]] name = "blinker" -version = "1.8.2" -requires_python = ">=3.8" +version = "1.9.0" +requires_python = ">=3.9" summary = "Fast, simple object-to-object and broadcast signaling" +groups = ["default"] files = [ - {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, - {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, + {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, + {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, ] [[package]] name = "cachetools" -version = "5.5.0" +version = "5.5.2" requires_python = ">=3.7" summary = "Extensible memoizing collections and decorators" +groups = ["default"] files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, + {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, + {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, ] [[package]] name = "certifi" -version = "2024.8.30" +version = "2025.1.31" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." +groups = ["default"] files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -198,11 +233,45 @@ name = "cffi" version = "1.17.1" requires_python = ">=3.8" summary = "Foreign Function Interface for Python calling C code." +groups = ["default"] dependencies = [ "pycparser", ] files = [ + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] @@ -211,6 +280,7 @@ name = "cfgv" version = "3.4.0" requires_python = ">=3.8" summary = "Validate configuration and produce human readable error messages." +groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -218,112 +288,143 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" -requires_python = ">=3.7.0" +version = "3.4.1" +requires_python = ">=3.7" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +groups = ["default"] +files = [ + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" requires_python = ">=3.7" summary = "Composable command line interface toolkit" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", + "importlib-metadata; python_version < \"3.8\"", +] files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [[package]] name = "cloudpickle" -version = "3.0.0" +version = "3.1.1" requires_python = ">=3.8" summary = "Pickler class to extend the standard pickle.Pickler functionality" +groups = ["default"] +files = [ + {file = "cloudpickle-3.1.1-py3-none-any.whl", hash = "sha256:c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e"}, + {file = "cloudpickle-3.1.1.tar.gz", hash = "sha256:b216fa8ae4019d5482a8ac3c95d8f6346115d8835911fd4aefd1a445e4242c64"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["default"] +marker = "platform_system == \"Windows\"" files = [ - {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"}, - {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] [[package]] name = "contourpy" -version = "1.3.0" -requires_python = ">=3.9" +version = "1.3.1" +requires_python = ">=3.10" summary = "Python library for calculating contours of 2D quadrilateral grids" +groups = ["default"] dependencies = [ "numpy>=1.23", ] files = [ - {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, - {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, - {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, - {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, - {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, - {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, - {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, - {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, - {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, - {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, - {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, - {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, - {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, - {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, - {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, - {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, - {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, - {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, - {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, - {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, - {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, - {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, - {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, - {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, - {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, - {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, - {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, - {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, - {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, - {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, - {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, - {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, - {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, - {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, - {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, - {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, - {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, - {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, - {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, + {file = "contourpy-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e8b974d8db2c5610fb4e76307e265de0edb655ae8169e8b21f41807ccbeec4b"}, + {file = "contourpy-1.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20914c8c973f41456337652a6eeca26d2148aa96dd7ac323b74516988bea89fc"}, + {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d40d37c1c3a4961b4619dd9d77b12124a453cc3d02bb31a07d58ef684d3d86"}, + {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:113231fe3825ebf6f15eaa8bc1f5b0ddc19d42b733345eae0934cb291beb88b6"}, + {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dbbc03a40f916a8420e420d63e96a1258d3d1b58cbdfd8d1f07b49fcbd38e85"}, + {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a04ecd68acbd77fa2d39723ceca4c3197cb2969633836ced1bea14e219d077c"}, + {file = "contourpy-1.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c414fc1ed8ee1dbd5da626cf3710c6013d3d27456651d156711fa24f24bd1291"}, + {file = "contourpy-1.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:31c1b55c1f34f80557d3830d3dd93ba722ce7e33a0b472cba0ec3b6535684d8f"}, + {file = "contourpy-1.3.1-cp311-cp311-win32.whl", hash = "sha256:f611e628ef06670df83fce17805c344710ca5cde01edfdc72751311da8585375"}, + {file = "contourpy-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:b2bdca22a27e35f16794cf585832e542123296b4687f9fd96822db6bae17bfc9"}, + {file = "contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509"}, + {file = "contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec"}, + {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9"}, + {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b"}, + {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d"}, + {file = "contourpy-1.3.1-cp312-cp312-win32.whl", hash = "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e"}, + {file = "contourpy-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d"}, + {file = "contourpy-1.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a761d9ccfc5e2ecd1bf05534eda382aa14c3e4f9205ba5b1684ecfe400716ef2"}, + {file = "contourpy-1.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:523a8ee12edfa36f6d2a49407f705a6ef4c5098de4f498619787e272de93f2d5"}, + {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece6df05e2c41bd46776fbc712e0996f7c94e0d0543af1656956d150c4ca7c81"}, + {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:573abb30e0e05bf31ed067d2f82500ecfdaec15627a59d63ea2d95714790f5c2"}, + {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fa36448e6a3a1a9a2ba23c02012c43ed88905ec80163f2ffe2421c7192a5d7"}, + {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c"}, + {file = "contourpy-1.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b75aa69cb4d6f137b36f7eb2ace9280cfb60c55dc5f61c731fdf6f037f958a3"}, + {file = "contourpy-1.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1"}, + {file = "contourpy-1.3.1-cp313-cp313-win32.whl", hash = "sha256:36987a15e8ace5f58d4d5da9dca82d498c2bbb28dff6e5d04fbfcc35a9cb3a82"}, + {file = "contourpy-1.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7895f46d47671fa7ceec40f31fae721da51ad34bdca0bee83e38870b1f47ffd"}, + {file = "contourpy-1.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9ddeb796389dadcd884c7eb07bd14ef12408aaae358f0e2ae24114d797eede30"}, + {file = "contourpy-1.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19c1555a6801c2f084c7ddc1c6e11f02eb6a6016ca1318dd5452ba3f613a1751"}, + {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:841ad858cff65c2c04bf93875e384ccb82b654574a6d7f30453a04f04af71342"}, + {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4318af1c925fb9a4fb190559ef3eec206845f63e80fb603d47f2d6d67683901c"}, + {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:14c102b0eab282427b662cb590f2e9340a9d91a1c297f48729431f2dcd16e14f"}, + {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda"}, + {file = "contourpy-1.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4d76d5993a34ef3df5181ba3c92fabb93f1eaa5729504fb03423fcd9f3177242"}, + {file = "contourpy-1.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:89785bb2a1980c1bd87f0cb1517a71cde374776a5f150936b82580ae6ead44a1"}, + {file = "contourpy-1.3.1-cp313-cp313t-win32.whl", hash = "sha256:8eb96e79b9f3dcadbad2a3891672f81cdcab7f95b27f28f1c67d75f045b6b4f1"}, + {file = "contourpy-1.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546"}, + {file = "contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699"}, ] [[package]] @@ -331,6 +432,7 @@ name = "cycler" version = "0.12.1" requires_python = ">=3.8" summary = "Composable style cycles" +groups = ["default"] files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, @@ -338,38 +440,41 @@ files = [ [[package]] name = "databricks-sdk" -version = "0.31.1" +version = "0.44.1" requires_python = ">=3.7" summary = "Databricks SDK for Python (Beta)" +groups = ["default"] dependencies = [ "google-auth~=2.0", "requests<3,>=2.28.1", ] files = [ - {file = "databricks_sdk-0.31.1-py3-none-any.whl", hash = "sha256:9ab286f87ae1cc98a00ef7d207e40661f4d14a464071425ad169d235919b35f6"}, - {file = "databricks_sdk-0.31.1.tar.gz", hash = "sha256:8609e655d0e5ecb15c2a8a6468e737f8dcb4f28c33239388de3ab386b921d790"}, + {file = "databricks-sdk-0.44.1.tar.gz", hash = "sha256:78b6734f79ddd33d05f00bbf3a0a9114e881c0a29d99dab369f19e3db0ac532c"}, + {file = "databricks_sdk-0.44.1-py3-none-any.whl", hash = "sha256:2808fc73ec9934551eb8587bf82da3a42aa0f11ebc2e97468e8ced8e5b27e34d"}, ] [[package]] name = "deprecated" -version = "1.2.14" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.18" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" summary = "Python @deprecated decorator to deprecate old python classes, functions or methods." +groups = ["default"] dependencies = [ "wrapt<2,>=1.10", ] files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, + {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, + {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, ] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" summary = "Distribution utilities" +groups = ["dev"] files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -377,7 +482,9 @@ name = "docker" version = "7.1.0" requires_python = ">=3.8" summary = "A Python library for the Docker Engine API." +groups = ["default"] dependencies = [ + "pywin32>=304; sys_platform == \"win32\"", "requests>=2.26.0", "urllib3>=1.26.0", ] @@ -390,6 +497,7 @@ files = [ name = "durationpy" version = "0.9" summary = "Module for converting between datetime.timedelta and Go's Duration strings." +groups = ["default"] files = [ {file = "durationpy-0.9-py3-none-any.whl", hash = "sha256:e65359a7af5cedad07fb77a2dd3f390f8eb0b74cb845589fa6c057086834dd38"}, {file = "durationpy-0.9.tar.gz", hash = "sha256:fd3feb0a69a0057d582ef643c355c40d2fa1c942191f914d12203b1a01ac722a"}, @@ -397,185 +505,225 @@ files = [ [[package]] name = "filelock" -version = "3.15.4" -requires_python = ">=3.8" +version = "3.17.0" +requires_python = ">=3.9" summary = "A platform independent file lock." +groups = ["default", "dev"] files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, + {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, ] [[package]] name = "flask" -version = "3.0.3" -requires_python = ">=3.8" +version = "3.1.0" +requires_python = ">=3.9" summary = "A simple framework for building complex web applications." +groups = ["default"] dependencies = [ "Jinja2>=3.1.2", - "Werkzeug>=3.0.0", - "blinker>=1.6.2", + "Werkzeug>=3.1", + "blinker>=1.9", "click>=8.1.3", - "itsdangerous>=2.1.2", + "importlib-metadata>=3.6; python_version < \"3.10\"", + "itsdangerous>=2.2", ] files = [ - {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, - {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, + {file = "flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136"}, + {file = "flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac"}, ] [[package]] name = "fonttools" -version = "4.53.1" +version = "4.56.0" requires_python = ">=3.8" summary = "Tools to manipulate font files" -files = [ - {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, - {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, - {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, - {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, - {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, - {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, - {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, - {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, - {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, - {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, - {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, - {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, - {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, - {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, - {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, - {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, - {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, - {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, +groups = ["default"] +files = [ + {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df"}, + {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c"}, + {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c"}, + {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049"}, + {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62"}, + {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0"}, + {file = "fonttools-4.56.0-cp311-cp311-win32.whl", hash = "sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b"}, + {file = "fonttools-4.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05"}, + {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9"}, + {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f"}, + {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2"}, + {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563"}, + {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a"}, + {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28"}, + {file = "fonttools-4.56.0-cp312-cp312-win32.whl", hash = "sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c"}, + {file = "fonttools-4.56.0-cp312-cp312-win_amd64.whl", hash = "sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba"}, + {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692"}, + {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0"}, + {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1"}, + {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea"}, + {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3"}, + {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278"}, + {file = "fonttools-4.56.0-cp313-cp313-win32.whl", hash = "sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f"}, + {file = "fonttools-4.56.0-cp313-cp313-win_amd64.whl", hash = "sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6"}, + {file = "fonttools-4.56.0-py3-none-any.whl", hash = "sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14"}, + {file = "fonttools-4.56.0.tar.gz", hash = "sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4"}, ] [[package]] name = "frozenlist" -version = "1.4.1" +version = "1.5.0" requires_python = ">=3.8" summary = "A list-like structure which implements collections.abc.MutableSequence" -files = [ - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +groups = ["default"] +files = [ + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "fsspec" -version = "2024.6.1" +version = "2025.2.0" requires_python = ">=3.8" summary = "File-system specification" +groups = ["default"] files = [ - {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, - {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, + {file = "fsspec-2025.2.0-py3-none-any.whl", hash = "sha256:9de2ad9ce1f85e1931858535bc882543171d197001a0a5eb2ddc04f1781ab95b"}, + {file = "fsspec-2025.2.0.tar.gz", hash = "sha256:1c24b16eaa0a1798afa0337aa0db9b256718ab2a89c425371f5628d22c3b6afd"}, ] [[package]] name = "fsspec" -version = "2024.6.1" +version = "2025.2.0" extras = ["http"] requires_python = ">=3.8" summary = "File-system specification" +groups = ["default"] dependencies = [ "aiohttp!=4.0.0a0,!=4.0.0a1", - "fsspec==2024.6.1", + "fsspec==2025.2.0", ] files = [ - {file = "fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e"}, - {file = "fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49"}, + {file = "fsspec-2025.2.0-py3-none-any.whl", hash = "sha256:9de2ad9ce1f85e1931858535bc882543171d197001a0a5eb2ddc04f1781ab95b"}, + {file = "fsspec-2025.2.0.tar.gz", hash = "sha256:1c24b16eaa0a1798afa0337aa0db9b256718ab2a89c425371f5628d22c3b6afd"}, ] [[package]] name = "gitdb" -version = "4.0.11" +version = "4.0.12" requires_python = ">=3.7" summary = "Git Object Database" +groups = ["default"] dependencies = [ "smmap<6,>=3.0.1", ] files = [ - {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, - {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, + {file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"}, + {file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"}, ] [[package]] name = "gitpython" -version = "3.1.43" +version = "3.1.44" requires_python = ">=3.7" summary = "GitPython is a Python library used to interact with Git repositories" +groups = ["default"] dependencies = [ "gitdb<5,>=4.0.1", + "typing-extensions>=3.7.4.3; python_version < \"3.8\"", ] files = [ - {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, - {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, + {file = "GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"}, + {file = "gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269"}, ] [[package]] name = "google-auth" -version = "2.34.0" +version = "2.38.0" requires_python = ">=3.7" summary = "Google Authentication Library" +groups = ["default"] dependencies = [ "cachetools<6.0,>=2.0.0", "pyasn1-modules>=0.2.1", "rsa<5,>=3.1.4", ] files = [ - {file = "google_auth-2.34.0-py2.py3-none-any.whl", hash = "sha256:72fd4733b80b6d777dcde515628a9eb4a577339437012874ea286bca7261ee65"}, - {file = "google_auth-2.34.0.tar.gz", hash = "sha256:8eb87396435c19b20d32abd2f984e31c191a15284af72eb922f10e5bde9c04cc"}, + {file = "google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a"}, + {file = "google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4"}, ] [[package]] name = "graphene" -version = "3.3" +version = "3.4.3" summary = "GraphQL Framework for Python" +groups = ["default"] dependencies = [ - "aniso8601<10,>=8", "graphql-core<3.3,>=3.1", "graphql-relay<3.3,>=3.1", + "python-dateutil<3,>=2.7.0", + "typing-extensions<5,>=4.7.1", ] files = [ - {file = "graphene-3.3-py2.py3-none-any.whl", hash = "sha256:bb3810be33b54cb3e6969506671eb72319e8d7ba0d5ca9c8066472f75bf35a38"}, - {file = "graphene-3.3.tar.gz", hash = "sha256:529bf40c2a698954217d3713c6041d69d3f719ad0080857d7ee31327112446b0"}, + {file = "graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71"}, + {file = "graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa"}, ] [[package]] name = "graphql-core" -version = "3.2.3" -requires_python = ">=3.6,<4" +version = "3.2.6" +requires_python = "<4,>=3.6" summary = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +groups = ["default"] +dependencies = [ + "typing-extensions<5,>=4; python_version < \"3.10\"", +] files = [ - {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, - {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, + {file = "graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"}, + {file = "graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab"}, ] [[package]] @@ -583,8 +731,10 @@ name = "graphql-relay" version = "3.2.0" requires_python = ">=3.6,<4" summary = "Relay library for graphql-core" +groups = ["default"] dependencies = [ "graphql-core<3.3,>=3.2", + "typing-extensions<5,>=4.1; python_version < \"3.8\"", ] files = [ {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"}, @@ -593,29 +743,47 @@ files = [ [[package]] name = "greenlet" -version = "3.0.3" +version = "3.1.1" requires_python = ">=3.7" summary = "Lightweight in-process concurrent programming" -files = [ - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +groups = ["default"] +marker = "(platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_version < \"3.14\"" +files = [ + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [[package]] @@ -623,7 +791,10 @@ name = "gunicorn" version = "23.0.0" requires_python = ">=3.7" summary = "WSGI HTTP Server for UNIX" +groups = ["default"] +marker = "platform_system != \"Windows\"" dependencies = [ + "importlib-metadata; python_version < \"3.8\"", "packaging", ] files = [ @@ -635,8 +806,10 @@ files = [ name = "hydra-core" version = "1.3.2" summary = "A framework for elegantly configuring complex applications" +groups = ["default"] dependencies = [ "antlr4-python3-runtime==4.9.*", + "importlib-resources; python_version < \"3.9\"", "omegaconf<2.4,>=2.2", "packaging", ] @@ -647,35 +820,54 @@ files = [ [[package]] name = "identify" -version = "2.6.0" -requires_python = ">=3.8" +version = "2.6.8" +requires_python = ">=3.9" summary = "File identification library for Python" +groups = ["dev"] files = [ - {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, - {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, + {file = "identify-2.6.8-py2.py3-none-any.whl", hash = "sha256:83657f0f766a3c8d0eaea16d4ef42494b39b34629a4b3192a9d020d349b3e255"}, + {file = "identify-2.6.8.tar.gz", hash = "sha256:61491417ea2c0c5c670484fd8abbb34de34cdae1e5f39a73ee65e48e4bb663fc"}, ] [[package]] name = "idna" -version = "3.7" -requires_python = ">=3.5" +version = "3.10" +requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" +groups = ["default"] files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[[package]] +name = "imageio" +version = "2.37.0" +requires_python = ">=3.9" +summary = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." +groups = ["default"] +dependencies = [ + "numpy", + "pillow>=8.3.2", +] +files = [ + {file = "imageio-2.37.0-py3-none-any.whl", hash = "sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed"}, + {file = "imageio-2.37.0.tar.gz", hash = "sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996"}, ] [[package]] name = "importlib-metadata" -version = "8.4.0" +version = "8.5.0" requires_python = ">=3.8" summary = "Read metadata from Python packages" +groups = ["default"] dependencies = [ - "zipp>=0.5", + "typing-extensions>=3.6.4; python_version < \"3.8\"", + "zipp>=3.20", ] files = [ - {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, - {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [[package]] @@ -683,6 +875,7 @@ name = "itsdangerous" version = "2.2.0" requires_python = ">=3.8" summary = "Safely pass data to untrusted environments and back." +groups = ["default"] files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, @@ -690,15 +883,16 @@ files = [ [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.6" requires_python = ">=3.7" summary = "A very fast and expressive template engine." +groups = ["default"] dependencies = [ "MarkupSafe>=2.0", ] files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [[package]] @@ -706,6 +900,7 @@ name = "joblib" version = "1.4.2" requires_python = ">=3.8" summary = "Lightweight pipelining with Python functions" +groups = ["default"] files = [ {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, @@ -716,9 +911,12 @@ name = "jsonschema" version = "4.23.0" requires_python = ">=3.8" summary = "An implementation of JSON Schema validation for Python" +groups = ["default"] dependencies = [ "attrs>=22.2.0", + "importlib-resources>=1.4.0; python_version < \"3.9\"", "jsonschema-specifications>=2023.03.6", + "pkgutil-resolve-name>=1.3.10; python_version < \"3.9\"", "referencing>=0.28.4", "rpds-py>=0.7.1", ] @@ -732,6 +930,7 @@ name = "jsonschema-specifications" version = "2024.10.1" requires_python = ">=3.9" summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +groups = ["default"] dependencies = [ "referencing>=0.31.0", ] @@ -742,44 +941,70 @@ files = [ [[package]] name = "kiwisolver" -version = "1.4.6" -requires_python = ">=3.8" +version = "1.4.8" +requires_python = ">=3.10" summary = "A fast implementation of the Cassowary constraint solver" -files = [ - {file = "kiwisolver-1.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:45a5cb5abad1ad9c265eed7e058fefafeb7964565b93b397ba2f480faec8d674"}, - {file = "kiwisolver-1.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e52b2568c47fb4f54d17576954e02b1de156c85152f87283a99db9670fd18c0"}, - {file = "kiwisolver-1.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:00af95204100bc1d0f26e1ed52ec77d6e3da5c9b845c88d31875c164e4ba6c0c"}, - {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ab1fedf86f3951a9e90a64edd15f598860ed60cd3664259756f097d527b5ae"}, - {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc985766bf20141ce64baecc39fb9fedbce094b2b8de1bb62676b79328988e4"}, - {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1942a155c737a7c3835a957897f0cc9ebc0085b7a75d934d86aecb1b27b8873"}, - {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f464403e391724f8e7dff188d3fb77a85bd1273b3fdba182e6671abcc44434f8"}, - {file = "kiwisolver-1.4.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce5efe545eea86f52ec5a1185e5052815ea86778e8268bad71fa46433f7c0bef"}, - {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cb30165f71b7b3378668346e220c81d590593a3a1ff76428a53780310df03f35"}, - {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5a987f740e1c9964e614acb87ba1f014b4be760a341effc8dc789913d1840e6"}, - {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f2ceaa6d0450623d108956647ef19a1a28c7e07880f1171c932477308d44d80b"}, - {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:788cbf99738f18ae8a27b9d4d7314502b4b917005cfdacd1d6a59038332ae24d"}, - {file = "kiwisolver-1.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2f6668678a6b9488a7f8a6320e1b1c6396d179a976472dbc08d1600d04119511"}, - {file = "kiwisolver-1.4.6-cp311-cp311-win32.whl", hash = "sha256:10a09a3e4213c2806bcfd2eb4edb756c557973d2cacf06873b18a247fce897da"}, - {file = "kiwisolver-1.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:683ffef2c51fdc54112dc610d06b59b88c21e23fb669b905da6d5bec80da1bde"}, - {file = "kiwisolver-1.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:3b852c7f0ed9a2fd339c228829bca0964233ed45de50aae3e87b72ca37d177f8"}, - {file = "kiwisolver-1.4.6-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:979df7e9334f6a3694ee9be8d42817e519ef6d155a16499714d082cf41296852"}, - {file = "kiwisolver-1.4.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:50c9c6c42bb6ca231626d1182b9128e89c5ce3c64456f811ff0280deb42d7bfe"}, - {file = "kiwisolver-1.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ace86489e7951bd26329a589198d3875c3d48380f889c69d3eb254b506a80101"}, - {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f94771988da902b475f78e85cf63c5c94392773b4a6494234d87c1b363b2fbc5"}, - {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62379eee430b1c477bb0a0bf6858a57c7c0dad9cee8b3144a5cb5d366c66a54"}, - {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e99b97d69499a7414572c906fbc7ca312519f2e17999730129f6c4492786e953"}, - {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab93f58afe3a02922a343189404f24ed885564e6316649790240124b95ef1d6e"}, - {file = "kiwisolver-1.4.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34105f4460ba50fc18a16a8e77a5122f7affe075628763fda748ad0ec534c3ee"}, - {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0081f85f0222620563409d4804c6567a930a45dafbe9674c7913fde131653992"}, - {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:df2a4a7cc2e01991e039a792457751b601bdf30143ab5f23f9a1e58f20c875f4"}, - {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1f401784df70ea2870e4e10adade66b5b06cb2c151bc2a8a414a1d10554e9a81"}, - {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:b19761c8c613b6d04c44f1a4797a144b44136f17ec009ccfb025e17b5698140c"}, - {file = "kiwisolver-1.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee7289430ded484cc2eff9d8ffcce58ed7fe2c26919321dbc0580322a49e0120"}, - {file = "kiwisolver-1.4.6-cp312-cp312-win32.whl", hash = "sha256:331b9d9f408e874ecf34bd79b79df8e099f0b1b351b8844609c1bfdc8d2d45b2"}, - {file = "kiwisolver-1.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:a9be95d086578b3ada61a4621c0e7ee5f456820bfdccc3329061fdeae1e31179"}, - {file = "kiwisolver-1.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:773f2d87825779ab69196dfcf63e9d91043273421c6128c8d4ed82bc6316068f"}, - {file = "kiwisolver-1.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:140f376c22b5148453acff768cff19c34ebbd593126617018732ea1d9ce65547"}, - {file = "kiwisolver-1.4.6.tar.gz", hash = "sha256:3cda29d601445e6aa11f80d90a9b8c2ae501650c55d7ad29829bd44499c9e7e0"}, +groups = ["default"] +files = [ + {file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84"}, + {file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561"}, + {file = "kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7"}, + {file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03"}, + {file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954"}, + {file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79"}, + {file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6"}, + {file = "kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0"}, + {file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab"}, + {file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc"}, + {file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25"}, + {file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc"}, + {file = "kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67"}, + {file = "kiwisolver-1.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34"}, + {file = "kiwisolver-1.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2"}, + {file = "kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502"}, + {file = "kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31"}, + {file = "kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb"}, + {file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f"}, + {file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc"}, + {file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a"}, + {file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a"}, + {file = "kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a"}, + {file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3"}, + {file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b"}, + {file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4"}, + {file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d"}, + {file = "kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8"}, + {file = "kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50"}, + {file = "kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476"}, + {file = "kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09"}, + {file = "kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1"}, + {file = "kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c"}, + {file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b"}, + {file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47"}, + {file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16"}, + {file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc"}, + {file = "kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246"}, + {file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794"}, + {file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b"}, + {file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3"}, + {file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957"}, + {file = "kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb"}, + {file = "kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2"}, + {file = "kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90"}, + {file = "kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85"}, + {file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"}, ] [[package]] @@ -787,6 +1012,7 @@ name = "kubernetes" version = "32.0.1" requires_python = ">=3.6" summary = "Kubernetes python client" +groups = ["default"] dependencies = [ "certifi>=14.05.14", "durationpy>=0.7", @@ -805,11 +1031,27 @@ files = [ {file = "kubernetes-32.0.1.tar.gz", hash = "sha256:42f43d49abd437ada79a79a16bd48a604d3471a117a8347e87db693f2ba0ba28"}, ] +[[package]] +name = "lazy-loader" +version = "0.4" +requires_python = ">=3.7" +summary = "Makes it easy to load subpackages and functions on demand." +groups = ["default"] +dependencies = [ + "importlib-metadata; python_version < \"3.8\"", + "packaging", +] +files = [ + {file = "lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"}, + {file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"}, +] + [[package]] name = "lightning" -version = "2.4.0" +version = "2.5.0.post0" requires_python = ">=3.9" summary = "The Deep Learning framework to train, deploy, and ship AI products Lightning fast." +groups = ["default"] dependencies = [ "PyYAML<8.0,>=5.4", "fsspec[http]<2026.0,>=2022.5.0", @@ -822,36 +1064,39 @@ dependencies = [ "typing-extensions<6.0,>=4.4.0", ] files = [ - {file = "lightning-2.4.0-py3-none-any.whl", hash = "sha256:560163af9711cf59055c448232c473150a299089efce0d2be3cc3288082d8768"}, - {file = "lightning-2.4.0.tar.gz", hash = "sha256:9156604cc56e4b2b603f34fa7f0fe5107375c8e6d85e74544b319a15faa9ed0e"}, + {file = "lightning-2.5.0.post0-py3-none-any.whl", hash = "sha256:b08463326e6fb39cb3e4db8ff2660a80ce3372a0688c80e3370c091346ea220c"}, + {file = "lightning-2.5.0.post0.tar.gz", hash = "sha256:f720fe4f6d03a7f15f9aef3112c5a0d1eafd8d27b903f4a1354b609685b2ec70"}, ] [[package]] name = "lightning-utilities" -version = "0.11.6" -requires_python = ">=3.8" +version = "0.13.1" +requires_python = ">=3.9" summary = "Lightning toolbox for across the our ecosystem." +groups = ["default"] dependencies = [ + "importlib-metadata>=4.0.0; python_version < \"3.8\"", "packaging>=17.1", "setuptools", "typing-extensions", ] files = [ - {file = "lightning_utilities-0.11.6-py3-none-any.whl", hash = "sha256:ecd9953c316cbaf56ad820fbe7bd062187b9973c4a23d47b076cd59dc080a310"}, - {file = "lightning_utilities-0.11.6.tar.gz", hash = "sha256:79fc27ef8ec8b8d55a537920f2c7610270c0c9e037fa6efc78f1aa34ec8cdf04"}, + {file = "lightning_utilities-0.13.1-py3-none-any.whl", hash = "sha256:5e468a3fd5d656ed36898b6efc9420fb476f4e24d14e3a9d59571ddb63620cf2"}, + {file = "lightning_utilities-0.13.1.tar.gz", hash = "sha256:ae9614d6e5165bd1bccf4211dbbe3265ae9a56e989089d768aac21c7e0af3558"}, ] [[package]] name = "mako" -version = "1.3.5" +version = "1.3.9" requires_python = ">=3.8" summary = "A super-fast templating language that borrows the best ideas from the existing templating languages." +groups = ["default"] dependencies = [ "MarkupSafe>=0.9.2", ] files = [ - {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, - {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, + {file = "Mako-1.3.9-py3-none-any.whl", hash = "sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1"}, + {file = "mako-1.3.9.tar.gz", hash = "sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac"}, ] [[package]] @@ -859,6 +1104,10 @@ name = "markdown" version = "3.7" requires_python = ">=3.8" summary = "Python implementation of John Gruber's Markdown." +groups = ["default"] +dependencies = [ + "importlib-metadata>=4.4; python_version < \"3.10\"", +] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -866,38 +1115,60 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.5" -requires_python = ">=3.7" +version = "3.0.2" +requires_python = ">=3.9" summary = "Safely add untrusted strings to HTML/XML markup." -files = [ - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +groups = ["default"] +files = [ + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "matplotlib" -version = "3.9.2" -requires_python = ">=3.9" +version = "3.10.1" +requires_python = ">=3.10" summary = "Python plotting package" +groups = ["default"] dependencies = [ "contourpy>=1.0.1", "cycler>=0.10", @@ -910,64 +1181,69 @@ dependencies = [ "python-dateutil>=2.7", ] files = [ - {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"}, - {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"}, - {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"}, - {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"}, - {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"}, - {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"}, - {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, - {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, - {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, - {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, - {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, - {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, - {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"}, - {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"}, - {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"}, - {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"}, - {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"}, - {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"}, - {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"}, - {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"}, - {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"}, - {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"}, - {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"}, - {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, + {file = "matplotlib-3.10.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401"}, + {file = "matplotlib-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe"}, + {file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd"}, + {file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c"}, + {file = "matplotlib-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7"}, + {file = "matplotlib-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a"}, + {file = "matplotlib-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107"}, + {file = "matplotlib-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be"}, + {file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6"}, + {file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d"}, + {file = "matplotlib-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea"}, + {file = "matplotlib-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c"}, + {file = "matplotlib-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b"}, + {file = "matplotlib-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1"}, + {file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3"}, + {file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6"}, + {file = "matplotlib-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b"}, + {file = "matplotlib-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473"}, + {file = "matplotlib-3.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01"}, + {file = "matplotlib-3.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb"}, + {file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972"}, + {file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3"}, + {file = "matplotlib-3.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f"}, + {file = "matplotlib-3.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9"}, + {file = "matplotlib-3.10.1.tar.gz", hash = "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba"}, ] [[package]] name = "mlflow" -version = "2.16.0" -requires_python = ">=3.8" +version = "2.20.3" +requires_python = ">=3.9" summary = "MLflow is an open source platform for the complete machine learning lifecycle" +groups = ["default"] dependencies = [ "Flask<4", "Jinja2<4,>=2.11; platform_system != \"Windows\"", + "Jinja2<4,>=3.0; platform_system == \"Windows\"", "alembic!=1.10.0,<2", "docker<8,>=4.0.0", "graphene<4", "gunicorn<24; platform_system != \"Windows\"", "markdown<4,>=3.3", "matplotlib<4", - "mlflow-skinny==2.16.0", + "mlflow-skinny==2.20.3", "numpy<3", "pandas<3", - "pyarrow<18,>=4.0.0", + "pyarrow<20,>=4.0.0", "scikit-learn<2", "scipy<2", "sqlalchemy<3,>=1.4.0", + "waitress<4; platform_system == \"Windows\"", ] files = [ - {file = "mlflow-2.16.0-py3-none-any.whl", hash = "sha256:9f27ef6ae7a82d7ecd67b6b4a4d50637a5e8160639115570fbc689758f9c0b54"}, - {file = "mlflow-2.16.0.tar.gz", hash = "sha256:82ea1a2e800f404f1586783b7636091c0a5754cf9ff45afeadf3a5e467f5168f"}, + {file = "mlflow-2.20.3-py3-none-any.whl", hash = "sha256:efafe5d4d17b53be1ae02c7d8708a5e4bbde4bd3aecd2bd68b64a3c4175e9dc6"}, + {file = "mlflow-2.20.3.tar.gz", hash = "sha256:a7b1baf53d4f10160864961320df0c4cb74fb4f21c7522ef80a35290d03573bb"}, ] [[package]] name = "mlflow-skinny" -version = "2.16.0" -requires_python = ">=3.8" +version = "2.20.3" +requires_python = ">=3.9" summary = "MLflow is an open source platform for the complete machine learning lifecycle" +groups = ["default"] dependencies = [ "cachetools<6,>=5.0.0", "click<9,>=7.0", @@ -979,19 +1255,23 @@ dependencies = [ "opentelemetry-sdk<3,>=1.9.0", "packaging<25", "protobuf<6,>=3.12.0", + "pydantic<3,>=1.10.8", "pyyaml<7,>=5.1", "requests<3,>=2.17.3", "sqlparse<1,>=0.4.0", + "typing-extensions<5,>=4.0.0", ] files = [ - {file = "mlflow_skinny-2.16.0-py3-none-any.whl", hash = "sha256:c55541f50efd0f6637377b10e8a654847a3fcd815b8680a95f02e0ca6bd7700c"}, - {file = "mlflow_skinny-2.16.0.tar.gz", hash = "sha256:9b823173063743783b4e7b6c52bdadcc7d9dab48eb883ac454c0d56609df6b2d"}, + {file = "mlflow_skinny-2.20.3-py3-none-any.whl", hash = "sha256:4cf9502bf8b7c4c971c90808560caeb2d57608354927f7b7b3150ca2c580c022"}, + {file = "mlflow_skinny-2.20.3.tar.gz", hash = "sha256:4151f74500611f4c2ee1caf30b0108817b456654b42edbede2503dd6e845ed91"}, ] [[package]] name = "mpmath" version = "1.3.0" summary = "Python library for arbitrary-precision floating-point arithmetic" +groups = ["default"] +marker = "python_version >= \"3.9\"" files = [ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, @@ -1002,73 +1282,135 @@ name = "msgpack" version = "1.1.0" requires_python = ">=3.8" summary = "MessagePack serializer" +groups = ["default"] files = [ + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, + {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, + {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, + {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, + {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, + {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, + {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, + {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, + {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, + {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, + {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, + {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, + {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, + {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, + {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, + {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, ] [[package]] name = "multidict" -version = "6.0.5" -requires_python = ">=3.7" +version = "6.1.0" +requires_python = ">=3.8" summary = "multidict implementation" -files = [ - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +groups = ["default"] +dependencies = [ + "typing-extensions>=4.1.0; python_version < \"3.11\"", +] +files = [ + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] [[package]] name = "mypy" -version = "1.11.1" -requires_python = ">=3.8" +version = "1.15.0" +requires_python = ">=3.9" summary = "Optional static typing for Python" +groups = ["dev"] dependencies = [ "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, - {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, - {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, - {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, - {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, - {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, - {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, - {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, - {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, - {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, + {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, + {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, + {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, + {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, + {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, + {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, + {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, + {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, ] [[package]] @@ -1076,6 +1418,7 @@ name = "mypy-extensions" version = "1.0.0" requires_python = ">=3.5" summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1083,12 +1426,13 @@ files = [ [[package]] name = "networkx" -version = "3.3" +version = "3.4.2" requires_python = ">=3.10" summary = "Python package for creating and manipulating graphs and networks" +groups = ["default"] files = [ - {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"}, - {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"}, + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, ] [[package]] @@ -1096,6 +1440,7 @@ name = "nodeenv" version = "1.9.1" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Node.js virtual environment builder" +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1103,27 +1448,52 @@ files = [ [[package]] name = "numpy" -version = "1.26.4" -requires_python = ">=3.9" +version = "2.2.3" +requires_python = ">=3.10" summary = "Fundamental package for array computing in Python" -files = [ - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +groups = ["default"] +files = [ + {file = "numpy-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:16372619ee728ed67a2a606a614f56d3eabc5b86f8b615c79d01957062826ca8"}, + {file = "numpy-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5521a06a3148686d9269c53b09f7d399a5725c47bbb5b35747e1cb76326b714b"}, + {file = "numpy-2.2.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:7c8dde0ca2f77828815fd1aedfdf52e59071a5bae30dac3b4da2a335c672149a"}, + {file = "numpy-2.2.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:77974aba6c1bc26e3c205c2214f0d5b4305bdc719268b93e768ddb17e3fdd636"}, + {file = "numpy-2.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d42f9c36d06440e34226e8bd65ff065ca0963aeecada587b937011efa02cdc9d"}, + {file = "numpy-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2712c5179f40af9ddc8f6727f2bd910ea0eb50206daea75f58ddd9fa3f715bb"}, + {file = "numpy-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c8b0451d2ec95010d1db8ca733afc41f659f425b7f608af569711097fd6014e2"}, + {file = "numpy-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9b4a8148c57ecac25a16b0e11798cbe88edf5237b0df99973687dd866f05e1b"}, + {file = "numpy-2.2.3-cp311-cp311-win32.whl", hash = "sha256:1f45315b2dc58d8a3e7754fe4e38b6fce132dab284a92851e41b2b344f6441c5"}, + {file = "numpy-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f48ba6f6c13e5e49f3d3efb1b51c8193215c42ac82610a04624906a9270be6f"}, + {file = "numpy-2.2.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12c045f43b1d2915eca6b880a7f4a256f59d62df4f044788c8ba67709412128d"}, + {file = "numpy-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87eed225fd415bbae787f93a457af7f5990b92a334e346f72070bf569b9c9c95"}, + {file = "numpy-2.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:712a64103d97c404e87d4d7c47fb0c7ff9acccc625ca2002848e0d53288b90ea"}, + {file = "numpy-2.2.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a5ae282abe60a2db0fd407072aff4599c279bcd6e9a2475500fc35b00a57c532"}, + {file = "numpy-2.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5266de33d4c3420973cf9ae3b98b54a2a6d53a559310e3236c4b2b06b9c07d4e"}, + {file = "numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe"}, + {file = "numpy-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:34c1b7e83f94f3b564b35f480f5652a47007dd91f7c839f404d03279cc8dd021"}, + {file = "numpy-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4d8335b5f1b6e2bce120d55fb17064b0262ff29b459e8493d1785c18ae2553b8"}, + {file = "numpy-2.2.3-cp312-cp312-win32.whl", hash = "sha256:4d9828d25fb246bedd31e04c9e75714a4087211ac348cb39c8c5f99dbb6683fe"}, + {file = "numpy-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d"}, + {file = "numpy-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bfdb06b395385ea9b91bf55c1adf1b297c9fdb531552845ff1d3ea6e40d5aba"}, + {file = "numpy-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23c9f4edbf4c065fddb10a4f6e8b6a244342d95966a48820c614891e5059bb50"}, + {file = "numpy-2.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:a0c03b6be48aaf92525cccf393265e02773be8fd9551a2f9adbe7db1fa2b60f1"}, + {file = "numpy-2.2.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:2376e317111daa0a6739e50f7ee2a6353f768489102308b0d98fcf4a04f7f3b5"}, + {file = "numpy-2.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fb62fe3d206d72fe1cfe31c4a1106ad2b136fcc1606093aeab314f02930fdf2"}, + {file = "numpy-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52659ad2534427dffcc36aac76bebdd02b67e3b7a619ac67543bc9bfe6b7cdb1"}, + {file = "numpy-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b416af7d0ed3271cad0f0a0d0bee0911ed7eba23e66f8424d9f3dfcdcae1304"}, + {file = "numpy-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1402da8e0f435991983d0a9708b779f95a8c98c6b18a171b9f1be09005e64d9d"}, + {file = "numpy-2.2.3-cp313-cp313-win32.whl", hash = "sha256:136553f123ee2951bfcfbc264acd34a2fc2f29d7cdf610ce7daf672b6fbaa693"}, + {file = "numpy-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5b732c8beef1d7bc2d9e476dbba20aaff6167bf205ad9aa8d30913859e82884b"}, + {file = "numpy-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:435e7a933b9fda8126130b046975a968cc2d833b505475e588339e09f7672890"}, + {file = "numpy-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7678556eeb0152cbd1522b684dcd215250885993dd00adb93679ec3c0e6e091c"}, + {file = "numpy-2.2.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2e8da03bd561504d9b20e7a12340870dfc206c64ea59b4cfee9fceb95070ee94"}, + {file = "numpy-2.2.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:c9aa4496fd0e17e3843399f533d62857cef5900facf93e735ef65aa4bbc90ef0"}, + {file = "numpy-2.2.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4ca91d61a4bf61b0f2228f24bbfa6a9facd5f8af03759fe2a655c50ae2c6610"}, + {file = "numpy-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaa09cd492e24fd9b15296844c0ad1b3c976da7907e1c1ed3a0ad21dded6f76"}, + {file = "numpy-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:246535e2f7496b7ac85deffe932896a3577be7af8fb7eebe7146444680297e9a"}, + {file = "numpy-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:daf43a3d1ea699402c5a850e5313680ac355b4adc9770cd5cfc2940e7861f1bf"}, + {file = "numpy-2.2.3-cp313-cp313t-win32.whl", hash = "sha256:cf802eef1f0134afb81fef94020351be4fe1d6681aadf9c5e862af6602af64ef"}, + {file = "numpy-2.2.3-cp313-cp313t-win_amd64.whl", hash = "sha256:aee2512827ceb6d7f517c8b85aa5d3923afe8fc7a57d028cffcd522f1c6fd082"}, + {file = "numpy-2.2.3.tar.gz", hash = "sha256:dbdc15f0c81611925f382dfa97b3bd0bc2c1ce19d4fe50482cb0ddc12ba30020"}, ] [[package]] @@ -1131,8 +1501,12 @@ name = "nvidia-cublas-cu12" version = "12.4.5.8" requires_python = ">=3" summary = "CUBLAS native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3"}, {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, + {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, ] [[package]] @@ -1140,8 +1514,12 @@ name = "nvidia-cuda-cupti-cu12" version = "12.4.127" requires_python = ">=3" summary = "CUDA profiling tools runtime libs." +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a"}, {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, + {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, ] [[package]] @@ -1149,8 +1527,12 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.4.127" requires_python = ">=3" summary = "NVRTC native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198"}, {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, + {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, ] [[package]] @@ -1158,8 +1540,12 @@ name = "nvidia-cuda-runtime-cu12" version = "12.4.127" requires_python = ">=3" summary = "CUDA Runtime native Libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3"}, {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, + {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, ] [[package]] @@ -1167,6 +1553,8 @@ name = "nvidia-cudnn-cu12" version = "9.1.0.70" requires_python = ">=3" summary = "cuDNN runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" dependencies = [ "nvidia-cublas-cu12", ] @@ -1180,8 +1568,15 @@ name = "nvidia-cufft-cu12" version = "11.2.1.3" requires_python = ">=3" summary = "CUFFT native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +dependencies = [ + "nvidia-nvjitlink-cu12", +] files = [ + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, + {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-win_amd64.whl", hash = "sha256:d802f4954291101186078ccbe22fc285a902136f974d369540fd4a5333d1440b"}, ] [[package]] @@ -1189,8 +1584,12 @@ name = "nvidia-curand-cu12" version = "10.3.5.147" requires_python = ">=3" summary = "CURAND native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9"}, {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, + {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, ] [[package]] @@ -1198,13 +1597,17 @@ name = "nvidia-cusolver-cu12" version = "11.6.1.9" requires_python = ">=3" summary = "CUDA solver native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" dependencies = [ "nvidia-cublas-cu12", "nvidia-cusparse-cu12", "nvidia-nvjitlink-cu12", ] files = [ + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e"}, {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260"}, + {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-win_amd64.whl", hash = "sha256:e77314c9d7b694fcebc84f58989f3aa4fb4cb442f12ca1a9bde50f5e8f6d1b9c"}, ] [[package]] @@ -1212,19 +1615,27 @@ name = "nvidia-cusparse-cu12" version = "12.3.1.170" requires_python = ">=3" summary = "CUSPARSE native runtime libraries" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" dependencies = [ "nvidia-nvjitlink-cu12", ] files = [ + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3"}, {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1"}, + {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-win_amd64.whl", hash = "sha256:9bc90fb087bc7b4c15641521f31c0371e9a612fc2ba12c338d3ae032e6b6797f"}, ] [[package]] name = "nvidia-cusparselt-cu12" version = "0.6.2" summary = "NVIDIA cuSPARSELt" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:067a7f6d03ea0d4841c85f0c6f1991c5dda98211f6302cb83a4ab234ee95bef8"}, {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:df2c24502fd76ebafe7457dbc4716b2fec071aabaed4fb7691a201cde03704d9"}, + {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-win_amd64.whl", hash = "sha256:0057c91d230703924c0422feabe4ce768841f9b4b44d28586b6f6d2eb86fbe70"}, ] [[package]] @@ -1232,6 +1643,8 @@ name = "nvidia-nccl-cu12" version = "2.21.5" requires_python = ">=3" summary = "NVIDIA Collective Communication Library (NCCL) Runtime" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, ] @@ -1241,8 +1654,12 @@ name = "nvidia-nvjitlink-cu12" version = "12.4.127" requires_python = ">=3" summary = "Nvidia JIT LTO Library" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4abe7fef64914ccfa909bc2ba39739670ecc9e820c83ccc7a6ed414122599b83"}, {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"}, + {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, ] [[package]] @@ -1250,8 +1667,12 @@ name = "nvidia-nvtx-cu12" version = "12.4.127" requires_python = ">=3" summary = "NVIDIA Tools Extension" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3"}, {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, + {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, ] [[package]] @@ -1259,6 +1680,7 @@ name = "oauthlib" version = "3.2.2" requires_python = ">=3.6" summary = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +groups = ["default"] files = [ {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, @@ -1269,9 +1691,11 @@ name = "omegaconf" version = "2.3.0" requires_python = ">=3.6" summary = "A flexible configuration library" +groups = ["default"] dependencies = [ "PyYAML>=5.1.0", "antlr4-python3-runtime==4.9.*", + "dataclasses; python_version == \"3.6\"", ] files = [ {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, @@ -1283,183 +1707,216 @@ name = "opencv-python-headless" version = "4.11.0.86" requires_python = ">=3.6" summary = "Wrapper package for OpenCV python bindings." +groups = ["default"] dependencies = [ + "numpy>=1.13.3; python_version < \"3.7\"", "numpy>=1.17.0; python_version >= \"3.7\"", "numpy>=1.17.3; python_version >= \"3.8\"", + "numpy>=1.19.3; python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\"", "numpy>=1.19.3; python_version >= \"3.9\"", + "numpy>=1.21.0; python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\"", "numpy>=1.21.2; python_version >= \"3.10\"", + "numpy>=1.21.4; python_version >= \"3.10\" and platform_system == \"Darwin\"", "numpy>=1.23.5; python_version >= \"3.11\"", + "numpy>=1.26.0; python_version >= \"3.12\"", ] files = [ {file = "opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb"}, {file = "opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b"}, + {file = "opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca"}, ] [[package]] name = "openslide-python" -version = "1.3.1" +version = "1.4.1" requires_python = ">=3.8" summary = "Python interface to OpenSlide" +groups = ["default"] dependencies = [ "Pillow", ] files = [ - {file = "openslide-python-1.3.1.tar.gz", hash = "sha256:0909c6257cd8decfbbd0082e8c0cd94bbe3a89ad31e142cfa9accc8bb959294e"}, - {file = "openslide_python-1.3.1-cp311-cp311-win32.whl", hash = "sha256:c4720598ba39e7b879e757eff31195f8b80d4638dcb0fbb297ca9823039724ae"}, - {file = "openslide_python-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:53a468cd92bdd17cf5b56592242709519c0c7d7028b2f466d20d75264471cc6d"}, - {file = "openslide_python-1.3.1-cp312-cp312-win32.whl", hash = "sha256:d10caf1a1c1e1f598d80e7a5e1a266979ed9bccf9ba8bf45aa34cf04639d9f9e"}, - {file = "openslide_python-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:d834fbca0824b902da9d8541f7c34a3e62496823a42de5ac7bf6c35e4c799678"}, + {file = "openslide_python-1.4.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3715fbed151ce448998a83d4a1c3defb1992c5e7e73d66fa05294bfecec0740c"}, + {file = "openslide_python-1.4.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63a4c01dfc15ceebaf4cd1d14c97e3f4e6658ef1f83b003d7e4e85a1a1aad39"}, + {file = "openslide_python-1.4.1-cp311-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f3015d4f591471d5c39fd7f853e8d3308eb29eff0e4be3938a8c9d97d0b72256"}, + {file = "openslide_python-1.4.1-cp311-abi3-win_amd64.whl", hash = "sha256:57ec66edf3e8f22dd8712071227f2e256fa04a542c99d72bb211d00285ccf0a2"}, + {file = "openslide_python-1.4.1.tar.gz", hash = "sha256:95da570994abd8a02db18b8dac68da0b3d3f7eba733bdeeb2a8b52e40e1de1c8"}, ] [[package]] name = "opentelemetry-api" -version = "1.27.0" +version = "1.30.0" requires_python = ">=3.8" summary = "OpenTelemetry Python API" +groups = ["default"] dependencies = [ "deprecated>=1.2.6", - "importlib-metadata<=8.4.0,>=6.0", + "importlib-metadata<=8.5.0,>=6.0", ] files = [ - {file = "opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7"}, - {file = "opentelemetry_api-1.27.0.tar.gz", hash = "sha256:ed673583eaa5f81b5ce5e86ef7cdaf622f88ef65f0b9aab40b843dcae5bef342"}, + {file = "opentelemetry_api-1.30.0-py3-none-any.whl", hash = "sha256:d5f5284890d73fdf47f843dda3210edf37a38d66f44f2b5aedc1e89ed455dc09"}, + {file = "opentelemetry_api-1.30.0.tar.gz", hash = "sha256:375893400c1435bf623f7dfb3bcd44825fe6b56c34d0667c542ea8257b1a1240"}, ] [[package]] name = "opentelemetry-sdk" -version = "1.27.0" +version = "1.30.0" requires_python = ">=3.8" summary = "OpenTelemetry Python SDK" +groups = ["default"] dependencies = [ - "opentelemetry-api==1.27.0", - "opentelemetry-semantic-conventions==0.48b0", + "opentelemetry-api==1.30.0", + "opentelemetry-semantic-conventions==0.51b0", "typing-extensions>=3.7.4", ] files = [ - {file = "opentelemetry_sdk-1.27.0-py3-none-any.whl", hash = "sha256:365f5e32f920faf0fd9e14fdfd92c086e317eaa5f860edba9cdc17a380d9197d"}, - {file = "opentelemetry_sdk-1.27.0.tar.gz", hash = "sha256:d525017dea0ccce9ba4e0245100ec46ecdc043f2d7b8315d56b19aff0904fa6f"}, + {file = "opentelemetry_sdk-1.30.0-py3-none-any.whl", hash = "sha256:14fe7afc090caad881addb6926cec967129bd9260c4d33ae6a217359f6b61091"}, + {file = "opentelemetry_sdk-1.30.0.tar.gz", hash = "sha256:c9287a9e4a7614b9946e933a67168450b9ab35f08797eb9bc77d998fa480fa18"}, ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.48b0" +version = "0.51b0" requires_python = ">=3.8" summary = "OpenTelemetry Semantic Conventions" +groups = ["default"] dependencies = [ "deprecated>=1.2.6", - "opentelemetry-api==1.27.0", + "opentelemetry-api==1.30.0", ] files = [ - {file = "opentelemetry_semantic_conventions-0.48b0-py3-none-any.whl", hash = "sha256:a0de9f45c413a8669788a38569c7e0a11ce6ce97861a628cca785deecdc32a1f"}, - {file = "opentelemetry_semantic_conventions-0.48b0.tar.gz", hash = "sha256:12d74983783b6878162208be57c9effcb89dc88691c64992d70bb89dc00daa1a"}, + {file = "opentelemetry_semantic_conventions-0.51b0-py3-none-any.whl", hash = "sha256:fdc777359418e8d06c86012c3dc92c88a6453ba662e941593adb062e48c2eeae"}, + {file = "opentelemetry_semantic_conventions-0.51b0.tar.gz", hash = "sha256:3fabf47f35d1fd9aebcdca7e6802d86bd5ebc3bc3408b7e3248dde6e87a18c47"}, ] [[package]] name = "packaging" -version = "24.1" +version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" +groups = ["default"] files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] name = "pandas" -version = "2.2.2" +version = "2.2.3" requires_python = ">=3.9" summary = "Powerful data structures for data analysis, time series, and statistics" +groups = ["default"] dependencies = [ + "numpy>=1.22.4; python_version < \"3.11\"", "numpy>=1.23.2; python_version == \"3.11\"", + "numpy>=1.26.0; python_version >= \"3.12\"", "python-dateutil>=2.8.2", "pytz>=2020.1", "tzdata>=2022.7", ] files = [ - {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"}, - {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"}, - {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"}, - {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"}, - {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"}, - {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"}, - {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"}, - {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, - {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, - {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, + {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, + {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, + {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, + {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, + {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, + {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, + {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, + {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, + {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, + {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, + {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, + {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, + {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, + {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, + {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, + {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, ] [[package]] name = "pillow" -version = "10.4.0" -requires_python = ">=3.8" +version = "11.1.0" +requires_python = ">=3.9" summary = "Python Imaging Library (Fork)" -files = [ - {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, - {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, - {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, - {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, - {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, - {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, - {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, - {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, - {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, - {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, - {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, -] - -[[package]] -name = "pkgconfig" -version = "1.5.5" -requires_python = ">=3.3,<4.0" -summary = "Interface Python with pkg-config" -files = [ - {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, - {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, +groups = ["default"] +files = [ + {file = "pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457"}, + {file = "pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6"}, + {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1"}, + {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2"}, + {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96"}, + {file = "pillow-11.1.0-cp311-cp311-win32.whl", hash = "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f"}, + {file = "pillow-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761"}, + {file = "pillow-11.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71"}, + {file = "pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a"}, + {file = "pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1"}, + {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f"}, + {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91"}, + {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c"}, + {file = "pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6"}, + {file = "pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf"}, + {file = "pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5"}, + {file = "pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc"}, + {file = "pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5"}, + {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114"}, + {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352"}, + {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3"}, + {file = "pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9"}, + {file = "pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c"}, + {file = "pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65"}, + {file = "pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861"}, + {file = "pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081"}, + {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c"}, + {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547"}, + {file = "pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab"}, + {file = "pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9"}, + {file = "pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe"}, + {file = "pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756"}, + {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, ] [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["dev"] files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [[package]] name = "pre-commit" -version = "3.8.0" +version = "4.1.0" requires_python = ">=3.9" summary = "A framework for managing and maintaining multi-language pre-commit hooks." +groups = ["dev"] dependencies = [ "cfgv>=2.0.0", "identify>=1.0.0", @@ -1468,72 +1925,161 @@ dependencies = [ "virtualenv>=20.10.0", ] files = [ - {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, - {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, + {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, + {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, +] + +[[package]] +name = "propcache" +version = "0.3.0" +requires_python = ">=3.9" +summary = "Accelerated property cache" +groups = ["default"] +files = [ + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, + {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, + {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, + {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, + {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, + {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, + {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, + {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, + {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, + {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, + {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, + {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, + {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, + {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, + {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, + {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, + {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, + {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, + {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, + {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, + {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, + {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, + {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, ] [[package]] name = "protobuf" -version = "5.28.0" +version = "5.29.3" requires_python = ">=3.8" summary = "" +groups = ["default"] files = [ - {file = "protobuf-5.28.0-cp310-abi3-win32.whl", hash = "sha256:66c3edeedb774a3508ae70d87b3a19786445fe9a068dd3585e0cefa8a77b83d0"}, - {file = "protobuf-5.28.0-cp310-abi3-win_amd64.whl", hash = "sha256:6d7cc9e60f976cf3e873acb9a40fed04afb5d224608ed5c1a105db4a3f09c5b6"}, - {file = "protobuf-5.28.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:532627e8fdd825cf8767a2d2b94d77e874d5ddb0adefb04b237f7cc296748681"}, - {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:018db9056b9d75eb93d12a9d35120f97a84d9a919bcab11ed56ad2d399d6e8dd"}, - {file = "protobuf-5.28.0-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:6206afcb2d90181ae8722798dcb56dc76675ab67458ac24c0dd7d75d632ac9bd"}, - {file = "protobuf-5.28.0-py3-none-any.whl", hash = "sha256:510ed78cd0980f6d3218099e874714cdf0d8a95582e7b059b06cabad855ed0a0"}, - {file = "protobuf-5.28.0.tar.gz", hash = "sha256:dde74af0fa774fa98892209992295adbfb91da3fa98c8f67a88afe8f5a349add"}, + {file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"}, + {file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"}, + {file = "protobuf-5.29.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e"}, + {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84"}, + {file = "protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f"}, + {file = "protobuf-5.29.3-py3-none-any.whl", hash = "sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f"}, + {file = "protobuf-5.29.3.tar.gz", hash = "sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620"}, ] [[package]] name = "pyarrow" -version = "17.0.0" -requires_python = ">=3.8" +version = "19.0.1" +requires_python = ">=3.9" summary = "Python library for Apache Arrow" -dependencies = [ - "numpy>=1.16.6", -] -files = [ - {file = "pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977"}, - {file = "pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3"}, - {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15"}, - {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597"}, - {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420"}, - {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4"}, - {file = "pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03"}, - {file = "pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22"}, - {file = "pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053"}, - {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a"}, - {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc"}, - {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a"}, - {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b"}, - {file = "pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7"}, - {file = "pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28"}, +groups = ["default"] +files = [ + {file = "pyarrow-19.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc55d71898ea30dc95900297d191377caba257612f384207fe9f8293b5850f90"}, + {file = "pyarrow-19.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:7a544ec12de66769612b2d6988c36adc96fb9767ecc8ee0a4d270b10b1c51e00"}, + {file = "pyarrow-19.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0148bb4fc158bfbc3d6dfe5001d93ebeed253793fff4435167f6ce1dc4bddeae"}, + {file = "pyarrow-19.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f24faab6ed18f216a37870d8c5623f9c044566d75ec586ef884e13a02a9d62c5"}, + {file = "pyarrow-19.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4982f8e2b7afd6dae8608d70ba5bd91699077323f812a0448d8b7abdff6cb5d3"}, + {file = "pyarrow-19.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:49a3aecb62c1be1d822f8bf629226d4a96418228a42f5b40835c1f10d42e4db6"}, + {file = "pyarrow-19.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:008a4009efdb4ea3d2e18f05cd31f9d43c388aad29c636112c2966605ba33466"}, + {file = "pyarrow-19.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:80b2ad2b193e7d19e81008a96e313fbd53157945c7be9ac65f44f8937a55427b"}, + {file = "pyarrow-19.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:ee8dec072569f43835932a3b10c55973593abc00936c202707a4ad06af7cb294"}, + {file = "pyarrow-19.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d5d1ec7ec5324b98887bdc006f4d2ce534e10e60f7ad995e7875ffa0ff9cb14"}, + {file = "pyarrow-19.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ad4c0eb4e2a9aeb990af6c09e6fa0b195c8c0e7b272ecc8d4d2b6574809d34"}, + {file = "pyarrow-19.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d383591f3dcbe545f6cc62daaef9c7cdfe0dff0fb9e1c8121101cabe9098cfa6"}, + {file = "pyarrow-19.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b4c4156a625f1e35d6c0b2132635a237708944eb41df5fbe7d50f20d20c17832"}, + {file = "pyarrow-19.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:5bd1618ae5e5476b7654c7b55a6364ae87686d4724538c24185bbb2952679960"}, + {file = "pyarrow-19.0.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e45274b20e524ae5c39d7fc1ca2aa923aab494776d2d4b316b49ec7572ca324c"}, + {file = "pyarrow-19.0.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d9dedeaf19097a143ed6da37f04f4051aba353c95ef507764d344229b2b740ae"}, + {file = "pyarrow-19.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ebfb5171bb5f4a52319344ebbbecc731af3f021e49318c74f33d520d31ae0c4"}, + {file = "pyarrow-19.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a21d39fbdb948857f67eacb5bbaaf36802de044ec36fbef7a1c8f0dd3a4ab2"}, + {file = "pyarrow-19.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:99bc1bec6d234359743b01e70d4310d0ab240c3d6b0da7e2a93663b0158616f6"}, + {file = "pyarrow-19.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1b93ef2c93e77c442c979b0d596af45e4665d8b96da598db145b0fec014b9136"}, + {file = "pyarrow-19.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9d46e06846a41ba906ab25302cf0fd522f81aa2a85a71021826f34639ad31ef"}, + {file = "pyarrow-19.0.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c0fe3dbbf054a00d1f162fda94ce236a899ca01123a798c561ba307ca38af5f0"}, + {file = "pyarrow-19.0.1-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:96606c3ba57944d128e8a8399da4812f56c7f61de8c647e3470b417f795d0ef9"}, + {file = "pyarrow-19.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f04d49a6b64cf24719c080b3c2029a3a5b16417fd5fd7c4041f94233af732f3"}, + {file = "pyarrow-19.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a9137cf7e1640dce4c190551ee69d478f7121b5c6f323553b319cac936395f6"}, + {file = "pyarrow-19.0.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7c1bca1897c28013db5e4c83944a2ab53231f541b9e0c3f4791206d0c0de389a"}, + {file = "pyarrow-19.0.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:58d9397b2e273ef76264b45531e9d552d8ec8a6688b7390b5be44c02a37aade8"}, + {file = "pyarrow-19.0.1.tar.gz", hash = "sha256:3bf266b485df66a400f282ac0b6d1b500b9d2ae73314a153dbe97d6d5cc8a99e"}, ] [[package]] name = "pyasn1" -version = "0.6.0" +version = "0.6.1" requires_python = ">=3.8" summary = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +groups = ["default"] files = [ - {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, - {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, ] [[package]] name = "pyasn1-modules" -version = "0.4.0" +version = "0.4.1" requires_python = ">=3.8" summary = "A collection of ASN.1-based protocols modules" +groups = ["default"] dependencies = [ "pyasn1<0.7.0,>=0.4.6", ] files = [ - {file = "pyasn1_modules-0.4.0-py3-none-any.whl", hash = "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b"}, - {file = "pyasn1_modules-0.4.0.tar.gz", hash = "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6"}, + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] [[package]] @@ -1541,6 +2087,7 @@ name = "pycparser" version = "2.22" requires_python = ">=3.8" summary = "C parser in Python" +groups = ["default"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1551,6 +2098,7 @@ name = "pydantic" version = "2.10.6" requires_python = ">=3.8" summary = "Data validation using Python type hints" +groups = ["default"] dependencies = [ "annotated-types>=0.6.0", "pydantic-core==2.27.2", @@ -1566,22 +2114,65 @@ name = "pydantic-core" version = "2.27.2" requires_python = ">=3.8" summary = "Core functionality for Pydantic validation and serialization" +groups = ["default"] dependencies = [ "typing-extensions!=4.7.0,>=4.6.0", ] files = [ + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, ] [[package]] name = "pyparsing" -version = "3.1.4" -requires_python = ">=3.6.8" +version = "3.2.1" +requires_python = ">=3.9" summary = "pyparsing module - Classes and methods to define and execute parsing grammars" +groups = ["default"] files = [ - {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, - {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, + {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, + {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, ] [[package]] @@ -1589,6 +2180,7 @@ name = "python-dateutil" version = "2.9.0.post0" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Extensions to the standard Python datetime module" +groups = ["default"] dependencies = [ "six>=1.5", ] @@ -1599,9 +2191,10 @@ files = [ [[package]] name = "pytorch-lightning" -version = "2.4.0" -requires_python = ">=3.8" +version = "2.5.0.post0" +requires_python = ">=3.9" summary = "PyTorch Lightning is the lightweight PyTorch wrapper for ML researchers. Scale your models. Write less boilerplate." +groups = ["default"] dependencies = [ "PyYAML>=5.4", "fsspec[http]>=2022.5.0", @@ -1613,36 +2206,56 @@ dependencies = [ "typing-extensions>=4.4.0", ] files = [ - {file = "pytorch-lightning-2.4.0.tar.gz", hash = "sha256:6aa897fd9d6dfa7b7b49f37c2f04e13592861831d08deae584dfda423fdb71c8"}, - {file = "pytorch_lightning-2.4.0-py3-none-any.whl", hash = "sha256:9ac7935229ac022ef06994c928217ed37f525ac6700f7d4fc57009624570e655"}, + {file = "pytorch_lightning-2.5.0.post0-py3-none-any.whl", hash = "sha256:c86bf4fded58b386f312f75337696a9b2d57077b858b3b9524400a03a0179b3a"}, + {file = "pytorch_lightning-2.5.0.post0.tar.gz", hash = "sha256:347235bf8573b4ebcf507a0dd755fcb9ce58c420c77220a9756a6edca0418532"}, ] [[package]] name = "pytz" -version = "2024.1" +version = "2025.1" summary = "World timezone definitions, modern and historical" +groups = ["default"] files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, + {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, ] [[package]] name = "pyvips" version = "2.2.3" -summary = "binding for the libvips image processing library, API mode" +summary = "binding for the libvips image processing library, ABI mode" +groups = ["default"] dependencies = [ "cffi>=1.0.0", - "pkgconfig", ] files = [ {file = "pyvips-2.2.3.tar.gz", hash = "sha256:43bceced0db492654c93008246a58a508e0373ae1621116b87b322f2ac72212f"}, ] +[[package]] +name = "pywin32" +version = "308" +summary = "Python for Window Extensions" +groups = ["default"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, +] + [[package]] name = "pyyaml" version = "6.0.2" requires_python = ">=3.8" summary = "YAML parser and emitter for Python" +groups = ["default", "dev"] files = [ {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, @@ -1681,6 +2294,7 @@ requires_python = ">=3.11" git = "ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git" revision = "7ce565cc35bfd1abe30db2e1e4e606e65dda8c84" summary = "A simple CLI tool for managing Kubernetes jobs." +groups = ["default"] dependencies = [ "click>=8.1.7", "kubernetes>=31.0.0", @@ -1688,11 +2302,12 @@ dependencies = [ [[package]] name = "rationai-masks" -version = "1.0.0" +version = "1.1.0" requires_python = ">=3.11" git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git" -revision = "7d56f2ba3c7b411bdf6043ae1224676c745317d2" +revision = "91b2a2a2e288417e9bdd0fd83ddd4f04af449dec" summary = "" +groups = ["default"] dependencies = [ "numpy>=1.9.0", "openslide-python>=1.3.1", @@ -1700,47 +2315,53 @@ dependencies = [ "pillow>=10.4.0", "pyvips>=2.2.3", "ray>=2.34.0", + "torch>=2.5.1", "tqdm>=4.66.5", ] [[package]] name = "rationai-mlkit" -version = "0.1.15" +version = "0.2.0" requires_python = ">=3.11" git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git" -revision = "19712cca6931f11d25292cd35c5678b53592b5e7" +revision = "233ead782353b3f23eee75702576f5c004cf300e" summary = "" +groups = ["default"] dependencies = [ "GitPython>=3.1.43", "hydra-core>=1.3.2", "lightning>=2.2.4", "mlflow>=2.12.1", "openslide-python>=1.3.1", + "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", "torch>=2.2.0", ] [[package]] name = "rationai-tiling" -version = "1.0.0" +version = "1.1.0" requires_python = ">=3.11" git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git" -revision = "5889fc70093e097684f6014dab8ad5d0616e14fd" +revision = "9096ada81542c172908dff5b2766cf729786471b" summary = "" +groups = ["default"] dependencies = [ "mlflow>=2.15.1", "numpy>=1.9.0", "openslide-python>=1.3.1", "pandas>=2.2.2", "pyvips>=2.2.3", + "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", "ray>=2.34.0", "tqdm>=4.66.5", ] [[package]] name = "ray" -version = "2.38.0" +version = "2.43.0" requires_python = ">=3.9" summary = "Ray provides a simple, universal API for building distributed applications." +groups = ["default"] dependencies = [ "aiosignal", "click>=7.0", @@ -1754,21 +2375,32 @@ dependencies = [ "requests", ] files = [ - {file = "ray-2.38.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:ece802cf3a1c102b53f63b8bc90d947971c4b387deaf233c224ed8ef34a1f3cb"}, + {file = "ray-2.43.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fde8a81280f07af983bc3769c9941db5db273ce10e92abb3348e41bed023d735"}, + {file = "ray-2.43.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e93c32ad0cb67f1f7da76fac409d87d5cd5ea3eb03b836830e9ef5cc810bc2c0"}, + {file = "ray-2.43.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:476ec3e1fa2464ddd5f049c0f2758ff9dfecc21fb8df4266f1df01b2780c6653"}, + {file = "ray-2.43.0-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:78c3bdbf182b4d019fa9a8aabd55c39bf705bb630aea064f768f305fc472d1eb"}, + {file = "ray-2.43.0-cp311-cp311-win_amd64.whl", hash = "sha256:e2b0fa0272ade67bad2e83d7de996795bfb4f10f4b895476b95fbfda6d3c3ed6"}, + {file = "ray-2.43.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:5121fdf4bcbcb0fda3b9b71164dd6c8fcc79a2e258022a2a3957e401018913fb"}, + {file = "ray-2.43.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f26f7b72da04c3c4422269c31b067abd15cb38424b7012d812ddfb2c77462ea"}, + {file = "ray-2.43.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:73770d4c8a989730985ff2b4292129249e28c1e29e84589470c9ba1ae91ca832"}, + {file = "ray-2.43.0-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:b45f478d29ce5df3fc19861df64fef9ed5c25f1e83fa10028d33fadefdeca095"}, + {file = "ray-2.43.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c3a9880112a8d561280a34e8ef9471070f81ca467e08b669e5e77a85e173c9c"}, ] [[package]] name = "referencing" -version = "0.35.1" -requires_python = ">=3.8" +version = "0.36.2" +requires_python = ">=3.9" summary = "JSON Referencing + Python" +groups = ["default"] dependencies = [ "attrs>=22.2.0", "rpds-py>=0.7.0", + "typing-extensions>=4.4.0; python_version < \"3.13\"", ] files = [ - {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, - {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, + {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"}, + {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"}, ] [[package]] @@ -1776,6 +2408,7 @@ name = "requests" version = "2.32.3" requires_python = ">=3.8" summary = "Python HTTP for Humans." +groups = ["default"] dependencies = [ "certifi>=2017.4.17", "charset-normalizer<4,>=2", @@ -1792,6 +2425,7 @@ name = "requests-oauthlib" version = "2.0.0" requires_python = ">=3.4" summary = "OAuthlib authentication support for Requests." +groups = ["default"] dependencies = [ "oauthlib>=3.0.0", "requests>=2.0.0", @@ -1803,12 +2437,64 @@ files = [ [[package]] name = "rpds-py" -version = "0.21.0" +version = "0.23.1" requires_python = ">=3.9" summary = "Python bindings to Rust's persistent data structures (rpds)" -files = [ - {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d"}, - {file = "rpds_py-0.21.0.tar.gz", hash = "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db"}, +groups = ["default"] +files = [ + {file = "rpds_py-0.23.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590"}, + {file = "rpds_py-0.23.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580"}, + {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35"}, + {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522"}, + {file = "rpds_py-0.23.1-cp311-cp311-win32.whl", hash = "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6"}, + {file = "rpds_py-0.23.1-cp311-cp311-win_amd64.whl", hash = "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf"}, + {file = "rpds_py-0.23.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c"}, + {file = "rpds_py-0.23.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc"}, + {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef"}, + {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad"}, + {file = "rpds_py-0.23.1-cp312-cp312-win32.whl", hash = "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057"}, + {file = "rpds_py-0.23.1-cp312-cp312-win_amd64.whl", hash = "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165"}, + {file = "rpds_py-0.23.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935"}, + {file = "rpds_py-0.23.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013"}, + {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957"}, + {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93"}, + {file = "rpds_py-0.23.1-cp313-cp313-win32.whl", hash = "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd"}, + {file = "rpds_py-0.23.1-cp313-cp313-win_amd64.whl", hash = "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70"}, + {file = "rpds_py-0.23.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731"}, + {file = "rpds_py-0.23.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722"}, + {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b"}, + {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5"}, + {file = "rpds_py-0.23.1-cp313-cp313t-win32.whl", hash = "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7"}, + {file = "rpds_py-0.23.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d"}, + {file = "rpds_py-0.23.1.tar.gz", hash = "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707"}, ] [[package]] @@ -1816,6 +2502,7 @@ name = "rsa" version = "4.9" requires_python = ">=3.6,<4" summary = "Pure-Python RSA implementation" +groups = ["default"] dependencies = [ "pyasn1>=0.1.3", ] @@ -1826,28 +2513,65 @@ files = [ [[package]] name = "ruff" -version = "0.6.0" +version = "0.9.9" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." -files = [ - {file = "ruff-0.6.0-py3-none-linux_armv6l.whl", hash = "sha256:92dcce923e5df265781e5fc76f9a1edad52201a7aafe56e586b90988d5239013"}, - {file = "ruff-0.6.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:31b90ff9dc79ed476c04e957ba7e2b95c3fceb76148f2079d0d68a908d2cfae7"}, - {file = "ruff-0.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d834a9ec9f8287dd6c3297058b3a265ed6b59233db22593379ee38ebc4b9768"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2089267692696aba342179471831a085043f218706e642564812145df8b8d0d"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa62b423ee4bbd8765f2c1dbe8f6aac203e0583993a91453dc0a449d465c84da"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7344e1a964b16b1137ea361d6516ce4ee61a0403fa94252a1913ecc1311adcae"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:487f3a35c3f33bf82be212ce15dc6278ea854e35573a3f809442f73bec8b2760"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75db409984077a793cf344d499165298a6f65449e905747ac65983b12e3e64b1"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84908bd603533ecf1db456d8fc2665d1f4335d722e84bc871d3bbd2d1116c272"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f1749a0aef3ec41ed91a0e2127a6ae97d2e2853af16dbd4f3c00d7a3af726c5"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:016fea751e2bcfbbd2f8cb19b97b37b3fd33148e4df45b526e87096f4e17354f"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6ae80f141b53b2e36e230017e64f5ea2def18fac14334ffceaae1b780d70c4f7"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:eaaaf33ea4b3f63fd264d6a6f4a73fa224bbfda4b438ffea59a5340f4afa2bb5"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7667ddd1fc688150a7ca4137140867584c63309695a30016880caf20831503a0"}, - {file = "ruff-0.6.0-py3-none-win32.whl", hash = "sha256:ae48365aae60d40865a412356f8c6f2c0be1c928591168111eaf07eaefa6bea3"}, - {file = "ruff-0.6.0-py3-none-win_amd64.whl", hash = "sha256:774032b507c96f0c803c8237ce7d2ef3934df208a09c40fa809c2931f957fe5e"}, - {file = "ruff-0.6.0-py3-none-win_arm64.whl", hash = "sha256:a5366e8c3ae6b2dc32821749b532606c42e609a99b0ae1472cf601da931a048c"}, - {file = "ruff-0.6.0.tar.gz", hash = "sha256:272a81830f68f9bd19d49eaf7fa01a5545c5a2e86f32a9935bb0e4bb9a1db5b8"}, +groups = ["dev"] +files = [ + {file = "ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367"}, + {file = "ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7"}, + {file = "ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb"}, + {file = "ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57"}, + {file = "ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e"}, + {file = "ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1"}, + {file = "ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1"}, + {file = "ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf"}, + {file = "ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933"}, +] + +[[package]] +name = "scikit-image" +version = "0.25.2" +requires_python = ">=3.10" +summary = "Image processing in Python" +groups = ["default"] +dependencies = [ + "imageio!=2.35.0,>=2.33", + "lazy-loader>=0.4", + "networkx>=3.0", + "numpy>=1.24", + "packaging>=21", + "pillow>=10.1", + "scipy>=1.11.4", + "tifffile>=2022.8.12", +] +files = [ + {file = "scikit_image-0.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f4bac9196fb80d37567316581c6060763b0f4893d3aca34a9ede3825bc035b17"}, + {file = "scikit_image-0.25.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d989d64ff92e0c6c0f2018c7495a5b20e2451839299a018e0e5108b2680f71e0"}, + {file = "scikit_image-0.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2cfc96b27afe9a05bc92f8c6235321d3a66499995675b27415e0d0c76625173"}, + {file = "scikit_image-0.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24cc986e1f4187a12aa319f777b36008764e856e5013666a4a83f8df083c2641"}, + {file = "scikit_image-0.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:b4f6b61fc2db6340696afe3db6b26e0356911529f5f6aee8c322aa5157490c9b"}, + {file = "scikit_image-0.25.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8db8dd03663112783221bf01ccfc9512d1cc50ac9b5b0fe8f4023967564719fb"}, + {file = "scikit_image-0.25.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:483bd8cc10c3d8a7a37fae36dfa5b21e239bd4ee121d91cad1f81bba10cfb0ed"}, + {file = "scikit_image-0.25.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d1e80107bcf2bf1291acfc0bf0425dceb8890abe9f38d8e94e23497cbf7ee0d"}, + {file = "scikit_image-0.25.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a17e17eb8562660cc0d31bb55643a4da996a81944b82c54805c91b3fe66f4824"}, + {file = "scikit_image-0.25.2-cp312-cp312-win_amd64.whl", hash = "sha256:bdd2b8c1de0849964dbc54037f36b4e9420157e67e45a8709a80d727f52c7da2"}, + {file = "scikit_image-0.25.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7efa888130f6c548ec0439b1a7ed7295bc10105458a421e9bf739b457730b6da"}, + {file = "scikit_image-0.25.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dd8011efe69c3641920614d550f5505f83658fe33581e49bed86feab43a180fc"}, + {file = "scikit_image-0.25.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28182a9d3e2ce3c2e251383bdda68f8d88d9fff1a3ebe1eb61206595c9773341"}, + {file = "scikit_image-0.25.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8abd3c805ce6944b941cfed0406d88faeb19bab3ed3d4b50187af55cf24d147"}, + {file = "scikit_image-0.25.2-cp313-cp313-win_amd64.whl", hash = "sha256:64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f"}, + {file = "scikit_image-0.25.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330d061bd107d12f8d68f1d611ae27b3b813b8cdb0300a71d07b1379178dd4cd"}, + {file = "scikit_image-0.25.2.tar.gz", hash = "sha256:e5a37e6cd4d0c018a7a55b9d601357e3382826d3888c10d0213fc63bff977dde"}, ] [[package]] @@ -1855,6 +2579,7 @@ name = "scikit-learn" version = "1.6.1" requires_python = ">=3.9" summary = "A set of python modules for machine learning and data mining" +groups = ["default"] dependencies = [ "joblib>=1.2.0", "numpy>=1.19.5", @@ -1862,128 +2587,279 @@ dependencies = [ "threadpoolctl>=3.1.0", ] files = [ + {file = "scikit_learn-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72abc587c75234935e97d09aa4913a82f7b03ee0b74111dcc2881cba3c5a7b33"}, + {file = "scikit_learn-1.6.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b3b00cdc8f1317b5f33191df1386c0befd16625f49d979fe77a8d44cae82410d"}, + {file = "scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc4765af3386811c3ca21638f63b9cf5ecf66261cc4815c1db3f1e7dc7b79db2"}, {file = "scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25fc636bdaf1cc2f4a124a116312d837148b5e10872147bdaf4887926b8c03d8"}, + {file = "scikit_learn-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:fa909b1a36e000a03c382aade0bd2063fd5680ff8b8e501660c0f59f021a6415"}, + {file = "scikit_learn-1.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:926f207c804104677af4857b2c609940b743d04c4c35ce0ddc8ff4f053cddc1b"}, + {file = "scikit_learn-1.6.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c2cae262064e6a9b77eee1c8e768fc46aa0b8338c6a8297b9b6759720ec0ff2"}, + {file = "scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1061b7c028a8663fb9a1a1baf9317b64a257fcb036dae5c8752b2abef31d136f"}, + {file = "scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e69fab4ebfc9c9b580a7a80111b43d214ab06250f8a7ef590a4edf72464dd86"}, + {file = "scikit_learn-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:70b1d7e85b1c96383f872a519b3375f92f14731e279a7b4c6cfd650cf5dffc52"}, + {file = "scikit_learn-1.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ffa1e9e25b3d93990e74a4be2c2fc61ee5af85811562f1288d5d055880c4322"}, + {file = "scikit_learn-1.6.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dc5cf3d68c5a20ad6d571584c0750ec641cc46aeef1c1507be51300e6003a7e1"}, + {file = "scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c06beb2e839ecc641366000ca84f3cf6fa9faa1777e29cf0c04be6e4d096a348"}, + {file = "scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8ca8cb270fee8f1f76fa9bfd5c3507d60c6438bbee5687f81042e2bb98e5a97"}, + {file = "scikit_learn-1.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:7a1c43c8ec9fde528d664d947dc4c0789be4077a3647f232869f41d9bf50e0fb"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a17c1dea1d56dcda2fac315712f3651a1fea86565b64b48fa1bc090249cbf236"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a7aa5f9908f0f28f4edaa6963c0a6183f1911e63a69aa03782f0d924c830a35"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0650e730afb87402baa88afbf31c07b84c98272622aaba002559b614600ca691"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:3f59fe08dc03ea158605170eb52b22a105f238a5d512c4470ddeca71feae8e5f"}, {file = "scikit_learn-1.6.1.tar.gz", hash = "sha256:b4fc2525eca2c69a59260f583c56a7557c6ccdf8deafdba6e060f94c1c59738e"}, ] [[package]] name = "scipy" -version = "1.14.1" +version = "1.15.2" requires_python = ">=3.10" summary = "Fundamental algorithms for scientific computing in Python" -dependencies = [ - "numpy<2.3,>=1.23.5", -] -files = [ - {file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"}, - {file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"}, - {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"}, - {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"}, - {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"}, - {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"}, - {file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"}, - {file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"}, - {file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"}, - {file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"}, - {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"}, - {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"}, - {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"}, - {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"}, - {file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"}, - {file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"}, - {file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"}, - {file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"}, - {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"}, - {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"}, - {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"}, - {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"}, - {file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"}, - {file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"}, - {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"}, +groups = ["default"] +dependencies = [ + "numpy<2.5,>=1.23.5", +] +files = [ + {file = "scipy-1.15.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:92233b2df6938147be6fa8824b8136f29a18f016ecde986666be5f4d686a91a4"}, + {file = "scipy-1.15.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:62ca1ff3eb513e09ed17a5736929429189adf16d2d740f44e53270cc800ecff1"}, + {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4c6676490ad76d1c2894d77f976144b41bd1a4052107902238047fb6a473e971"}, + {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8bf5cb4a25046ac61d38f8d3c3426ec11ebc350246a4642f2f315fe95bda655"}, + {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a8e34cf4c188b6dd004654f88586d78f95639e48a25dfae9c5e34a6dc34547e"}, + {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28a0d2c2075946346e4408b211240764759e0fabaeb08d871639b5f3b1aca8a0"}, + {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:42dabaaa798e987c425ed76062794e93a243be8f0f20fff6e7a89f4d61cb3d40"}, + {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f5e296ec63c5da6ba6fa0343ea73fd51b8b3e1a300b0a8cae3ed4b1122c7462"}, + {file = "scipy-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:597a0c7008b21c035831c39927406c6181bcf8f60a73f36219b69d010aa04737"}, + {file = "scipy-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c4697a10da8f8765bb7c83e24a470da5797e37041edfd77fd95ba3811a47c4fd"}, + {file = "scipy-1.15.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:869269b767d5ee7ea6991ed7e22b3ca1f22de73ab9a49c44bad338b725603301"}, + {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bad78d580270a4d32470563ea86c6590b465cb98f83d760ff5b0990cb5518a93"}, + {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b09ae80010f52efddb15551025f9016c910296cf70adbf03ce2a8704f3a5ad20"}, + {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a6fd6eac1ce74a9f77a7fc724080d507c5812d61e72bd5e4c489b042455865e"}, + {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8"}, + {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:03205d57a28e18dfd39f0377d5002725bf1f19a46f444108c29bdb246b6c8a11"}, + {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:601881dfb761311045b03114c5fe718a12634e5608c3b403737ae463c9885d53"}, + {file = "scipy-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:e7c68b6a43259ba0aab737237876e5c2c549a031ddb7abc28c7b47f22e202ded"}, + {file = "scipy-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01edfac9f0798ad6b46d9c4c9ca0e0ad23dbf0b1eb70e96adb9fa7f525eff0bf"}, + {file = "scipy-1.15.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:08b57a9336b8e79b305a143c3655cc5bdbe6d5ece3378578888d2afbb51c4e37"}, + {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:54c462098484e7466362a9f1672d20888f724911a74c22ae35b61f9c5919183d"}, + {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:cf72ff559a53a6a6d77bd8eefd12a17995ffa44ad86c77a5df96f533d4e6c6bb"}, + {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de9d1416b3d9e7df9923ab23cd2fe714244af10b763975bea9e4f2e81cebd27"}, + {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb530e4794fc8ea76a4a21ccb67dea33e5e0e60f07fc38a49e821e1eae3b71a0"}, + {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5ea7ed46d437fc52350b028b1d44e002646e28f3e8ddc714011aaf87330f2f32"}, + {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11e7ad32cf184b74380f43d3c0a706f49358b904fa7d5345f16ddf993609184d"}, + {file = "scipy-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:a5080a79dfb9b78b768cebf3c9dcbc7b665c5875793569f48bf0e2b1d7f68f6f"}, + {file = "scipy-1.15.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:447ce30cee6a9d5d1379087c9e474628dab3db4a67484be1b7dc3196bfb2fac9"}, + {file = "scipy-1.15.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c90ebe8aaa4397eaefa8455a8182b164a6cc1d59ad53f79943f266d99f68687f"}, + {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:def751dd08243934c884a3221156d63e15234a3155cf25978b0a668409d45eb6"}, + {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:302093e7dfb120e55515936cb55618ee0b895f8bcaf18ff81eca086c17bd80af"}, + {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd5b77413e1855351cdde594eca99c1f4a588c2d63711388b6a1f1c01f62274"}, + {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d0194c37037707b2afa7a2f2a924cf7bac3dc292d51b6a925e5fcb89bc5c776"}, + {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:bae43364d600fdc3ac327db99659dcb79e6e7ecd279a75fe1266669d9a652828"}, + {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f031846580d9acccd0044efd1a90e6f4df3a6e12b4b6bd694a7bc03a89892b28"}, + {file = "scipy-1.15.2-cp313-cp313t-win_amd64.whl", hash = "sha256:fe8a9eb875d430d81755472c5ba75e84acc980e4a8f6204d402849234d3017db"}, + {file = "scipy-1.15.2.tar.gz", hash = "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec"}, ] [[package]] name = "setuptools" -version = "72.2.0" -requires_python = ">=3.8" +version = "75.8.2" +requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" +groups = ["default"] files = [ - {file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"}, - {file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"}, + {file = "setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f"}, + {file = "setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2"}, ] [[package]] name = "simsimd" version = "6.2.1" summary = "Portable mixed-precision BLAS-like vector math library for x86 and ARM" -files = [ +groups = ["default"] +files = [ + {file = "simsimd-6.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e9614309af75be4d08a051dc61ed5cf41b5239b8303b37dc2f9c8a7223534392"}, + {file = "simsimd-6.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea4f0f68be5f85bbcf4322bfdd1b449176cf5fdd99960c546514457635632443"}, + {file = "simsimd-6.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:12a8d60ccc8991dfbbf056c221ce4f02135f5892492894972f421a6f155015d9"}, + {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a74142ea21a6fd3ec5c64e4d4acf1ec6f4d80c0bb1a5989d68af6e84f7ac612e"}, + {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298f7c793fc2a1eeedcefa1278eb2ef6f52ce0b36aaa8780885f96a39ce1a4e8"}, + {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4025ebad36fb3fa5cffcd48d33375d5e5decc59c1129a259b74fed097eab1ab5"}, + {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f486682aa7a8918d86df411d3c11c635db4b67d514cb6bb499c0edab7fb8ec58"}, {file = "simsimd-6.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173e66699597a4fcf6fa50b52cced40216fdcfba15f60b761a2bd9cb1d98a444"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b5c6f79f797cc020a2ff64950162dfb6d130c51a07cdac5ad97ec836e85ce50"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:25812637f43feaef1a33ae00b81a4d2b0116aadae3a08267486c1e57236fc368"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:592a578c788a9cb7877eff41487cc7f50474e00f774de74bea8590fa95c804ae"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:191c020f312350ac06eee829376b11d8c1282da8fefb4381fe0625edfb678d8d"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9ad2c247ed58ba9bb170a01295cb315a45c817775cc7e51ad342f70978a1057"}, + {file = "simsimd-6.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0ff603134600da12175e66b842b7a7331c827fa070d1d8b63386a40bc8d09fcd"}, + {file = "simsimd-6.2.1-cp311-cp311-win32.whl", hash = "sha256:99dff4e04663c82284152ecc2e8bf76b2825f3f17e179abf7892e06196061056"}, + {file = "simsimd-6.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0efc6343c440a26cf16463c4c667655af9597bcbd55ad66f33a80b2b84de7412"}, + {file = "simsimd-6.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:2d364f2c24dd38578bf0eec436c4b901c900ae1893680f46eb5632e01330d814"}, + {file = "simsimd-6.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9b3315e41bb759dc038ecd6f4fa7bcf278bf72ee7d982f752482cdc732aea271"}, + {file = "simsimd-6.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d476c874bafa0d12d4c8c5c47faf17407f3c96140616384421c2aa980342b6f"}, + {file = "simsimd-6.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9d4f15c06cc221d29e181197c7bbf92c5e829220cbeb3cd1cf080de78b04f2a"}, + {file = "simsimd-6.2.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d286fd4538cb1a1c70e69da00a3acee301519d578931b41161f4f1379d1195c6"}, + {file = "simsimd-6.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:050f68cfa85f1fb2cfa156280928e42926e3977034b755023ce1315bf59e87ff"}, + {file = "simsimd-6.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67bb4b17e04919545f29c7b708faaccbe027f164f8b5c9f4328604fa8f5560ea"}, + {file = "simsimd-6.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3d6bffd999dbb36e606b065e0180365efac2606049c4f7818e4cba2d34c3678f"}, + {file = "simsimd-6.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:25adb244fb75dbf49af0d1bcac4ed4a3fef8e847d78449faa5595af0a3e20d61"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b4542cee77e801a9c27370fc36ae271514fc0fb2ce14a35f8b25f47989e3d267"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4f665228f8ff4911790b485e74b00fa9586a141dde6011970be71bb303b5a22f"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:783b4308f80ae00763b0eaa0dac26196958f9c2df60d35a0347ebd2f82ece46d"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:95055e72cfe313c1c8694783bf8a631cc15673b3b775abef367e396d931db0b8"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a98f2b383f51b4f4ee568a637fc7958a347fdae0bd184cff8faa8030b6454a39"}, + {file = "simsimd-6.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e474fd10ceb38e2c9f826108a7762f8ff7912974846d86f08c4e7b19cd35ed4"}, + {file = "simsimd-6.2.1-cp312-cp312-win32.whl", hash = "sha256:b2530ea44fffeab25e5752bec6a5991f30fbc430b04647980db5b195c0971d48"}, + {file = "simsimd-6.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc23283235d5b8f0373b95a547e26da2d7785647a5d0fa15c282fc8c49c0dcb0"}, + {file = "simsimd-6.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:5692ce7e56253178eea9dbd58191734918409b83d54b07cfdcecf868d0150a73"}, + {file = "simsimd-6.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:76b32fdc7142c9714e94651ece8bc00dd5139c554813211552aa358e44af0e07"}, + {file = "simsimd-6.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f44e5e2319427f94db658c6f75caae78850da505902874a1664a83ef5713f333"}, + {file = "simsimd-6.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:05323cbad7200592c2e53fbcc759e615594e8ca444ef5eddf9f3fb196ad4de9c"}, + {file = "simsimd-6.2.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1f3cbe5c39db2bb64f30999104de1215ba3805d6059af7bc5a9d662d50f4707"}, + {file = "simsimd-6.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaa94e0932ae2a48b7e4df8c29204dc9fe59f72b1faeb08e9d5015bf51fb9f21"}, + {file = "simsimd-6.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:508465f8d4e3e0fff07c939921aeedf55b0ade9f56f64e938c350c283dea42fb"}, + {file = "simsimd-6.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ca67f6273ef544c74c48b134af756de7c98a711ccf69cd0791225f26dd449281"}, + {file = "simsimd-6.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:d470b43ce606f21f54a23fc19ad6928333e17d0956b02eb27b7b112edc156a10"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59518b9834c167a1dd8900600718e95cdadc9d74525452f426aa8455a38c55ef"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:59c2978c4e402097d8a4b38f076ff98cc43e6b059d53f89736404f26e9a9bd5a"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:edc68e727d53ed2866dcfb625f15e52be8f1e6809f4be2147bf8d2115a2542b7"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9e5e82551d75c0e2cd0d4b8af8db1cae7b5ac6dcc076c0c760870ff81f78135b"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2fa19f8c9786757d19afcbda9f8fb68de55e4f5562725ae8727f887d01bf0e4d"}, + {file = "simsimd-6.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b0748aa6bd4df4c5a3f5e979aec14b26588f1b2e0d44075dcc9eaf4d555e15b"}, + {file = "simsimd-6.2.1-cp313-cp313-win32.whl", hash = "sha256:7f43721e1a4ebe8d2245b0e85dd7de7153d1bf22839579d5f69a345909c68d9e"}, + {file = "simsimd-6.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:6af1565e0ef7060bc52a38e3273a8e6e92aff47835965dc5311298563475935e"}, + {file = "simsimd-6.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:e690b41377c8dd157d585713b0bc35c845aee7742334bf12d1f087fc8a65b6c3"}, {file = "simsimd-6.2.1.tar.gz", hash = "sha256:5e202c5386a4141946b7aee05faac8ebc2e36bca0a360b24080e57b59bc4ef6a"}, ] [[package]] name = "six" -version = "1.16.0" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "1.17.0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Python 2 and 3 compatibility utilities" +groups = ["default"] files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "smmap" -version = "5.0.1" +version = "5.0.2" requires_python = ">=3.7" summary = "A pure Python implementation of a sliding window memory map manager" +groups = ["default"] files = [ - {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, - {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, + {file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"}, + {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, ] [[package]] name = "sqlalchemy" -version = "2.0.33" +version = "2.0.38" requires_python = ">=3.7" summary = "Database Abstraction Library" +groups = ["default"] dependencies = [ - "greenlet!=0.4.17; python_version < \"3.13\" and (platform_machine == \"aarch64\" or (platform_machine == \"ppc64le\" or (platform_machine == \"x86_64\" or (platform_machine == \"amd64\" or (platform_machine == \"AMD64\" or (platform_machine == \"win32\" or platform_machine == \"WIN32\"))))))", + "greenlet!=0.4.17; (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_version < \"3.14\"", + "importlib-metadata; python_version < \"3.8\"", "typing-extensions>=4.6.0", ] files = [ - {file = "SQLAlchemy-2.0.33-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:570ec43e8c3c020abac4f0720baa5fe5187334e3f1e8e1777183c041962b61cc"}, - {file = "SQLAlchemy-2.0.33-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81759e77a4985abdbac068762a0eaf0f11860fe041ad6da170aae7615ea72531"}, - {file = "SQLAlchemy-2.0.33-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82c72da5be489c8d150deba70d5732398695418df5232bceb52ee323ddd9753b"}, - {file = "SQLAlchemy-2.0.33-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:30a3f55be76364b64c83788728faaba782ab282a24909e1994404c2146d39982"}, - {file = "SQLAlchemy-2.0.33-cp311-cp311-win32.whl", hash = "sha256:17d0c69f66392ad2db1609373a74d1f834b2e632f3f52d446747b8ec220aea53"}, - {file = "SQLAlchemy-2.0.33-cp311-cp311-win_amd64.whl", hash = "sha256:c5d5a733c6af7f392435e673d1b136f6bdf2366033abb35eed680400dc730840"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d81e3aeab456fe24c3f0dcfd4f952a3a5ee45e9c14fc66d34c1d7a60cf7b698"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca8788dc1baee100f09110f33a01d928cf9df4483d2bfb25a37be31a659d46bb"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684aee5fd811091b2f48006fb3fe6c7f2de4a716ef8d294a2aab762099753133"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1109cc6dc5c9d1223c42186391e6a5509e6d4ab2c30fa629573c10184f742f2e"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-win32.whl", hash = "sha256:c633e2d2f8a7b88c06e276bbe16cb7e62fed815fcbeb69cd9752cea166ecb8e8"}, - {file = "SQLAlchemy-2.0.33-cp312-cp312-win_amd64.whl", hash = "sha256:77eaf8fdf305266b806a91ae4633edbf86ad37e13bd92ac85e305e7f654c19a5"}, - {file = "SQLAlchemy-2.0.33-py3-none-any.whl", hash = "sha256:ae294808afde1b14a1a69aa86a69cadfe391848bbb233a5332a8065e4081cabc"}, - {file = "sqlalchemy-2.0.33.tar.gz", hash = "sha256:91c93333c2b37ff721dc83b37e28c29de4c502b5612f2d093468037b86aa2be0"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bf89e0e4a30714b357f5d46b6f20e0099d38b30d45fa68ea48589faf5f12f62d"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8455aa60da49cb112df62b4721bd8ad3654a3a02b9452c783e651637a1f21fa2"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53c0d6a859b2db58332e0e6a921582a02c1677cc93d4cbb36fdf49709b327b2"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c4817dff8cef5697f5afe5fec6bc1783994d55a68391be24cb7d80d2dbc3a6"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9cea5b756173bb86e2235f2f871b406a9b9d722417ae31e5391ccaef5348f2c"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e9cdbd18c1f84631312b64993f7d755d85a3930252f6276a77432a2b25a2f3"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-win32.whl", hash = "sha256:cb39ed598aaf102251483f3e4675c5dd6b289c8142210ef76ba24aae0a8f8aba"}, + {file = "SQLAlchemy-2.0.38-cp311-cp311-win_amd64.whl", hash = "sha256:f9d57f1b3061b3e21476b0ad5f0397b112b94ace21d1f439f2db472e568178ae"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12d5b06a1f3aeccf295a5843c86835033797fea292c60e72b07bcb5d820e6dd3"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e036549ad14f2b414c725349cce0772ea34a7ab008e9cd67f9084e4f371d1f32"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee3bee874cb1fadee2ff2b79fc9fc808aa638670f28b2145074538d4a6a5028e"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e185ea07a99ce8b8edfc788c586c538c4b1351007e614ceb708fd01b095ef33e"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b79ee64d01d05a5476d5cceb3c27b5535e6bb84ee0f872ba60d9a8cd4d0e6579"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afd776cf1ebfc7f9aa42a09cf19feadb40a26366802d86c1fba080d8e5e74bdd"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-win32.whl", hash = "sha256:a5645cd45f56895cfe3ca3459aed9ff2d3f9aaa29ff7edf557fa7a23515a3725"}, + {file = "SQLAlchemy-2.0.38-cp312-cp312-win_amd64.whl", hash = "sha256:1052723e6cd95312f6a6eff9a279fd41bbae67633415373fdac3c430eca3425d"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ecef029b69843b82048c5b347d8e6049356aa24ed644006c9a9d7098c3bd3bfd"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c8bcad7fc12f0cc5896d8e10fdf703c45bd487294a986903fe032c72201596b"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a0ef3f98175d77180ffdc623d38e9f1736e8d86b6ba70bff182a7e68bed7727"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b0ac78898c50e2574e9f938d2e5caa8fe187d7a5b69b65faa1ea4648925b096"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9eb4fa13c8c7a2404b6a8e3772c17a55b1ba18bc711e25e4d6c0c9f5f541b02a"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5dba1cdb8f319084f5b00d41207b2079822aa8d6a4667c0f369fce85e34b0c86"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-win32.whl", hash = "sha256:eae27ad7580529a427cfdd52c87abb2dfb15ce2b7a3e0fc29fbb63e2ed6f8120"}, + {file = "SQLAlchemy-2.0.38-cp313-cp313-win_amd64.whl", hash = "sha256:b335a7c958bc945e10c522c069cd6e5804f4ff20f9a744dd38e748eb602cbbda"}, + {file = "SQLAlchemy-2.0.38-py3-none-any.whl", hash = "sha256:63178c675d4c80def39f1febd625a6333f44c0ba269edd8a468b156394b27753"}, + {file = "sqlalchemy-2.0.38.tar.gz", hash = "sha256:e5a4d82bdb4bf1ac1285a68eab02d253ab73355d9f0fe725a97e1e0fa689decb"}, ] [[package]] name = "sqlparse" -version = "0.5.1" +version = "0.5.3" requires_python = ">=3.8" summary = "A non-validating SQL parser." +groups = ["default"] files = [ - {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, - {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, + {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, + {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, ] [[package]] name = "stringzilla" -version = "3.12.1" +version = "3.12.2" summary = "SIMD-accelerated string search, sort, hashes, fingerprints, & edit distances" -files = [ - {file = "stringzilla-3.12.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef30bd15638f83aa12978a0d184d1830caf55a7f80ccbbab0528f73873d4a017"}, - {file = "stringzilla-3.12.1.tar.gz", hash = "sha256:b812c9fc9a0ff36594e847443443895be91d38aa460a7b02b4a6e3048b76e2c8"}, +groups = ["default"] +files = [ + {file = "stringzilla-3.12.2-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:78363cfa4ac9a232b728dd40f59b0d8b0ef31629708751fbdee9c0117d06500f"}, + {file = "stringzilla-3.12.2-cp311-cp311-macosx_10_11_x86_64.whl", hash = "sha256:0ad4ae468411348532fd7cb35c7f0207b37f1a40fc7d7882f63e7b0cfc8ec117"}, + {file = "stringzilla-3.12.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6a4b3048d87637c13562aac4574cf5c422a0c242214466eef8f608ae7fbb3668"}, + {file = "stringzilla-3.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a8ba2ac1eb24942b436108cbeba1e21a4478a3711b30411f37d1b7ac5c6608bc"}, + {file = "stringzilla-3.12.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2d7cc27190cbad655b1afcd135b329aa236e76da0eb26bc0e3c5e5d8e2763824"}, + {file = "stringzilla-3.12.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab52ad4a78ad85c7269999641e2be030b76f907ff2838edd89dd0f312fb96984"}, + {file = "stringzilla-3.12.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e1d5d9ccfe33e0b7d24330630ea4847cc92b4017f8068c863772e7d469f3767"}, + {file = "stringzilla-3.12.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bda0b337a4f02caf8084227340538964b345f09e22dcee9f9834d535f2849546"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15de752fa1e671193b67d3b88150c9d2702671088f64751a8d4932d0dd833263"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1f4761736ea1bf44720d2c5938f35a1a8949b477320cc64b0ce71648d61c72bf"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:abebe012bacffdb1c6b3dda22059c392a680768b2bf0e152066d69d03bbc2231"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:144246e778d9738a68e0b119b9ea98f2c6953b7b777abacb75a59ced8a418370"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6076fdacb33a62709f122edbeb99f209dd6e805915f8bc727b0c0acacb58c095"}, + {file = "stringzilla-3.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:796efadc75fa1760af4bf860d49b4c00b155101f62563680cf0961af98a87d3a"}, + {file = "stringzilla-3.12.2-cp311-cp311-win32.whl", hash = "sha256:a823b1c5e384ebb35fe2f300fc5020c86781883c20895c3ab103f546d47c67ad"}, + {file = "stringzilla-3.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:77d208fc5afbf7ab03d82c7555a0115f92d0cd8f5d1fac45c104b14472fbbe02"}, + {file = "stringzilla-3.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:9f8ff669618c1d67e3ee19690be9b18afe26c0ba5578e0eceda7cb6abc4f15e8"}, + {file = "stringzilla-3.12.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:89404cabcc05ddd3e7a98497db0fd33d5cf1b1b4b6c7028129f54bfe280a8b00"}, + {file = "stringzilla-3.12.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5664f6144774f8f51b98d65ff221bd886e28d00bf9063e0312cd4306dec5d31d"}, + {file = "stringzilla-3.12.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3e433dd22c25a5bebd598610350946e4c49f160dd1a5c0259bf6903cb66184df"}, + {file = "stringzilla-3.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6096ba629f61bb31ca6644f45f988b0c3b84eefdbc2d5d3244b351cdb3698dd1"}, + {file = "stringzilla-3.12.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8d2e913adcd1373c0805eaa98c6083f0f28bf6a0d2a87363c75523e22396a64c"}, + {file = "stringzilla-3.12.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4a918b1b28314a06f2ab3f18832abaa7bd78d4125c0d8f6df66fe6a605b47643"}, + {file = "stringzilla-3.12.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edf6b66fa50f4134f74b5b9268659fee9fa313ad74044d178181dc2e951f6aaa"}, + {file = "stringzilla-3.12.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ca4f853b8d659e83c09afba3eae0892b9671966d4a2a0aadc8f615ac8c1d1da"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d7b511c86f349c93b692fff8cc8cd01a0836dac267686a45ea3cfccc0d80e1dc"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45d8a7dc944fa00b6578500389dfe82992ad64f2c47d5946328d54d2f1b576ff"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f6fba19519d8c4710ac0ee69fe963474e82861a333949bd8351b3c34ef95256b"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d2e8b2180d22cbb34c9d32f5d8aa200fb4b20d5855851933efb3d29f794f4ecd"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9fc777c111ebb7d0d4f6b695f79c33d4c4233e53cb8e933ba602ec6a0739030d"}, + {file = "stringzilla-3.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2102058a1ed6f4a8a932cc75b14e246930b6377c120069ce814e220fdd0b2709"}, + {file = "stringzilla-3.12.2-cp312-cp312-win32.whl", hash = "sha256:49852d3f0334c5b90b4585f01797ac257e697f3fa0d9b490e1934523185138c3"}, + {file = "stringzilla-3.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:3189580a878d3b861ce1c8b3783fe65cb835313fe27a32c751daac36d6d63160"}, + {file = "stringzilla-3.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:d58333ceee04f514d2778d15ed0daca25b8f04aba519b9ea03c0447c5dc5f38b"}, + {file = "stringzilla-3.12.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:72721c1acaf9003d946f1e15cfcac6996a34640fdf2b3595a724a3c6f52ccb84"}, + {file = "stringzilla-3.12.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:038e9cbd1d91dc3bae32b95a2616aaf9516b65e0a1326d8b9b33afbd1b92b100"}, + {file = "stringzilla-3.12.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a7596bb471c92fb63871eaf8eb26461597772ad1c2026362b10bff9a4aa71f78"}, + {file = "stringzilla-3.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cecbd9046642778d0552c4d756f89d6b83d3ea7932a80b8fe59ad659e704fd62"}, + {file = "stringzilla-3.12.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b2c484f37f9bcb7bb8a430125b9f62d007abfaea9d0f7c9140aa9231f137669"}, + {file = "stringzilla-3.12.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aad609515530159073c60ceb505fef9dd5c051794f4a742ca1a868baf61a652b"}, + {file = "stringzilla-3.12.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4730bd6051d4eccaae1efa94418542ef8e03c84280035ce0a63ac4ed9fc12225"}, + {file = "stringzilla-3.12.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a77a2da827bb89f5ba499d369393a4213bca6ea14f5a9c00e4822c33517b82e3"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1091cc713a605ce4cd0f43f23e3f53c83797f3463cc34e2b25e75a1584e7a1ab"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6f8f96b52850b59cc087051c90a6cdc03692c02d0b25906b9dd4da68ab44203d"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c2e47828819c656dc1dd6c30c4535879bbe648cb26879073a83014c81916acd2"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bacd129e39977c887406f476aa0eef377d5401f33b54518f52e20767a19cb82b"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f2e045cb443124c9f72a5e6353e707ce3e110bf1fc4359cf6cbd3c16dfdb6f6"}, + {file = "stringzilla-3.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0efa82e5daedfe32c6a5e862017763bae9a32d6f12b8e72d7c4eaa5a6819f357"}, + {file = "stringzilla-3.12.2-cp313-cp313-win32.whl", hash = "sha256:3920b8c7ad11e7d76763df5747bd0770c2b797ea5afb0169d3fef0a47b4f0a2a"}, + {file = "stringzilla-3.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:b73b6c6ee7664fc2adf6a22861b3acefbd7d692ac4741299be1679cbda3710f4"}, + {file = "stringzilla-3.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:7f821ddccc36f57ae14351f12818e278a24b0e161c076c464d2c8193f0d56db5"}, + {file = "stringzilla-3.12.2.tar.gz", hash = "sha256:0538d5de6ec5f9cd59b0254fb412254c43b421be4baf37740fa781e8c09b7663"}, ] [[package]] @@ -1991,6 +2867,8 @@ name = "sympy" version = "1.13.1" requires_python = ">=3.8" summary = "Computer algebra system (CAS) in Python" +groups = ["default"] +marker = "python_version >= \"3.9\"" dependencies = [ "mpmath<1.4,>=1.1.0", ] @@ -2004,16 +2882,32 @@ name = "threadpoolctl" version = "3.5.0" requires_python = ">=3.8" summary = "threadpoolctl" +groups = ["default"] files = [ {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, ] +[[package]] +name = "tifffile" +version = "2025.2.18" +requires_python = ">=3.10" +summary = "Read and write TIFF files" +groups = ["default"] +dependencies = [ + "numpy", +] +files = [ + {file = "tifffile-2025.2.18-py3-none-any.whl", hash = "sha256:54b36c4d5e5b8d8920134413edfe5a7cfb1c7617bb50cddf7e2772edb7149043"}, + {file = "tifffile-2025.2.18.tar.gz", hash = "sha256:8d731789e691b468746c1615d989bc550ac93cf753e9210865222e90a5a95d11"}, +] + [[package]] name = "torch" version = "2.6.0" requires_python = ">=3.9.0" summary = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +groups = ["default"] dependencies = [ "filelock", "fsspec", @@ -2032,27 +2926,41 @@ dependencies = [ "nvidia-nccl-cu12==2.21.5; platform_system == \"Linux\" and platform_machine == \"x86_64\"", "nvidia-nvjitlink-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", "nvidia-nvtx-cu12==12.4.127; platform_system == \"Linux\" and platform_machine == \"x86_64\"", + "setuptools; python_version >= \"3.12\"", "sympy==1.13.1; python_version >= \"3.9\"", "triton==3.2.0; platform_system == \"Linux\" and platform_machine == \"x86_64\"", "typing-extensions>=4.10.0", ] files = [ {file = "torch-2.6.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:7979834102cd5b7a43cc64e87f2f3b14bd0e1458f06e9f88ffa386d07c7446e1"}, + {file = "torch-2.6.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:ccbd0320411fe1a3b3fec7b4d3185aa7d0c52adac94480ab024b5c8f74a0bf1d"}, + {file = "torch-2.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:46763dcb051180ce1ed23d1891d9b1598e07d051ce4c9d14307029809c4d64f7"}, + {file = "torch-2.6.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:94fc63b3b4bedd327af588696559f68c264440e2503cc9e6954019473d74ae21"}, + {file = "torch-2.6.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:2bb8987f3bb1ef2675897034402373ddfc8f5ef0e156e2d8cfc47cacafdda4a9"}, + {file = "torch-2.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:b789069020c5588c70d5c2158ac0aa23fd24a028f34a8b4fcb8fcb4d7efcf5fb"}, + {file = "torch-2.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:7e1448426d0ba3620408218b50aa6ada88aeae34f7a239ba5431f6c8774b1239"}, + {file = "torch-2.6.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:9a610afe216a85a8b9bc9f8365ed561535c93e804c2a317ef7fabcc5deda0989"}, + {file = "torch-2.6.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:4874a73507a300a5d089ceaff616a569e7bb7c613c56f37f63ec3ffac65259cf"}, + {file = "torch-2.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:a0d5e1b9874c1a6c25556840ab8920569a7a4137afa8a63a32cee0bc7d89bd4b"}, + {file = "torch-2.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:510c73251bee9ba02ae1cb6c9d4ee0907b3ce6020e62784e2d7598e0cfa4d6cc"}, + {file = "torch-2.6.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:ff96f4038f8af9f7ec4231710ed4549da1bdebad95923953a25045dcf6fd87e2"}, ] [[package]] name = "torchmetrics" -version = "1.4.1" -requires_python = ">=3.8" +version = "1.6.2" +requires_python = ">=3.9" summary = "PyTorch native Metrics" +groups = ["default"] dependencies = [ "lightning-utilities>=0.8.0", "numpy>1.20.0", "packaging>17.1", - "torch>=1.10.0", + "torch>=2.0.0", ] files = [ - {file = "torchmetrics-1.4.1-py3-none-any.whl", hash = "sha256:c2e7cd56dd8bdc60ae63d712f3bdce649f23bd174d9180bdd0b746e0230b865a"}, + {file = "torchmetrics-1.6.2-py3-none-any.whl", hash = "sha256:586b970aff33a2154bfb6ed4539a557e9a268b6dce408bbdef0fec99fef3c78b"}, + {file = "torchmetrics-1.6.2.tar.gz", hash = "sha256:a3fa6372dbf01183d0f6fda2159e9526fb62818aa3630660909c290425f67df6"}, ] [[package]] @@ -2060,31 +2968,51 @@ name = "torchvision" version = "0.21.0" requires_python = ">=3.9" summary = "image and video datasets and models for torch deep learning" +groups = ["default"] dependencies = [ "numpy", "pillow!=8.3.*,>=5.3.0", "torch==2.6.0", ] files = [ + {file = "torchvision-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110d115333524d60e9e474d53c7d20f096dbd8a080232f88dddb90566f90064c"}, {file = "torchvision-0.21.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:3891cd086c5071bda6b4ee9d266bb2ac39c998c045c2ebcd1e818b8316fb5d41"}, + {file = "torchvision-0.21.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:54454923a50104c66a9ab6bd8b73a11c2fc218c964b1006d5d1fe5b442c3dcb6"}, + {file = "torchvision-0.21.0-cp311-cp311-win_amd64.whl", hash = "sha256:49bcfad8cfe2c27dee116c45d4f866d7974bcf14a5a9fbef893635deae322f2f"}, + {file = "torchvision-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:97a5814a93c793aaf0179cfc7f916024f4b63218929aee977b645633d074a49f"}, + {file = "torchvision-0.21.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:b578bcad8a4083b40d34f689b19ca9f7c63e511758d806510ea03c29ac568f7b"}, + {file = "torchvision-0.21.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5083a5b1fec2351bf5ea9900a741d54086db75baec4b1d21e39451e00977f1b1"}, + {file = "torchvision-0.21.0-cp312-cp312-win_amd64.whl", hash = "sha256:6eb75d41e3bbfc2f7642d0abba9383cc9ae6c5a4ca8d6b00628c225e1eaa63b3"}, + {file = "torchvision-0.21.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:659b76c86757cb2ee4ca2db245e0740cfc3081fef46f0f1064d11adb4a8cee31"}, + {file = "torchvision-0.21.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:084ac3f5a1f50c70d630a488d19bf62f323018eae1b1c1232f2b7047d3a7b76d"}, + {file = "torchvision-0.21.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:5045a3a5f21ec3eea6962fa5f2fa2d4283f854caec25ada493fcf4aab2925467"}, + {file = "torchvision-0.21.0-cp313-cp313-win_amd64.whl", hash = "sha256:9147f5e096a9270684e3befdee350f3cacafd48e0c54ab195f45790a9c146d67"}, ] [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.1" requires_python = ">=3.7" summary = "Fast, Extensible Progress Meter" +groups = ["default"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [[package]] name = "triton" version = "3.2.0" summary = "A language and compiler for custom Deep Learning operations" +groups = ["default"] +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" files = [ {file = "triton-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8009a1fb093ee8546495e96731336a33fb8856a38e45bb4ab6affd6dbc3ba220"}, + {file = "triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d9b215efc1c26fa7eefb9a157915c92d52e000d2bf83e5f69704047e63f125c"}, + {file = "triton-3.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5dfa23ba84541d7c0a531dfce76d8bcd19159d50a4a8b14ad01e91734a5c1b0"}, ] [[package]] @@ -2092,6 +3020,7 @@ name = "typing-extensions" version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" +groups = ["default", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2099,37 +3028,53 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2025.1" requires_python = ">=2" summary = "Provider of IANA time zone data" +groups = ["default"] files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, ] [[package]] name = "urllib3" -version = "2.2.2" -requires_python = ">=3.8" +version = "2.3.0" +requires_python = ">=3.9" summary = "HTTP library with thread-safe connection pooling, file post, and more." +groups = ["default"] files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [[package]] name = "virtualenv" -version = "20.26.3" -requires_python = ">=3.7" +version = "20.29.3" +requires_python = ">=3.8" summary = "Virtual Python Environment builder" +groups = ["dev"] dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", + "importlib-metadata>=6.6; python_version < \"3.8\"", "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, + {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, +] + +[[package]] +name = "waitress" +version = "3.0.2" +requires_python = ">=3.9.0" +summary = "Waitress WSGI server" +groups = ["default"] +marker = "platform_system == \"Windows\"" +files = [ + {file = "waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e"}, + {file = "waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f"}, ] [[package]] @@ -2137,6 +3082,7 @@ name = "websocket-client" version = "1.8.0" requires_python = ">=3.8" summary = "WebSocket client for Python with low level API options" +groups = ["default"] files = [ {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, @@ -2144,97 +3090,144 @@ files = [ [[package]] name = "werkzeug" -version = "3.0.4" -requires_python = ">=3.8" +version = "3.1.3" +requires_python = ">=3.9" summary = "The comprehensive WSGI web application library." +groups = ["default"] dependencies = [ "MarkupSafe>=2.1.1", ] files = [ - {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, - {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, + {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, + {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, ] [[package]] name = "wrapt" -version = "1.16.0" -requires_python = ">=3.6" +version = "1.17.2" +requires_python = ">=3.8" summary = "Module for decorators, wrappers and monkey patching." -files = [ - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +groups = ["default"] +files = [ + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, + {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, + {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, + {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, + {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, + {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, + {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, + {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, + {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, + {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, + {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, ] [[package]] name = "yarl" -version = "1.9.4" -requires_python = ">=3.7" +version = "1.18.3" +requires_python = ">=3.9" summary = "Yet another URL library" +groups = ["default"] dependencies = [ "idna>=2.0", "multidict>=4.0", -] -files = [ - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, + "propcache>=0.2.0", +] +files = [ + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, + {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, + {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, + {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, + {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, + {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, + {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, + {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, + {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, + {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, + {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, + {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, + {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, + {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, + {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, + {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, + {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, + {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [[package]] name = "zipp" -version = "3.20.1" -requires_python = ">=3.8" +version = "3.21.0" +requires_python = ">=3.9" summary = "Backport of pathlib-compatible object wrapper for zip files" +groups = ["default"] files = [ - {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, - {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] diff --git a/pyproject.toml b/pyproject.toml index 64d0f5c..bd5e1e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,21 +1,22 @@ [project] -name = "project-name" +name = "Stain Normalization" version = "0.1.0" -authors = [] +authors = ["Adam Lopatka"] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } dependencies = [ - "torch>=2.4.0", - "lightning>=2.4.0", - "torchmetrics>=1.4.1", + "lightning>=2.0.0", + "albumentations>=1.4.14", + "torchmetrics>=1.4.14", + "torchvision>=0.17.2", + "torch>=2.2.2", + "tqdm>=4.66.5", "rationai-mlkit @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git", "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", - "albumentations>=2.0.4", - "scikit-learn>=1.6.1", - "torchvision>=0.21.0", "rationai-kube-jobs @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git", + "scikit-image>=0.25.2" ] [tool.pdm.dev-dependencies] @@ -25,19 +26,19 @@ dev = ["mypy", "pre-commit", "ruff"] mask_generate = "python preprocessing/mask_generator.py" tiler = "python preprocessing/tiler.py" -train = "python -m project_name mode=fit" -validate = "python -m project_name mode=validate" -test = "python -m project_name mode=test" -predict = "python -m project_name mode=predict" +train = "python -m stain_normalization mode=fit" +validate = "python -m stain_normalization mode=validate" +test = "python -m stain_normalization mode=test" +predict = "python -m stain_normalization mode=predict" l = { composite = ["lint", "format", "mypy"] } lint = "ruff check --fix" format = "ruff format" mypy = "mypy ." -post_install = { composite = [ - "pre-commit autoupdate", - "pre-commit install", - "pre-commit install --hook-type commit-msg", -] } +# post_install = { composite = [ +# "pre-commit autoupdate", +# "pre-commit install", +# "pre-commit install --hook-type commit-msg", +#] } [tool.pdm] distribution = false diff --git a/stain_normalization/main.py b/stain_normalization/__main__.py similarity index 100% rename from stain_normalization/main.py rename to stain_normalization/__main__.py diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py index e2468c3..3d9dbb1 100644 --- a/stain_normalization/data/datasets/stain_normalization.py +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -1,21 +1,21 @@ from collections.abc import Iterable import pandas as pd -from albumentations import TransformType +from albumentations import Transform3D from albumentations.pytorch import ToTensorV2 from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset -from stain_normalization.typing import Metadata, PredictSample, Sample +from stain_normalization.typing import PredictSample, Sample class StainNormalization(MetaTiledSlides[Sample]): def __init__( self, uris: Iterable[str], - modify:TransformType, - transforms: TransformType | None = None, - + modify: Transform3D, + transforms: Transform3D | None = None, + ) -> None: self.modify = modify self.transforms = transforms @@ -38,8 +38,8 @@ class StainNormalizationPredict(MetaTiledSlides[PredictSample]): def __init__( self, uris: Iterable[str], - modify:TransformType, - transforms: TransformType | None = None, + modify: Transform3D, + transforms: Transform3D | None = None, ) -> None: self.modify = modify @@ -65,8 +65,8 @@ def __init__( slide_metadata: pd.Series, tiles: pd.DataFrame, include_target: bool, - transforms: TransformType | None = None, - modify:TransformType | None = None, + modify: Transform3D, + transforms: Transform3D | None = None, ) -> None: super().__init__() self.slide_tiles = OpenSlideTilesDataset( @@ -90,8 +90,8 @@ def __getitem__(self, idx: int) -> Sample | PredictSample: if self.transforms is not None: original_image = self.transforms(image=original_image)["image"] - - modified_image = self.modify(original_image)["image"] + + modified_image = self.modify(image=original_image)["image"] # modification_name = "Original" # if self.modify: diff --git a/stain_normalization/modeling/__init__.py b/stain_normalization/modeling/__init__.py index 6e52155..9ae4c05 100644 --- a/stain_normalization/modeling/__init__.py +++ b/stain_normalization/modeling/__init__.py @@ -1,3 +1,2 @@ -from . import metrics from .l1ssim_loss import L1SSIMLoss __all__ = ["L1SSIMLoss", "metrics"] \ No newline at end of file diff --git a/stain_normalization/modeling/backbone/vgg16.py b/stain_normalization/modeling/backbone/vgg16.py index b621ed7..0864515 100644 --- a/stain_normalization/modeling/backbone/vgg16.py +++ b/stain_normalization/modeling/backbone/vgg16.py @@ -1,5 +1,5 @@ from torch import nn -from torchvision +import torchvision def vgg16(weights: str | None = None) -> nn.Module: return torchvision.models.vgg16(weights=weights).features diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 19e626f..7aca27c 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -1,14 +1,12 @@ -from collections import defaultdict - -import torch from lightning import LightningModule from torch import Tensor, nn from torch.optim.optimizer import Optimizer from stain_normalization.modeling import L1SSIMLoss from stain_normalization.typing import Input, Outputs from torch.optim import Adam -from torch.optim.optimizer import Optimizer -from torchmetrics import PeakSignalNoiseRatio,StructuralSimilarityIndexMeasure, MetricCollection +from torch.optim.optimizer import Optimizer +from torchmetrics.image import PeakSignalNoiseRatio,StructuralSimilarityIndexMeasure +from torchmetrics import MetricCollection class StainNormalizationModel(LightningModule): def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: From 9c6aad7538bda0a5696b0dd17ecf5f594056dd50 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 01:11:07 +0000 Subject: [PATCH 30/79] chore: job config --- configs/default.yaml | 2 +- job.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 42230e2..749d17b 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -30,7 +30,7 @@ data: metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: Testing #First Train Stain Normalization + run_name: First Train Stain Normalization description: Testing Stain Normalization hyperparams: {} diff --git a/job.py b/job.py index 20b4bf4..1064fdd 100644 --- a/job.py +++ b/job.py @@ -2,17 +2,17 @@ submit_job( - job_name="some name", - username="your name", + job_name="Stain Normalization Train", + username="xlopatka", cpu=10, memory="128Gi", gpu="A40", script=[ - "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/... workdir", - "cd workdir", - "git checkout develop", + "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git", + "cd staining", + "git checkout feature/ml-stain-normalization", "pdm sync --skip=post_install", - "pdm fit model/backbone=resnet18", + "pdm train", ], storage=Storage(mou=True), ) From a593c298b7d126f90aa67d102f13e8596946b0fb Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:11:39 +0000 Subject: [PATCH 31/79] fix: job run parametrs --- configs/default.yaml | 2 +- job.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 749d17b..6cefd09 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -24,7 +24,7 @@ trainer: mode: min data: - batch_size: 256 + batch_size: 126 num_workers: 8 metadata: diff --git a/job.py b/job.py index 1064fdd..69d00ae 100644 --- a/job.py +++ b/job.py @@ -2,11 +2,11 @@ submit_job( - job_name="Stain Normalization Train", + job_name="stain-normalization-train", username="xlopatka", cpu=10, memory="128Gi", - gpu="A40", + gpu="H100", script=[ "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git", "cd staining", From 4c9e89d46e6748dedf9432ac50bf371c43c59560 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:17:34 +0000 Subject: [PATCH 32/79] fix: lower batch size --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index 6cefd09..a99ca43 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -24,7 +24,7 @@ trainer: mode: min data: - batch_size: 126 + batch_size: 64 num_workers: 8 metadata: From b4df4e3ba4bd3e4a24dbc66295595cc76a0b425a Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:22:46 +0000 Subject: [PATCH 33/79] fix: lower workers --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index a99ca43..f716551 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -25,7 +25,7 @@ trainer: data: batch_size: 64 - num_workers: 8 + num_workers: 4 metadata: user: xlopatka From 4af7ac1d3b1a2e7badbbad1adfbe5e99d894574f Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:42:18 +0000 Subject: [PATCH 34/79] fix: ensure float32 tensors --- stain_normalization/data/datasets/stain_normalization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py index 3d9dbb1..4205e0f 100644 --- a/stain_normalization/data/datasets/stain_normalization.py +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -105,8 +105,8 @@ def __getitem__(self, idx: int) -> Sample | PredictSample: # modification=modification_name # ) - original_image = self.to_tensor(image=original_image)["image"] - modified_image = self.to_tensor(image=modified_image)["image"] + original_image = self.to_tensor(image=original_image)["image"].float() + modified_image = self.to_tensor(image=modified_image)["image"].float() if self.include_target: return modified_image, original_image From 07a4002bb24119f8c01849d51997809c6f9f40cc Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:48:22 +0000 Subject: [PATCH 35/79] fix: missing () --- stain_normalization/stain_normalization_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 7aca27c..7487419 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -12,7 +12,7 @@ class StainNormalizationModel(LightningModule): def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: super().__init__() self.backbone = backbone - self.decode_head = decode_head + self.decode_head = decode_head() self.criterion = L1SSIMLoss() self.val_metrics = MetricCollection( From 1bc166cf300f5ed9b6d302df36dde5c6208ba6ff Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 09:52:45 +0000 Subject: [PATCH 36/79] fix: decode_head settings --- configs/model/decode_head/unet2048.yaml | 5 ++--- configs/model/decode_head/unet512.yaml | 5 ++--- stain_normalization/stain_normalization_model.py | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/configs/model/decode_head/unet2048.yaml b/configs/model/decode_head/unet2048.yaml index 00a4921..dce8b92 100644 --- a/configs/model/decode_head/unet2048.yaml +++ b/configs/model/decode_head/unet2048.yaml @@ -1,4 +1,3 @@ -decode_head: - _target_: stain_normalization.modeling.decode_head.UNetDecoder - in_channels: 2048 +_target_: stain_normalization.modeling.decode_head.UNetDecoder +in_channels: 2048 diff --git a/configs/model/decode_head/unet512.yaml b/configs/model/decode_head/unet512.yaml index 531bf9f..6442711 100644 --- a/configs/model/decode_head/unet512.yaml +++ b/configs/model/decode_head/unet512.yaml @@ -1,4 +1,3 @@ -decode_head: - _target_: stain_normalization.modeling.decode_head.UNetDecoder - in_channels: 512 +_target_: stain_normalization.modeling.decode_head.UNetDecoder +in_channels: 512 diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 7487419..7aca27c 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -12,7 +12,7 @@ class StainNormalizationModel(LightningModule): def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: super().__init__() self.backbone = backbone - self.decode_head = decode_head() + self.decode_head = decode_head self.criterion = L1SSIMLoss() self.val_metrics = MetricCollection( From c258af2b605645e497cf849e302be8a2edfa6b5a Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 7 Mar 2025 14:22:41 +0000 Subject: [PATCH 37/79] chore: config change --- configs/default.yaml | 2 +- job.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index f716551..5b71b24 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -24,7 +24,7 @@ trainer: mode: min data: - batch_size: 64 + batch_size: 128 num_workers: 4 metadata: diff --git a/job.py b/job.py index 69d00ae..6da6dee 100644 --- a/job.py +++ b/job.py @@ -6,7 +6,8 @@ username="xlopatka", cpu=10, memory="128Gi", - gpu="H100", + gpu="A40", + shm="16384Mi", script=[ "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git", "cd staining", From 8d8190d9d496ef392a950e37f075495997cf2b78 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sun, 9 Mar 2025 00:32:15 +0000 Subject: [PATCH 38/79] fix: job settign optimalization --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index 5b71b24..5fd58bb 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -25,7 +25,7 @@ trainer: data: batch_size: 128 - num_workers: 4 + num_workers: 8 metadata: user: xlopatka From d9e331932cca9791197fad7ac9ed2882dc431d1a Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Thu, 13 Mar 2025 03:05:00 +0000 Subject: [PATCH 39/79] fix: image normalization --- .../datasets/stain_normalization/predict.yaml | 5 +-- .../datasets/stain_normalization/test.yaml | 5 +-- .../datasets/stain_normalization/train.yaml | 1 + .../datasets/stain_normalization/val.yaml | 3 +- configs/data/normalize/default.yaml | 10 ++++++ configs/default.yaml | 2 +- .../data/datasets/stain_normalization.py | 34 +++++++++++-------- 7 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 configs/data/normalize/default.yaml diff --git a/configs/data/datasets/stain_normalization/predict.yaml b/configs/data/datasets/stain_normalization/predict.yaml index 7832a66..5da9773 100644 --- a/configs/data/datasets/stain_normalization/predict.yaml +++ b/configs/data/datasets/stain_normalization/predict.yaml @@ -1,6 +1,7 @@ defaults: - - /data/transforms@transforms: test + # - /data/transforms@transforms: test - /data/modify@modify: test - + - /data/normalize@normalize: default + _target_: stain_normalization.data.datasets.StainNormalizationPredict uris: ["mlflow-artifacts:"] diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml index 78dabba..4904032 100644 --- a/configs/data/datasets/stain_normalization/test.yaml +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -1,6 +1,7 @@ defaults: - - /data/transforms@transforms: test + # - /data/transforms@transforms: test - /data/modify@modify: test - + - /data/normalize@normalize: default + _target_: stain_normalization.data.datasets.StainNormalization uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test"] diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml index 5a7feec..dfa39eb 100644 --- a/configs/data/datasets/stain_normalization/train.yaml +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -1,6 +1,7 @@ defaults: # - /data/transforms@transforms: train - /data/modify@modify: train + - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.StainNormalization uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - train"] diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index 142cfb8..860ea53 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -1,6 +1,7 @@ defaults: - - /data/transforms@transforms: test + # - /data/transforms@transforms: test - /data/modify@modify: test + - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.StainNormalization uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - val"] diff --git a/configs/data/normalize/default.yaml b/configs/data/normalize/default.yaml new file mode 100644 index 0000000..08d72da --- /dev/null +++ b/configs/data/normalize/default.yaml @@ -0,0 +1,10 @@ +_target_: albumentations.Normalize +mean: + - 0.780361961 + - 0.614529804 + - 0.725567843 +std: + - 0.144428627 + - 0.183275686 + - 0.140768627 +max_pixel_value: 1 diff --git a/configs/default.yaml b/configs/default.yaml index 5fd58bb..998ba31 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -30,7 +30,7 @@ data: metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: First Train Stain Normalization + run_name: Second Train Stain Normalization description: Testing Stain Normalization hyperparams: {} diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py index 4205e0f..6c6f354 100644 --- a/stain_normalization/data/datasets/stain_normalization.py +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -1,5 +1,6 @@ from collections.abc import Iterable +import numpy as np import pandas as pd from albumentations import Transform3D from albumentations.pytorch import ToTensorV2 @@ -14,11 +15,13 @@ def __init__( self, uris: Iterable[str], modify: Transform3D, + normalize: Transform3D | None = None, transforms: Transform3D | None = None, ) -> None: self.modify = modify self.transforms = transforms + self.normalize = normalize super().__init__(uris=uris) def generate_datasets(self) -> Iterable[Dataset[Sample]]: @@ -28,6 +31,7 @@ def generate_datasets(self) -> Iterable[Dataset[Sample]]: tiles=self.filter_tiles_by_slide(slide["id"]), include_target=True, modify=self.modify, + normalize=self.normalize, transforms=self.transforms, ) for _, slide in self.slides.iterrows() @@ -39,10 +43,12 @@ def __init__( self, uris: Iterable[str], modify: Transform3D, + normalize: Transform3D | None = None, transforms: Transform3D | None = None, ) -> None: self.modify = modify + self.normalize = normalize self.transforms = transforms super().__init__(uris=uris) @@ -53,6 +59,7 @@ def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: tiles=self.filter_tiles_by_slide(slide["id"]), include_target=False, modify=self.modify, + normalize=self.normalize, transforms=self.transforms, ) for _, slide in self.slides.iterrows() @@ -66,6 +73,7 @@ def __init__( tiles: pd.DataFrame, include_target: bool, modify: Transform3D, + normalize: Transform3D | None = None, transforms: Transform3D | None = None, ) -> None: super().__init__() @@ -76,38 +84,36 @@ def __init__( tile_extent_y=slide_metadata.tile_extent_y, tiles=tiles, ) + self.modify = modify + self.normalize = normalize self.transforms = transforms self.include_target = include_target self.to_tensor = ToTensorV2() - self.modify = modify def __len__(self) -> int: return len(self.slide_tiles) def __getitem__(self, idx: int) -> Sample | PredictSample: original_image = self.slide_tiles[idx] - + # This is not distruptive transform as rotate, flip if self.transforms is not None: original_image = self.transforms(image=original_image)["image"] + # Create "wrong" image to use as input. Outputs image in float 0-1 modified_image = self.modify(image=original_image)["image"] + + if np.max(original_image) > 1.0: + original_image = original_image / 255.0 - # modification_name = "Original" - # if self.modify: - # out = self.modify(original_image) - # modified_image = out["image"] - # modification_name = out["modification_name"] - # metadata = Metadata( - # slide=self.slide_tiles.slide_path.stem, - # x=self.slide_tiles.tiles.iloc[idx]["x"], - # y=self.slide_tiles.tiles.iloc[idx]["y"], - # modification=modification_name - # ) + if self.normalize: + original_image = self.normalize(image=original_image)["image"] + modified_image = self.normalize(image=modified_image)["image"] original_image = self.to_tensor(image=original_image)["image"].float() modified_image = self.to_tensor(image=modified_image)["image"].float() - + + if self.include_target: return modified_image, original_image From 986667d07b43cb6cdba45e00463f7fadba34f0e2 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sun, 23 Mar 2025 01:53:42 +0000 Subject: [PATCH 40/79] feat: tiles export --- pdm.lock | 30 ++++++++- pyproject.toml | 3 +- stain_normalization/__main__.py | 5 +- stain_normalization/callbacks/tiles_export.py | 62 +++++++++++++++++++ stain_normalization/data/data_module.py | 14 +++++ .../data/datasets/stain_normalization.py | 18 +++--- stain_normalization/data/utils/__init__.py | 4 ++ stain_normalization/data/utils/collate_fn.py | 6 ++ .../stain_normalization_model.py | 4 ++ stain_normalization/typing.py | 4 +- 10 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 stain_normalization/callbacks/tiles_export.py create mode 100644 stain_normalization/data/utils/__init__.py create mode 100644 stain_normalization/data/utils/collate_fn.py diff --git a/pdm.lock b/pdm.lock index 57e651c..282e879 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:b6548b53106f41b522b88929821234d14bbde40c39c47dafe1e38851ca0ec4e9" +content_hash = "sha256:5332e3a0a1aebc8df232aacd3e71bbc5bdbaeec0efddc8d0137eafb3cd6c2c32" [[metadata.targets]] requires_python = ">=3.11" @@ -1730,6 +1730,20 @@ files = [ {file = "opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca"}, ] +[[package]] +name = "openslide-bin" +version = "4.0.0.6" +requires_python = ">=3.8" +summary = "Binary build of OpenSlide" +groups = ["default"] +files = [ + {file = "openslide-bin-4.0.0.6.tar.gz", hash = "sha256:baca4a590cb15c8685f1ee1905d496bb0a23468b969f7066a2126c24c9e9ef39"}, + {file = "openslide_bin-4.0.0.6-py3-none-macosx_11_0_universal2.whl", hash = "sha256:f9c4ed0da275202dce531b163d92e1b860d215e779e7620fdd0dd92b7c40764b"}, + {file = "openslide_bin-4.0.0.6-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:43af7aabab7aa6d7c21573736de8b59ccf2f4078f0ae26da70d86005d2ee662b"}, + {file = "openslide_bin-4.0.0.6-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:0bc2e6d624781b0ba24d2ef3d8623fd52de7645520911539e1279d599212ecb0"}, + {file = "openslide_bin-4.0.0.6-py3-none-win_amd64.whl", hash = "sha256:d9bb0659bce0384f6f961aa64c0cfdb882c8dacd6f4fbfaf84895e06fe571f40"}, +] + [[package]] name = "openslide-python" version = "1.4.1" @@ -1900,6 +1914,17 @@ files = [ {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, ] +[[package]] +name = "pkgconfig" +version = "1.5.5" +requires_python = ">=3.3,<4.0" +summary = "Interface Python with pkg-config" +groups = ["default"] +files = [ + {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, + {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, +] + [[package]] name = "platformdirs" version = "4.3.6" @@ -2223,10 +2248,11 @@ files = [ [[package]] name = "pyvips" version = "2.2.3" -summary = "binding for the libvips image processing library, ABI mode" +summary = "binding for the libvips image processing library, API mode" groups = ["default"] dependencies = [ "cffi>=1.0.0", + "pkgconfig", ] files = [ {file = "pyvips-2.2.3.tar.gz", hash = "sha256:43bceced0db492654c93008246a58a508e0373ae1621116b87b322f2ac72212f"}, diff --git a/pyproject.toml b/pyproject.toml index bd5e1e3..83dd1f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,8 @@ dependencies = [ "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", "rationai-kube-jobs @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git", - "scikit-image>=0.25.2" + "scikit-image>=0.25.2", + "openslide-bin>=4.0.0.6" ] [tool.pdm.dev-dependencies] diff --git a/stain_normalization/__main__.py b/stain_normalization/__main__.py index 24659aa..c4e1155 100644 --- a/stain_normalization/__main__.py +++ b/stain_normalization/__main__.py @@ -6,6 +6,7 @@ from omegaconf import DictConfig, OmegaConf from rationai.mlkit import Trainer, autolog +from stain_normalization.callbacks.tiles_export import TilesExport from stain_normalization.data import DataModule from stain_normalization.stain_normalization_model import StainNormalizationModel @@ -27,7 +28,9 @@ def main(config: DictConfig, logger: Logger | None) -> None: ) model = hydra.utils.instantiate(config.model, _target_=StainNormalizationModel) - trainer = hydra.utils.instantiate(config.trainer, _target_=Trainer, logger=logger) + tile_export_callbeck = TilesExport(config.output_dir, config.data.predict.normalize) + + trainer = hydra.utils.instantiate(config.trainer, _target_=Trainer, logger=logger, callbacks=[tile_export_callbeck]) getattr(trainer, config.mode)(model, datamodule=data, ckpt_path=config.checkpoint) diff --git a/stain_normalization/callbacks/tiles_export.py b/stain_normalization/callbacks/tiles_export.py new file mode 100644 index 0000000..7166dcd --- /dev/null +++ b/stain_normalization/callbacks/tiles_export.py @@ -0,0 +1,62 @@ +from pathlib import Path +from lightning import Callback, LightningModule, Trainer +from PIL import Image +from omegaconf import DictConfig +import torch + + +class TilesExport(Callback): + def __init__(self, output_dir: str | Path, predict_normalization_config: DictConfig) -> None: + super().__init__() + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + # Extract normalization parameters from the config (predict normalization) + normalization = predict_normalization_config + self.mean = torch.tensor(normalization.mean).view(3, 1, 1) + self.std = torch.tensor(normalization.std).view(3, 1, 1) + + + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: + device = tensor.device + + std = self.std.to(device) + mean = self.mean.to(device) + + return (tensor * std) + mean + + def tensor_to_image(self, tensor: torch.Tensor) -> Image.Image: + """Convert a PyTorch tensor to a PIL image .""" + tensor = self.denormalize(tensor) + tensor = tensor.clamp(0, 1) + tensor = (tensor * 255).byte() + return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) + + def on_predict_batch_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list], + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + """ + Saves three images per sample: + - Original Image (ground truth) + - Modified Image (input to model) + - Predicted Image (model output) + """ + for b in range(len(outputs)): + predicted_image = outputs[b] + original_image = Image.fromarray(batch[1][b]["original_image"].astype("uint8")) + modified_image = Image.fromarray((batch[1][b]["modified_image"] * 255).astype("uint8")) + index = batch[1][b]["index"] + + predicted_image = self.tensor_to_image(predicted_image) + + # Save images + original_image.save(self.output_dir / f"{index}_original.png") + modified_image.save(self.output_dir / f"{index}_modified.png") + predicted_image.save(self.output_dir / f"{index}_predicted.png") + diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py index 40147f6..88a9138 100644 --- a/stain_normalization/data/data_module.py +++ b/stain_normalization/data/data_module.py @@ -1,4 +1,6 @@ +from typing import Any from collections.abc import Iterable +from torch import Tensor from hydra.utils import instantiate from lightning import LightningDataModule @@ -6,6 +8,7 @@ from torch.utils.data import DataLoader from stain_normalization.typing import Input +from stain_normalization.data.utils import collate_fn class DataModule(LightningDataModule): @@ -26,6 +29,9 @@ def setup(self, stage: str) -> None: self.val = instantiate(self.datasets["val"]) case "test": self.test = instantiate(self.datasets["test"]) + case "predict": + # this need predict val is for debuging only + self.predict = instantiate(self.datasets["predict"]) def train_dataloader(self) -> Iterable[Input]: return DataLoader( @@ -49,3 +55,11 @@ def test_dataloader(self) -> Iterable[Input]: return DataLoader( self.test, batch_size=self.batch_size, num_workers=self.num_workers ) + + def predict_dataloader(self) -> Iterable[tuple[Tensor, list[dict[str, Any]]]]: + return DataLoader( + self.predict, + batch_size=self.batch_size, + num_workers=self.num_workers, + collate_fn=collate_fn, + ) \ No newline at end of file diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py index 6c6f354..64aa680 100644 --- a/stain_normalization/data/datasets/stain_normalization.py +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -94,27 +94,25 @@ def __len__(self) -> int: return len(self.slide_tiles) def __getitem__(self, idx: int) -> Sample | PredictSample: - original_image = self.slide_tiles[idx] - + original_image_255 = self.slide_tiles[idx] # This is not distruptive transform as rotate, flip if self.transforms is not None: - original_image = self.transforms(image=original_image)["image"] + original_image_255 = self.transforms(image=original_image)["image"] # Create "wrong" image to use as input. Outputs image in float 0-1 - modified_image = self.modify(image=original_image)["image"] - - if np.max(original_image) > 1.0: - original_image = original_image / 255.0 + modified_image_raw = self.modify(image=original_image_255)["image"] + modified_image = modified_image_raw + original_image = original_image_255 / 255.0 if self.normalize: original_image = self.normalize(image=original_image)["image"] modified_image = self.normalize(image=modified_image)["image"] - original_image = self.to_tensor(image=original_image)["image"].float() - modified_image = self.to_tensor(image=modified_image)["image"].float() + original_image = self.to_tensor(image=original_image)["image"] + modified_image = self.to_tensor(image=modified_image)["image"] if self.include_target: return modified_image, original_image - return modified_image + return modified_image, {"original_image":original_image_255, "modified_image":modified_image_raw,"index":idx} diff --git a/stain_normalization/data/utils/__init__.py b/stain_normalization/data/utils/__init__.py new file mode 100644 index 0000000..dca47bc --- /dev/null +++ b/stain_normalization/data/utils/__init__.py @@ -0,0 +1,4 @@ +from stain_normalization.data.utils.collate_fn import collate_fn + + +__all__ = ["collate_fn"] diff --git a/stain_normalization/data/utils/collate_fn.py b/stain_normalization/data/utils/collate_fn.py new file mode 100644 index 0000000..667897e --- /dev/null +++ b/stain_normalization/data/utils/collate_fn.py @@ -0,0 +1,6 @@ +from typing import Any +import torch +from torch import Tensor + +def collate_fn(batch: list[tuple[Tensor, Any]]) -> tuple[Tensor, list[Any]]: + return torch.stack([x[0] for x in batch]), [x[1] for x in batch] diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 7aca27c..5103d70 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -7,6 +7,7 @@ from torch.optim.optimizer import Optimizer from torchmetrics.image import PeakSignalNoiseRatio,StructuralSimilarityIndexMeasure from torchmetrics import MetricCollection +from typing import Any class StainNormalizationModel(LightningModule): def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: @@ -61,6 +62,9 @@ def test_step(self, batch: Input) -> None: on_epoch=True, ) + def predict_step(self, batch: tuple[Tensor, Any], batch_idx: int, dataloader_idx: int = 0) -> Outputs: + inputs = batch[0] + return self(inputs) def configure_optimizers(self) -> Optimizer: return Adam(self.parameters(), lr=1e-4) diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py index 0216ae3..70c55c4 100644 --- a/stain_normalization/typing.py +++ b/stain_normalization/typing.py @@ -1,4 +1,4 @@ -from typing import TypeAlias, TypedDict +from typing import TypeAlias, TypedDict, Dict, Any from torch import Tensor @@ -10,7 +10,7 @@ # PredictSample: TypeAlias = tuple[Tensor, Metadata] # Sample: TypeAlias = tuple[Tensor, Tensor, Metadata] -PredictSample: TypeAlias = tuple[Tensor] +PredictSample: TypeAlias = tuple[Tensor, Dict[str, Any]] Sample: TypeAlias = tuple[Tensor, Tensor] Input: TypeAlias = Sample From 834a149241dfc24d0f5282e6c317efc6b886938c Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sun, 23 Mar 2025 02:25:26 +0000 Subject: [PATCH 41/79] feat: update loss function --- .../datasets/stain_normalization/val.yaml | 2 +- configs/default.yaml | 4 +- stain_normalization/modeling/l1ssim_loss.py | 49 ++++++++++++++++--- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index 860ea53..8a584fa 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -1,6 +1,6 @@ defaults: # - /data/transforms@transforms: test - - /data/modify@modify: test + - /data/modify@modify: train - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.StainNormalization diff --git a/configs/default.yaml b/configs/default.yaml index 998ba31..c33f0f4 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -30,11 +30,11 @@ data: metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: Second Train Stain Normalization + run_name: Third Train Stain Normalization description: Testing Stain Normalization hyperparams: {} - +output_dir: ./data diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 16cf95d..2910f0b 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -5,22 +5,59 @@ from math import exp -class L1SSIMLoss(nn.Module): - def __init__(self, lambda_dssim: float = 0.5): +class L1SSIMLoss(nn.Module): + def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2, lambda_hf: float = 0.1): super().__init__() self.lambda_dssim = lambda_dssim + self.lambda_gdl = lambda_gdl + self.lambda_hf = lambda_hf def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: - - Ll1 = F.l1_loss(image, target_image, reduction='mean') + Ll1 = F.l1_loss(image, target_image, reduction='mean') # L1 loss + ssim_loss = 1.0 - ssim(image, target_image) # SSIM loss - ssim_loss = 1.0 - ssim(image, target_image) + gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges + hf_loss = high_frequency_loss(image, target_image) # HF loss for textures total_loss = (1.0 - self.lambda_dssim) * Ll1 + \ - self.lambda_dssim * ssim_loss + self.lambda_dssim * ssim_loss + \ + self.lambda_gdl * gdl_loss + \ + self.lambda_hf * hf_loss + return total_loss +def laplacian_filter(image): + kernel = torch.tensor([[0, -1, 0], [-1, 4, -1], [0, -1, 0]], dtype=torch.float32) + kernel = kernel.view(1, 1, 3, 3).to(image.device) + + filtered = [] + for i in range(image.shape[1]): + filtered.append(F.conv2d(image[:, i:i+1, :, :], kernel, padding=1)) + return torch.cat(filtered, dim=1) + + +def high_frequency_loss(image, target_image): + image_lap = laplacian_filter(image) + target_lap = laplacian_filter(target_image) + + return F.l1_loss(image_lap, target_lap, reduction='mean') + + +def gradient_loss(image, target_image): + def gradient(x): + dx = torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :]) # Horizontal gradient + dy = torch.abs(x[:, :, :, :-1] - x[:, :, :, 1:]) # Vertical gradient + return dx, dy + + image_dx, image_dy = gradient(image) + target_dx, target_dy = gradient(target_image) + + loss_x = F.l1_loss(image_dx, target_dx, reduction='mean') + loss_y = F.l1_loss(image_dy, target_dy, reduction='mean') + + return loss_x + loss_y + def gaussian(window_size, sigma): gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / From 6c028397f001cd98a5b2428dda479e0a45995133 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Thu, 27 Mar 2025 21:23:05 +0000 Subject: [PATCH 42/79] fix: p=1 --- configs/data/modify/test.yaml | 1 + configs/data/modify/train.yaml | 1 + configs/data/transforms/train.yaml | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configs/data/modify/test.yaml b/configs/data/modify/test.yaml index d69792c..8024799 100644 --- a/configs/data/modify/test.yaml +++ b/configs/data/modify/test.yaml @@ -1,4 +1,5 @@ _target_: albumentations.OneOf +p: 1.0 transforms: - _target_: stain_normalization.data.transformation.HEDFactor h_range: [0.8, 1.2] diff --git a/configs/data/modify/train.yaml b/configs/data/modify/train.yaml index d69792c..8024799 100644 --- a/configs/data/modify/train.yaml +++ b/configs/data/modify/train.yaml @@ -1,4 +1,5 @@ _target_: albumentations.OneOf +p: 1.0 transforms: - _target_: stain_normalization.data.transformation.HEDFactor h_range: [0.8, 1.2] diff --git a/configs/data/transforms/train.yaml b/configs/data/transforms/train.yaml index 4cec39f..5e357d6 100644 --- a/configs/data/transforms/train.yaml +++ b/configs/data/transforms/train.yaml @@ -4,4 +4,9 @@ transforms: p: 1.0 - _target_: albumentations.Flip p: 0.75 - + - _target_: albumentations.RandomGamma + p: 0.5 + - _target_: albumentations.RandomBrightnessContrast + p: 0.5 + - _target_: albumentations.HueSaturationValue + p: 0.5 \ No newline at end of file From 68c919dcba61f26147115295c51a373004bba9c9 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 28 Mar 2025 09:25:54 +0000 Subject: [PATCH 43/79] fix: more frequent validation --- configs/default.yaml | 1 + stain_normalization/modeling/l1ssim_loss.py | 82 ++------------------- 2 files changed, 7 insertions(+), 76 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index c33f0f4..9f2532c 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -17,6 +17,7 @@ trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 + val_check_interval: 250 callbacks: - _target_: lightning.pytorch.callbacks.ModelCheckpoint save_top_k: 1 diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 2910f0b..81638a9 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -3,47 +3,29 @@ import torch.nn as nn from torch.autograd import Variable from math import exp +from torchmetrics.image import StructuralSimilarityIndexMeasure as SSIM class L1SSIMLoss(nn.Module): - def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2, lambda_hf: float = 0.1): + def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2, ): super().__init__() self.lambda_dssim = lambda_dssim self.lambda_gdl = lambda_gdl - self.lambda_hf = lambda_hf def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: Ll1 = F.l1_loss(image, target_image, reduction='mean') # L1 loss - ssim_loss = 1.0 - ssim(image, target_image) # SSIM loss + ssim_loss = 1.0 - SSIM(image, target_image) gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges - hf_loss = high_frequency_loss(image, target_image) # HF loss for textures + # hf_loss = high_frequency_loss(image, target_image) # HF loss for textures total_loss = (1.0 - self.lambda_dssim) * Ll1 + \ self.lambda_dssim * ssim_loss + \ - self.lambda_gdl * gdl_loss + \ - self.lambda_hf * hf_loss - + self.lambda_gdl * gdl_loss + return total_loss -def laplacian_filter(image): - kernel = torch.tensor([[0, -1, 0], [-1, 4, -1], [0, -1, 0]], dtype=torch.float32) - kernel = kernel.view(1, 1, 3, 3).to(image.device) - - filtered = [] - for i in range(image.shape[1]): - filtered.append(F.conv2d(image[:, i:i+1, :, :], kernel, padding=1)) - return torch.cat(filtered, dim=1) - - -def high_frequency_loss(image, target_image): - image_lap = laplacian_filter(image) - target_lap = laplacian_filter(target_image) - - return F.l1_loss(image_lap, target_lap, reduction='mean') - - def gradient_loss(image, target_image): def gradient(x): dx = torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :]) # Horizontal gradient @@ -58,55 +40,3 @@ def gradient(x): return loss_x + loss_y - -def gaussian(window_size, sigma): - gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / - float(2 * sigma ** 2)) for x in range(window_size)]) - return gauss / gauss.sum() - - -def create_window(window_size, channel): - _1D_window = gaussian(window_size, 1.5).unsqueeze(1) - _2D_window = _1D_window.mm( - _1D_window.t()).float().unsqueeze(0).unsqueeze(0) - window = Variable(_2D_window.expand( - channel, 1, window_size, window_size).contiguous()) - return window - - -def ssim(img1, img2, window_size=11, size_average=True): - channel = img1.size(-3) - window = create_window(window_size, channel) - - if img1.is_cuda: - window = window.cuda(img1.get_device()) - window = window.type_as(img1) - - return _ssim(img1, img2, window, window_size, channel, size_average) - - -def _ssim(img1, img2, window, window_size, channel, size_average=True): - mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) - mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) - - mu1_sq = mu1.pow(2) - mu2_sq = mu2.pow(2) - mu1_mu2 = mu1 * mu2 - - sigma1_sq = F.conv2d(img1 * img1, window, - padding=window_size // 2, groups=channel) - mu1_sq - sigma2_sq = F.conv2d(img2 * img2, window, - padding=window_size // 2, groups=channel) - mu2_sq - sigma12 = F.conv2d(img1 * img2, window, - padding=window_size // 2, groups=channel) - mu1_mu2 - - C1 = 0.01 ** 2 - C2 = 0.03 ** 2 - - ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / \ - ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) - - if size_average: - return ssim_map.mean() - else: - return ssim_map.mean(1).mean(1).mean(1) From a2a5725a07a3f78fffc453b43573468f9152208e Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 18:42:51 +0000 Subject: [PATCH 44/79] fix: val logging --- stain_normalization/stain_normalization_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 5103d70..8e82da7 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -48,7 +48,8 @@ def validation_step(self, batch: Input) -> None: self.log_dict( self.val_metrics, batch_size=len(inputs), - on_epoch=True, + on_epoch=False, + on_step=True ) From 497328c3c2c17e9ae020fd5e9c5b958ada18a1b9 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 18:45:04 +0000 Subject: [PATCH 45/79] fix: val logging --- stain_normalization/stain_normalization_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 8e82da7..7a8783e 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -43,7 +43,7 @@ def validation_step(self, batch: Input) -> None: outputs = self(inputs) loss = self.criterion(outputs, targets) - self.log("validation/loss", loss, on_step=False, on_epoch=True) + self.log("validation/loss", loss, on_step=True, on_epoch=False) self.val_metrics.update(outputs, targets) self.log_dict( self.val_metrics, From 80b47732dab5e51ef92f4f96ac17f16471cac1dd Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 19:33:46 +0000 Subject: [PATCH 46/79] fix: repair loss function --- stain_normalization/modeling/l1ssim_loss.py | 62 +++++++++++++++++-- .../stain_normalization_model.py | 6 +- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 81638a9..e921916 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -3,26 +3,24 @@ import torch.nn as nn from torch.autograd import Variable from math import exp -from torchmetrics.image import StructuralSimilarityIndexMeasure as SSIM class L1SSIMLoss(nn.Module): - def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2, ): + def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2): super().__init__() self.lambda_dssim = lambda_dssim self.lambda_gdl = lambda_gdl def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: Ll1 = F.l1_loss(image, target_image, reduction='mean') # L1 loss - ssim_loss = 1.0 - SSIM(image, target_image) + ssim_loss = 1.0 - ssim(image, target_image) # SSIM loss gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges - # hf_loss = high_frequency_loss(image, target_image) # HF loss for textures total_loss = (1.0 - self.lambda_dssim) * Ll1 + \ self.lambda_dssim * ssim_loss + \ - self.lambda_gdl * gdl_loss - + self.lambda_gdl * gdl_loss + return total_loss @@ -40,3 +38,55 @@ def gradient(x): return loss_x + loss_y + +def gaussian(window_size, sigma): + gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / + float(2 * sigma ** 2)) for x in range(window_size)]) + return gauss / gauss.sum() + + +def create_window(window_size, channel): + _1D_window = gaussian(window_size, 1.5).unsqueeze(1) + _2D_window = _1D_window.mm( + _1D_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable(_2D_window.expand( + channel, 1, window_size, window_size).contiguous()) + return window + + +def ssim(img1, img2, window_size=11, size_average=True): + channel = img1.size(-3) + window = create_window(window_size, channel) + + if img1.is_cuda: + window = window.cuda(img1.get_device()) + window = window.type_as(img1) + + return _ssim(img1, img2, window, window_size, channel, size_average) + + +def _ssim(img1, img2, window, window_size, channel, size_average=True): + mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) + mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, + padding=window_size // 2, groups=channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, + padding=window_size // 2, groups=channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, + padding=window_size // 2, groups=channel) - mu1_mu2 + + C1 = 0.01 ** 2 + C2 = 0.03 ** 2 + + ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / \ + ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + + if size_average: + return ssim_map.mean() + else: + return ssim_map.mean(1).mean(1).mean(1) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 7a8783e..387e8d5 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -43,13 +43,13 @@ def validation_step(self, batch: Input) -> None: outputs = self(inputs) loss = self.criterion(outputs, targets) - self.log("validation/loss", loss, on_step=True, on_epoch=False) + self.log("validation/loss", loss, on_step=True, on_epoch=True) self.val_metrics.update(outputs, targets) self.log_dict( self.val_metrics, batch_size=len(inputs), - on_epoch=False, - on_step=True + on_epoch=True, + on_step=True, ) From 9d60be840a3510de91f7727ecff993d1eb89587b Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 19:56:50 +0000 Subject: [PATCH 47/79] fix: revert val logging --- stain_normalization/stain_normalization_model.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 387e8d5..98b858a 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -43,15 +43,13 @@ def validation_step(self, batch: Input) -> None: outputs = self(inputs) loss = self.criterion(outputs, targets) - self.log("validation/loss", loss, on_step=True, on_epoch=True) + self.log("validation/loss", loss, on_step=False, on_epoch=True) self.val_metrics.update(outputs, targets) self.log_dict( self.val_metrics, batch_size=len(inputs), - on_epoch=True, - on_step=True, + on_epoch=True, ) - def test_step(self, batch: Input) -> None: inputs, targets = batch From 20caad9a3b92a97d962a392463317c8246eef248 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 20:31:27 +0000 Subject: [PATCH 48/79] fix: optimalise train data load --- .../data/datasets/stain_normalization.py | 72 ++++++++++++++----- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py index 64aa680..9203f9e 100644 --- a/stain_normalization/data/datasets/stain_normalization.py +++ b/stain_normalization/data/datasets/stain_normalization.py @@ -17,7 +17,6 @@ def __init__( modify: Transform3D, normalize: Transform3D | None = None, transforms: Transform3D | None = None, - ) -> None: self.modify = modify self.transforms = transforms @@ -26,10 +25,9 @@ def __init__( def generate_datasets(self) -> Iterable[Dataset[Sample]]: return ( - _StainNormalizationSlideTiles( + _StainNormalizationTrainSlideTiles( slide, tiles=self.filter_tiles_by_slide(slide["id"]), - include_target=True, modify=self.modify, normalize=self.normalize, transforms=self.transforms, @@ -45,8 +43,7 @@ def __init__( modify: Transform3D, normalize: Transform3D | None = None, transforms: Transform3D | None = None, - - ) -> None: + ) -> None: self.modify = modify self.normalize = normalize self.transforms = transforms @@ -54,10 +51,9 @@ def __init__( def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: return ( - _StainNormalizationSlideTiles( + _StainNormalizationPredictSlideTiles( slide, tiles=self.filter_tiles_by_slide(slide["id"]), - include_target=False, modify=self.modify, normalize=self.normalize, transforms=self.transforms, @@ -66,12 +62,11 @@ def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: ) -class _StainNormalizationSlideTiles(Dataset[Sample | PredictSample]): +class _StainNormalizationTrainSlideTiles(Dataset[Sample]): def __init__( self, slide_metadata: pd.Series, tiles: pd.DataFrame, - include_target: bool, modify: Transform3D, normalize: Transform3D | None = None, transforms: Transform3D | None = None, @@ -87,17 +82,62 @@ def __init__( self.modify = modify self.normalize = normalize self.transforms = transforms - self.include_target = include_target self.to_tensor = ToTensorV2() def __len__(self) -> int: return len(self.slide_tiles) - def __getitem__(self, idx: int) -> Sample | PredictSample: + def __getitem__(self, idx: int) -> Sample: + original_image = self.slide_tiles[idx] + # Apply non-disruptive transformations such as rotation, flip + if self.transforms is not None: + original_image = self.transforms(image=original_image)["image"] + + # Create "wrong" image to use as input. Outputs image in float 0-1 + modified_image = self.modify(image=original_image)["image"] + original_image = original_image / 255.0 + + if self.normalize: + original_image = self.normalize(image=original_image)["image"] + modified_image = self.normalize(image=modified_image)["image"] + + original_image = self.to_tensor(image=original_image)["image"] + modified_image = self.to_tensor(image=modified_image)["image"] + + return modified_image, original_image + + + +class _StainNormalizationPredictSlideTiles(Dataset[PredictSample]): + def __init__( + self, + slide_metadata: pd.Series, + tiles: pd.DataFrame, + modify: Transform3D, + normalize: Transform3D | None = None, + transforms: Transform3D | None = None, + ) -> None: + super().__init__() + self.slide_tiles = OpenSlideTilesDataset( + slide_path=slide_metadata.path, + level=slide_metadata.level, + tile_extent_x=slide_metadata.tile_extent_x, + tile_extent_y=slide_metadata.tile_extent_y, + tiles=tiles, + ) + self.modify = modify + self.normalize = normalize + self.transforms = transforms + self.to_tensor = ToTensorV2() + + def __len__(self) -> int: + return len(self.slide_tiles) + + def __getitem__(self, idx: int) -> PredictSample: original_image_255 = self.slide_tiles[idx] - # This is not distruptive transform as rotate, flip + # Apply non-disruptive transformations such as rotation, flip if self.transforms is not None: - original_image_255 = self.transforms(image=original_image)["image"] + original_image_255 = self.transforms(image=original_image_255)["image"] # Create "wrong" image to use as input. Outputs image in float 0-1 modified_image_raw = self.modify(image=original_image_255)["image"] @@ -112,7 +152,5 @@ def __getitem__(self, idx: int) -> Sample | PredictSample: modified_image = self.to_tensor(image=modified_image)["image"] - if self.include_target: - return modified_image, original_image - - return modified_image, {"original_image":original_image_255, "modified_image":modified_image_raw,"index":idx} + return modified_image, {"original_image": original_image_255, "modified_image": modified_image_raw, "index": idx} + From 4da48cdf8109bc3a51cdfb3e437452d09df324b1 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Mar 2025 21:54:38 +0000 Subject: [PATCH 49/79] fix: update val frequency --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index 9f2532c..29c3e7e 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -17,7 +17,7 @@ trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 - val_check_interval: 250 + val_check_interval: 0.25 callbacks: - _target_: lightning.pytorch.callbacks.ModelCheckpoint save_top_k: 1 From 0df039e4c2cf7bb291b0b9f5ec802d8efd6567f4 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 18 Apr 2025 22:43:33 +0000 Subject: [PATCH 50/79] feat: change to full unet --- stain_normalization/modeling/__init__.py | 3 +- stain_normalization/modeling/unet.py | 114 ++++++++++++++++++ .../stain_normalization_model.py | 12 +- 3 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 stain_normalization/modeling/unet.py diff --git a/stain_normalization/modeling/__init__.py b/stain_normalization/modeling/__init__.py index 9ae4c05..2c4be67 100644 --- a/stain_normalization/modeling/__init__.py +++ b/stain_normalization/modeling/__init__.py @@ -1,2 +1,3 @@ from .l1ssim_loss import L1SSIMLoss -__all__ = ["L1SSIMLoss", "metrics"] \ No newline at end of file +from .unet import UNet +__all__ = ["L1SSIMLoss", "UNet"] \ No newline at end of file diff --git a/stain_normalization/modeling/unet.py b/stain_normalization/modeling/unet.py new file mode 100644 index 0000000..485bc9b --- /dev/null +++ b/stain_normalization/modeling/unet.py @@ -0,0 +1,114 @@ +""" +Model created using segmentation_models_pytorch library: +# Adapted U-Net implementation based on https://github.com/milesial/Pytorch-UNet + +Ronneberger, O., Fischer, P., & Brox, T. (2015). +U-Net: Convolutional Networks for Biomedical Image Segmentation. +arXiv:1505.04597 [cs.CV]. +Retrieved from https://arxiv.org/abs/1505.04597. +""" + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class DoubleConv(nn.Module): + """(convolution => [BN] => ReLU) * 2""" + + def __init__(self, in_channels, out_channels, mid_channels=None): + super().__init__() + if not mid_channels: + mid_channels = out_channels + self.double_conv = nn.Sequential( + nn.Conv2d(in_channels, mid_channels, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(mid_channels), + nn.ReLU(inplace=True), + nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True) + ) + + def forward(self, x): + return self.double_conv(x) + + +class Down(nn.Module): + """Downscaling with maxpool then double conv""" + + def __init__(self, in_channels, out_channels): + super().__init__() + self.maxpool_conv = nn.Sequential( + nn.MaxPool2d(2), + DoubleConv(in_channels, out_channels) + ) + + def forward(self, x): + return self.maxpool_conv(x) + + +class Up(nn.Module): + """Upscaling then double conv""" + + def __init__(self, in_channels, out_channels, bilinear=True): + super().__init__() + + # if bilinear, use the normal convolutions to reduce the number of channels + if bilinear: + self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) + else: + self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) + self.conv = DoubleConv(in_channels, out_channels) + + def forward(self, x1, x2): + x1 = self.up(x1) + # input is CHW + diffY = x2.size()[2] - x1.size()[2] + diffX = x2.size()[3] - x1.size()[3] + + x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, + diffY // 2, diffY - diffY // 2]) + # if you have padding issues, see + # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a + # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd + x = torch.cat([x2, x1], dim=1) + return self.conv(x) + + +class OutConv(nn.Module): + def __init__(self, in_channels, out_channels): + super(OutConv, self).__init__() + self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) + + def forward(self, x): + return self.conv(x) + + +class UNet(nn.Module): + def __init__(self, in_channels=3, out_channels=3, bilinear=True): + super(UNet, self).__init__() + self.in_conv = DoubleConv(in_channels, 64) + self.down1 = Down(64, 128) + self.down2 = Down(128, 256) + self.down3 = Down(256, 512) + + factor = 2 if bilinear else 1 + self.down4 = (Down(512, 1024 // factor)) + self.up1 = (Up(1024, 512 // factor, bilinear)) + self.up2 = (Up(512, 256 // factor, bilinear)) + self.up3 = (Up(256, 128 // factor, bilinear)) + self.up4 = (Up(128, 64, bilinear)) + self.out_conv = OutConv(64, out_channels) + + def forward(self, x): + x1 = self.in_conv(x) + x2 = self.down1(x1) + x3 = self.down2(x2) + x4 = self.down3(x3) + x5 = self.down4(x4) + + x = self.up1(x5, x4) + x = self.up2(x, x3) + x = self.up3(x, x2) + x = self.up4(x, x1) + return self.out_conv(x) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 98b858a..9906481 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -1,7 +1,7 @@ from lightning import LightningModule from torch import Tensor, nn from torch.optim.optimizer import Optimizer -from stain_normalization.modeling import L1SSIMLoss +from stain_normalization.modeling import L1SSIMLoss, UNet from stain_normalization.typing import Input, Outputs from torch.optim import Adam from torch.optim.optimizer import Optimizer @@ -12,22 +12,20 @@ class StainNormalizationModel(LightningModule): def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: super().__init__() - self.backbone = backbone - self.decode_head = decode_head + self.unet = UNet(in_channels=3,out_channels=3) self.criterion = L1SSIMLoss() self.val_metrics = MetricCollection( { "ssim": StructuralSimilarityIndexMeasure(), - "psnr": PeakSignalNoiseRatio() + # "psnr": PeakSignalNoiseRatio() } ) self.test_metrics = self.val_metrics.clone(prefix="test/") self.val_metrics.prefix = "validation/" def forward(self, x: Input) -> Outputs: - features = self.backbone(x) - return self.decode_head(features) + return self.unet(x) def training_step(self, batch: Input) -> Tensor: inputs, targets = batch @@ -43,7 +41,7 @@ def validation_step(self, batch: Input) -> None: outputs = self(inputs) loss = self.criterion(outputs, targets) - self.log("validation/loss", loss, on_step=False, on_epoch=True) + self.log("validation/loss", loss, on_step=False, on_epoch=True, logger=True) self.val_metrics.update(outputs, targets) self.log_dict( self.val_metrics, From c000c354c02eebcfaf120365f6bc31e11227a259 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 18 Apr 2025 22:50:16 +0000 Subject: [PATCH 51/79] chore: update job setup --- configs/default.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 29c3e7e..b551854 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -17,7 +17,7 @@ trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 - val_check_interval: 0.25 + val_check_interval: 0.5 callbacks: - _target_: lightning.pytorch.callbacks.ModelCheckpoint save_top_k: 1 @@ -26,12 +26,12 @@ trainer: data: batch_size: 128 - num_workers: 8 + num_workers: 6 metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: Third Train Stain Normalization + run_name: Unet Train Stain Normalization description: Testing Stain Normalization hyperparams: {} From 8522a27b32adf94eebe5fa1000ea05da9ef6f72b Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 18 Apr 2025 23:20:40 +0000 Subject: [PATCH 52/79] chore: update job setup --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index b551854..58b6d6b 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -25,7 +25,7 @@ trainer: mode: min data: - batch_size: 128 + batch_size: 64 num_workers: 6 metadata: From ad4bfd1b09bb15b737fa5dda345573b401bf4db4 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 16 May 2025 03:10:32 +0000 Subject: [PATCH 53/79] chore: code cleanup --- .../datasets/stain_normalization/predict.yaml | 6 +- .../datasets/stain_normalization/test.yaml | 3 +- .../datasets/stain_normalization/train.yaml | 3 +- .../datasets/stain_normalization/val.yaml | 3 +- configs/data/transforms/test.yaml | 4 - configs/data/transforms/train copy.yaml | 16 -- configs/data/transforms/train.yaml | 12 -- configs/default.yaml | 29 ++-- configs/experiment/.gitkeep | 0 configs/model/backbone/resnet50.yaml | 2 - configs/model/backbone/vgg16.yaml | 2 - configs/model/decode_head/unet2048.yaml | 3 - configs/model/decode_head/unet512.yaml | 3 - pyproject.toml | 3 +- stain_normalization/__main__.py | 8 +- stain_normalization/callbacks/__init__.py | 6 + .../callbacks/analysis_export.py | 117 +++++++++++++ stain_normalization/callbacks/save_wsi.py | 52 ++++++ stain_normalization/callbacks/tiles_export.py | 57 ++++--- stain_normalization/data/data_module.py | 6 +- stain_normalization/data/datasets/__init__.py | 7 +- .../data/datasets/predict_dataset.py | 74 +++++++++ .../data/datasets/stain_normalization.py | 156 ------------------ .../data/datasets/test_dataset.py | 80 +++++++++ .../data/datasets/train_dataset.py | 75 +++++++++ .../__init__.py | 0 .../combiend_modification.py | 0 .../exposure_adjustment.py | 11 +- .../hed_factor.py | 0 .../hvs_modification.py | 0 .../modeling/backbone/__init__.py | 5 - .../modeling/backbone/resnet50.py | 7 - .../modeling/backbone/vgg16.py | 6 - .../modeling/decode_head/__init__.py | 4 - .../modeling/decode_head/unet.py | 35 ---- stain_normalization/modeling/l1ssim_loss.py | 4 +- .../stain_normalization_model.py | 15 +- stain_normalization/typing.py | 8 - 38 files changed, 485 insertions(+), 337 deletions(-) delete mode 100644 configs/data/transforms/test.yaml delete mode 100644 configs/data/transforms/train copy.yaml delete mode 100644 configs/data/transforms/train.yaml delete mode 100644 configs/experiment/.gitkeep delete mode 100644 configs/model/backbone/resnet50.yaml delete mode 100644 configs/model/backbone/vgg16.yaml delete mode 100644 configs/model/decode_head/unet2048.yaml delete mode 100644 configs/model/decode_head/unet512.yaml create mode 100644 stain_normalization/callbacks/__init__.py create mode 100644 stain_normalization/callbacks/analysis_export.py create mode 100644 stain_normalization/callbacks/save_wsi.py create mode 100644 stain_normalization/data/datasets/predict_dataset.py delete mode 100644 stain_normalization/data/datasets/stain_normalization.py create mode 100644 stain_normalization/data/datasets/test_dataset.py create mode 100644 stain_normalization/data/datasets/train_dataset.py rename stain_normalization/data/{transformation => modification}/__init__.py (100%) rename stain_normalization/data/{transformation => modification}/combiend_modification.py (100%) rename stain_normalization/data/{transformation => modification}/exposure_adjustment.py (57%) rename stain_normalization/data/{transformation => modification}/hed_factor.py (100%) rename stain_normalization/data/{transformation => modification}/hvs_modification.py (100%) delete mode 100644 stain_normalization/modeling/backbone/__init__.py delete mode 100644 stain_normalization/modeling/backbone/resnet50.py delete mode 100644 stain_normalization/modeling/backbone/vgg16.py delete mode 100644 stain_normalization/modeling/decode_head/__init__.py delete mode 100644 stain_normalization/modeling/decode_head/unet.py diff --git a/configs/data/datasets/stain_normalization/predict.yaml b/configs/data/datasets/stain_normalization/predict.yaml index 5da9773..0cf3d2e 100644 --- a/configs/data/datasets/stain_normalization/predict.yaml +++ b/configs/data/datasets/stain_normalization/predict.yaml @@ -1,7 +1,5 @@ defaults: - # - /data/transforms@transforms: test - - /data/modify@modify: test - /data/normalize@normalize: default -_target_: stain_normalization.data.datasets.StainNormalizationPredict -uris: ["mlflow-artifacts:"] +_target_: stain_normalization.data.datasets.PredictDataset +uris: ["mlflow-artifacts:/79/ce91ce61ac8e4b4784b76a7193e59da9/artifacts/FNBrno_400/2"] diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml index 4904032..c55810c 100644 --- a/configs/data/datasets/stain_normalization/test.yaml +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -1,7 +1,6 @@ defaults: - # - /data/transforms@transforms: test - /data/modify@modify: test - /data/normalize@normalize: default -_target_: stain_normalization.data.datasets.StainNormalization +_target_: stain_normalization.data.datasets.TestDataset uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test"] diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml index dfa39eb..e0f2b43 100644 --- a/configs/data/datasets/stain_normalization/train.yaml +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -1,7 +1,6 @@ defaults: - # - /data/transforms@transforms: train - /data/modify@modify: train - /data/normalize@normalize: default -_target_: stain_normalization.data.datasets.StainNormalization +_target_: stain_normalization.data.datasets.TrainDataset uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - train"] diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index 8a584fa..b39e255 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -1,8 +1,7 @@ defaults: - # - /data/transforms@transforms: test - /data/modify@modify: train - /data/normalize@normalize: default -_target_: stain_normalization.data.datasets.StainNormalization +_target_: stain_normalization.data.datasets.TrainDataset uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - val"] diff --git a/configs/data/transforms/test.yaml b/configs/data/transforms/test.yaml deleted file mode 100644 index 7c0a147..0000000 --- a/configs/data/transforms/test.yaml +++ /dev/null @@ -1,4 +0,0 @@ -_target_: albumentations.Normalize -mean: [198.9923, 156.7051, 185.0198] -std: [36.8293, 46.7353, 35.8960] -max_pixel_value: 1 diff --git a/configs/data/transforms/train copy.yaml b/configs/data/transforms/train copy.yaml deleted file mode 100644 index 81162f1..0000000 --- a/configs/data/transforms/train copy.yaml +++ /dev/null @@ -1,16 +0,0 @@ -_target_: albumentations.Compose -transforms: - - _target_: albumentations.RandomRotate90 - p: 1.0 - - _target_: albumentations.Flip - p: 0.75 - - _target_: albumentations.RandomGamma - p: 0.5 - - _target_: albumentations.RandomBrightnessContrast - p: 0.5 - - _target_: albumentations.HueSaturationValue - p: 0.5 - - _target_: albumentations.Normalize - mean: [198.9923, 156.7051, 185.0198] - std: [36.8293, 46.7353, 35.8960] - max_pixel_value: 1 diff --git a/configs/data/transforms/train.yaml b/configs/data/transforms/train.yaml deleted file mode 100644 index 5e357d6..0000000 --- a/configs/data/transforms/train.yaml +++ /dev/null @@ -1,12 +0,0 @@ -_target_: albumentations.Compose -transforms: - - _target_: albumentations.RandomRotate90 - p: 1.0 - - _target_: albumentations.Flip - p: 0.75 - - _target_: albumentations.RandomGamma - p: 0.5 - - _target_: albumentations.RandomBrightnessContrast - p: 0.5 - - _target_: albumentations.HueSaturationValue - p: 0.5 \ No newline at end of file diff --git a/configs/default.yaml b/configs/default.yaml index 58b6d6b..0076175 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -5,37 +5,46 @@ defaults: - /data/datasets@data.val: stain_normalization/val - /data/datasets@data.test: stain_normalization/test - /data/datasets@data.predict: stain_normalization/predict - - /model/backbone: resnet50 - - /model/decode_head: unet2048 - _self_ seed: ${random_seed:} -mode: ??? -checkpoint: null +mode: predict +checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 - val_check_interval: 0.5 callbacks: - _target_: lightning.pytorch.callbacks.ModelCheckpoint save_top_k: 1 monitor: validation/loss mode: min + - _target_: stain_normalization.callbacks.TilesExport + output_dir: ${output_dir} + normalization_config: ${data.test.normalize} + + - _target_: stain_normalization.callbacks.AnalysisExport + output_dir: ${output_dir} + normalization_config: ${data.test.normalize} + + - _target_: stain_normalization.callbacks.SaveWSI + output_dir: ${output_dir} + normalization_config: ${data.predict.normalize} data: - batch_size: 64 - num_workers: 6 + batch_size: 64 + num_workers: 32 metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: Unet Train Stain Normalization - description: Testing Stain Normalization + run_name: Debuging + description: Stain Normalization hyperparams: {} -output_dir: ./data + +output_dir: ./data/test-dataset diff --git a/configs/experiment/.gitkeep b/configs/experiment/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/configs/model/backbone/resnet50.yaml b/configs/model/backbone/resnet50.yaml deleted file mode 100644 index 4b6b5f2..0000000 --- a/configs/model/backbone/resnet50.yaml +++ /dev/null @@ -1,2 +0,0 @@ -_target_: stain_normalization.modeling.backbone.resnet50 -weights: null diff --git a/configs/model/backbone/vgg16.yaml b/configs/model/backbone/vgg16.yaml deleted file mode 100644 index 4e72da5..0000000 --- a/configs/model/backbone/vgg16.yaml +++ /dev/null @@ -1,2 +0,0 @@ -_target_: stain_normalization.modeling.backbone.vgg16 -weights: null diff --git a/configs/model/decode_head/unet2048.yaml b/configs/model/decode_head/unet2048.yaml deleted file mode 100644 index dce8b92..0000000 --- a/configs/model/decode_head/unet2048.yaml +++ /dev/null @@ -1,3 +0,0 @@ -_target_: stain_normalization.modeling.decode_head.UNetDecoder -in_channels: 2048 - diff --git a/configs/model/decode_head/unet512.yaml b/configs/model/decode_head/unet512.yaml deleted file mode 100644 index 6442711..0000000 --- a/configs/model/decode_head/unet512.yaml +++ /dev/null @@ -1,3 +0,0 @@ -_target_: stain_normalization.modeling.decode_head.UNetDecoder -in_channels: 512 - diff --git a/pyproject.toml b/pyproject.toml index 83dd1f8..e498650 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,8 @@ dependencies = [ "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", "rationai-kube-jobs @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git", "scikit-image>=0.25.2", - "openslide-bin>=4.0.0.6" + "openslide-bin>=4.0.0.6", + "rationai-staining @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" ] [tool.pdm.dev-dependencies] diff --git a/stain_normalization/__main__.py b/stain_normalization/__main__.py index c4e1155..f9b86dd 100644 --- a/stain_normalization/__main__.py +++ b/stain_normalization/__main__.py @@ -6,7 +6,6 @@ from omegaconf import DictConfig, OmegaConf from rationai.mlkit import Trainer, autolog -from stain_normalization.callbacks.tiles_export import TilesExport from stain_normalization.data import DataModule from stain_normalization.stain_normalization_model import StainNormalizationModel @@ -26,11 +25,8 @@ def main(config: DictConfig, logger: Logger | None) -> None: _recursive_=False, # to avoid instantiating all the datasets _target_=DataModule, ) - model = hydra.utils.instantiate(config.model, _target_=StainNormalizationModel) - - tile_export_callbeck = TilesExport(config.output_dir, config.data.predict.normalize) - - trainer = hydra.utils.instantiate(config.trainer, _target_=Trainer, logger=logger, callbacks=[tile_export_callbeck]) + model = StainNormalizationModel() + trainer = hydra.utils.instantiate(config.trainer, _target_=Trainer, logger=logger) getattr(trainer, config.mode)(model, datamodule=data, ckpt_path=config.checkpoint) diff --git a/stain_normalization/callbacks/__init__.py b/stain_normalization/callbacks/__init__.py new file mode 100644 index 0000000..f78f0d7 --- /dev/null +++ b/stain_normalization/callbacks/__init__.py @@ -0,0 +1,6 @@ +from stain_normalization.callbacks.analysis_export import AnalysisExport +from stain_normalization.callbacks.tiles_export import TilesExport +from stain_normalization.callbacks.save_wsi import SaveWSI + +__all__ = ["TileExport", "AnalysisExport", "SaveWSI"] + diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py new file mode 100644 index 0000000..0abaa8f --- /dev/null +++ b/stain_normalization/callbacks/analysis_export.py @@ -0,0 +1,117 @@ +import mlflow +import pandas as pd +import torch +from pathlib import Path +from lightning import Callback, LightningModule, Trainer +import numpy as np +from skimage.metrics import structural_similarity as ssim +from rationai.staining import estimate_stain_vectors + + +class AnalysisExport(Callback): + def __init__(self, output_dir: str | Path, normalization_config) -> None: + super().__init__() + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + normalization = normalization_config + self.mean = torch.tensor(normalization.mean).view(3, 1, 1) + self.std = torch.tensor(normalization.std).view(3, 1, 1) + + self.df_diff = pd.DataFrame() + self.df_raw = pd.DataFrame() + + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: + std = self.std.to(tensor.device) + mean = self.mean.to(tensor.device) + return (tensor * std) + mean + + def tensor_to_image(self, tensor: torch.Tensor) -> np.ndarray: + tensor = self.denormalize(tensor).clamp(0, 1) + return (tensor * 255).byte().permute(1, 2, 0).cpu().numpy() + + def _estimate_vectors(self, img: np.ndarray) -> np.ndarray: + return estimate_stain_vectors(img, i0=240, alpha=1, beta=0.15) + + def _compare_vectors(self, vec1: np.ndarray, vec2: np.ndarray) -> float: + return float(np.linalg.norm(vec1 - vec2)) + + def _compute_ssim(self, img1: np.ndarray, img2: np.ndarray) -> float: + return float(ssim(img1, img2, channel_axis=-1, data_range=255)) + + def _compute_nmi(self, img: np.ndarray): # normalized median intensity + avg_rgb = img.mean(axis=2) + median_val = np.median(avg_rgb) + p95_val = np.percentile(avg_rgb, 95) + nmi = median_val / p95_val if p95_val != 0 else 0 + return nmi + +def on_test_batch_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list], + batch_idx: int, + dataloader_idx: int = 0, +) -> None: + for b in range(len(outputs)): + predicted_tensor = outputs[b] + original_np = batch[1][b]["original_image"].astype("uint8") + modified_np = (batch[1][b]["modified_image"] * 255).astype("uint8") + index = batch[1][b]["index"] + predicted_np = self.tensor_to_image(predicted_tensor) + + vec_original = self._estimate_vectors(original_np) + vec_modified = self._estimate_vectors(modified_np) + vec_predicted = self._estimate_vectors(predicted_np) + + vec_diff_mod = self._compare_vectors(vec_original, vec_modified) + vec_diff_pred = self._compare_vectors(vec_original, vec_predicted) + + ssim_mod = self._compute_ssim(original_np, modified_np) + ssim_pred = self._compute_ssim(original_np, predicted_np) + + + nmi_original = self.compute_nmi(original_np) + nmi_modified = self.compute_nmi(modified_np) + nmi_predicted = self.compute_nmi(predicted_np) + + diff_row = { + "index": index, + "vector_diff_modified_vs_original": vec_diff_mod, + "vector_diff_predicted_vs_original": vec_diff_pred, + "ssim_modified_vs_original": ssim_mod, + "ssim_predicted_vs_original": ssim_pred, + "nmi_diff_modified_vs_original": nmi_modified - nmi_original, + "nmi_diff_predicted_vs_original": nmi_predicted - nmi_original, + } + + raw_row = {"index": index} + for name, vec, nmi in zip( + ["original", "modified", "predicted"], + [vec_original, vec_modified, vec_predicted], + [nmi_original, nmi_modified, nmi_predicted] + ): + vectors = vec.flatten() + for j, val in enumerate(vectors): + raw_row[f"{name}_vec_{j}"] = val + raw_row[f"{name}_nmi"] = nmi + + self.df_diff = pd.concat([self.df_diff, pd.DataFrame([diff_row])], ignore_index=True) + self.df_raw = pd.concat([self.df_raw, pd.DataFrame([raw_row])], ignore_index=True) + + def on_predict_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list, + ) -> None: + diff_path = self.output_dir / "analysis_differences.csv" + raw_path = self.output_dir / "analysis_raw_vectors.csv" + + self.df_diff.to_csv(diff_path, index=False) + self.df_raw.to_csv(raw_path, index=False) + + mlflow.log_artifact(str(diff_path), artifact_path="analysis_metrics") + mlflow.log_artifact(str(raw_path), artifact_path="analysis_metrics") diff --git a/stain_normalization/callbacks/save_wsi.py b/stain_normalization/callbacks/save_wsi.py new file mode 100644 index 0000000..614a466 --- /dev/null +++ b/stain_normalization/callbacks/save_wsi.py @@ -0,0 +1,52 @@ +from lightning.pytorch.callbacks import Callback +from pathlib import Path +import torch +from PIL import Image +from omegaconf import DictConfig + + +class SaveWSI(Callback): + def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> None: + super().__init__() + self.output_root = Path(output_dir) + self.mean = torch.tensor(normalization_config.mean).view(3, 1, 1) + self.std = torch.tensor(normalization_config.std).view(3, 1, 1) + + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: + device = tensor.device + std = self.std.to(device) + mean = self.mean.to(device) + return (tensor * std) + mean + + def on_predict_batch_end( + self, + trainer, + pl_module, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list], + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + + for b in range(len(outputs)): + predicted_image = outputs[b] + metadata = batch[1][b] + + slide_name = metadata["slide_name"] + level = metadata["level"] + original_image = Image.fromarray(metadata["original_image"].astype("uint8")) + filename = f'{metadata["xy"]}.png' + + base_folder = self.output_root / str(slide_name) / str(level) + predicted_folder = base_folder / "predicted" + original_folder = base_folder / "original" + + predicted_folder.mkdir(parents=True, exist_ok=True) + original_folder.mkdir(parents=True, exist_ok=True) + + original_image.save(original_folder / filename) + + predicted_image = self.denormalize(predicted_image).clamp(0, 1) + predicted_image = (predicted_image * 255).byte() + predicted_image = Image.fromarray(predicted_image.permute(1, 2, 0).cpu().numpy()) + predicted_image.save(predicted_folder / filename) diff --git a/stain_normalization/callbacks/tiles_export.py b/stain_normalization/callbacks/tiles_export.py index 7166dcd..d0897bd 100644 --- a/stain_normalization/callbacks/tiles_export.py +++ b/stain_normalization/callbacks/tiles_export.py @@ -6,57 +6,64 @@ class TilesExport(Callback): - def __init__(self, output_dir: str | Path, predict_normalization_config: DictConfig) -> None: + def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> None: super().__init__() self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) - # Extract normalization parameters from the config (predict normalization) - normalization = predict_normalization_config + normalization = normalization_config self.mean = torch.tensor(normalization.mean).view(3, 1, 1) self.std = torch.tensor(normalization.std).view(3, 1, 1) - - + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: - device = tensor.device - + device = tensor.device std = self.std.to(device) mean = self.mean.to(device) - return (tensor * std) + mean - + def tensor_to_image(self, tensor: torch.Tensor) -> Image.Image: - """Convert a PyTorch tensor to a PIL image .""" tensor = self.denormalize(tensor) tensor = tensor.clamp(0, 1) tensor = (tensor * 255).byte() return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) + + def on_test_batch_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list], + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + self._save_images(outputs, batch, is_predict=False) def on_predict_batch_end( self, trainer: Trainer, pl_module: LightningModule, - outputs: list[torch.Tensor], + outputs: list[torch.Tensor], batch: tuple[torch.Tensor, list], batch_idx: int, dataloader_idx: int = 0, ) -> None: - """ - Saves three images per sample: - - Original Image (ground truth) - - Modified Image (input to model) - - Predicted Image (model output) - """ + self._save_images(outputs, batch, is_predict=True) + + def _save_images(self, outputs, batch, is_predict: bool) -> None: + inputs, data = batch for b in range(len(outputs)): - predicted_image = outputs[b] - original_image = Image.fromarray(batch[1][b]["original_image"].astype("uint8")) - modified_image = Image.fromarray((batch[1][b]["modified_image"] * 255).astype("uint8")) - index = batch[1][b]["index"] + index = data[b].get("index", 0) + predicted_image = outputs[b] + name = data[b].get("name", str(index)) predicted_image = self.tensor_to_image(predicted_image) - # Save images - original_image.save(self.output_dir / f"{index}_original.png") - modified_image.save(self.output_dir / f"{index}_modified.png") - predicted_image.save(self.output_dir / f"{index}_predicted.png") + predicted_image.save(self.output_dir / f"{name}.png") + + if not is_predict: + original_image = Image.fromarray(data[b]["original_image"].astype("uint8")) + original_image.save(self.output_dir / f"{name}_original.png") + if "modified_image" in data[b]: + modified_image = Image.fromarray((data[b]["modified_image"] * 255).astype("uint8")) + modified_image.save(self.output_dir / f"{name}_modified.png") diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py index 88a9138..c956a65 100644 --- a/stain_normalization/data/data_module.py +++ b/stain_normalization/data/data_module.py @@ -30,7 +30,6 @@ def setup(self, stage: str) -> None: case "test": self.test = instantiate(self.datasets["test"]) case "predict": - # this need predict val is for debuging only self.predict = instantiate(self.datasets["predict"]) def train_dataloader(self) -> Iterable[Input]: @@ -53,7 +52,10 @@ def val_dataloader(self) -> Iterable[Input]: def test_dataloader(self) -> Iterable[Input]: return DataLoader( - self.test, batch_size=self.batch_size, num_workers=self.num_workers + self.test, + batch_size=self.batch_size, + num_workers=self.num_workers, + collate_fn=collate_fn, ) def predict_dataloader(self) -> Iterable[tuple[Tensor, list[dict[str, Any]]]]: diff --git a/stain_normalization/data/datasets/__init__.py b/stain_normalization/data/datasets/__init__.py index 32125cf..7047900 100644 --- a/stain_normalization/data/datasets/__init__.py +++ b/stain_normalization/data/datasets/__init__.py @@ -1,4 +1,5 @@ -from stain_normalization.data.datasets.stain_normalization import StainNormalization, StainNormalizationPredict +from stain_normalization.data.datasets.train_dataset import TrainDataset +from stain_normalization.data.datasets.predict_dataset import PredictDataset +from stain_normalization.data.datasets.test_dataset import TestDataset - -__all__ = ["StainNormalization", "StainNormalizationPredict"] +__all__ = ["TrainDataset", "PredictDataset", "TestDataset"] diff --git a/stain_normalization/data/datasets/predict_dataset.py b/stain_normalization/data/datasets/predict_dataset.py new file mode 100644 index 0000000..2e06f88 --- /dev/null +++ b/stain_normalization/data/datasets/predict_dataset.py @@ -0,0 +1,74 @@ +from collections.abc import Iterable +import numpy as np +import pandas as pd +from albumentations import Transform3D +from albumentations.pytorch import ToTensorV2 +from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset +from torch.utils.data import Dataset +from stain_normalization.typing import PredictSample + +class PredictDataset(MetaTiledSlides[PredictSample]): + def __init__( + self, + uris: Iterable[str], + normalize: Transform3D | None = None, + ) -> None: + self.normalize = normalize + super().__init__(uris=uris) + + def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: + return ( + _PredictSlideTiles( + slide, + tiles=self.filter_tiles_by_slide(slide["id"]), + normalize=self.normalize, + ) + for _, slide in self.slides.iterrows() + ) + + +class _PredictSlideTiles(Dataset[PredictSample]): + def __init__( + self, + slide_metadata: pd.Series, + tiles: pd.DataFrame, + normalize: Transform3D | None = None, + ) -> None: + super().__init__() + self.slide_tiles = OpenSlideTilesDataset( + slide_path=slide_metadata.path, + level=slide_metadata.level, + tile_extent_x=slide_metadata.tile_extent_x, + tile_extent_y=slide_metadata.tile_extent_y, + tiles=tiles, + ) + + self.normalize = normalize + self.to_tensor = ToTensorV2() + + def __len__(self) -> int: + return len(self.slide_tiles) + + def __getitem__(self, idx: int) -> PredictSample: + input_image_255 = self.slide_tiles[idx] + slide_name = self.slide_tiles.slide_path.stem + level = self.slide_tiles.level + x = self.slide_tiles.tiles.iloc[idx]["x"] + y = self.slide_tiles.tiles.iloc[idx]["y"] + + input_image = input_image_255 / 255.0 + + if self.normalize: + input_image = self.normalize(image=input_image)["image"] + + input_image = self.to_tensor(image=input_image)["image"] + + return input_image, {"original_image": input_image_255, + "modified_image": None, + "slide_name": slide_name, + "level":level , + "index": idx, + "xy":f"{x}_{y}", + "name":f"{slide_name}-{x}-{y}"} + + diff --git a/stain_normalization/data/datasets/stain_normalization.py b/stain_normalization/data/datasets/stain_normalization.py deleted file mode 100644 index 9203f9e..0000000 --- a/stain_normalization/data/datasets/stain_normalization.py +++ /dev/null @@ -1,156 +0,0 @@ -from collections.abc import Iterable - -import numpy as np -import pandas as pd -from albumentations import Transform3D -from albumentations.pytorch import ToTensorV2 -from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset -from torch.utils.data import Dataset - -from stain_normalization.typing import PredictSample, Sample - - -class StainNormalization(MetaTiledSlides[Sample]): - def __init__( - self, - uris: Iterable[str], - modify: Transform3D, - normalize: Transform3D | None = None, - transforms: Transform3D | None = None, - ) -> None: - self.modify = modify - self.transforms = transforms - self.normalize = normalize - super().__init__(uris=uris) - - def generate_datasets(self) -> Iterable[Dataset[Sample]]: - return ( - _StainNormalizationTrainSlideTiles( - slide, - tiles=self.filter_tiles_by_slide(slide["id"]), - modify=self.modify, - normalize=self.normalize, - transforms=self.transforms, - ) - for _, slide in self.slides.iterrows() - ) - - -class StainNormalizationPredict(MetaTiledSlides[PredictSample]): - def __init__( - self, - uris: Iterable[str], - modify: Transform3D, - normalize: Transform3D | None = None, - transforms: Transform3D | None = None, - ) -> None: - self.modify = modify - self.normalize = normalize - self.transforms = transforms - super().__init__(uris=uris) - - def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: - return ( - _StainNormalizationPredictSlideTiles( - slide, - tiles=self.filter_tiles_by_slide(slide["id"]), - modify=self.modify, - normalize=self.normalize, - transforms=self.transforms, - ) - for _, slide in self.slides.iterrows() - ) - - -class _StainNormalizationTrainSlideTiles(Dataset[Sample]): - def __init__( - self, - slide_metadata: pd.Series, - tiles: pd.DataFrame, - modify: Transform3D, - normalize: Transform3D | None = None, - transforms: Transform3D | None = None, - ) -> None: - super().__init__() - self.slide_tiles = OpenSlideTilesDataset( - slide_path=slide_metadata.path, - level=slide_metadata.level, - tile_extent_x=slide_metadata.tile_extent_x, - tile_extent_y=slide_metadata.tile_extent_y, - tiles=tiles, - ) - self.modify = modify - self.normalize = normalize - self.transforms = transforms - self.to_tensor = ToTensorV2() - - def __len__(self) -> int: - return len(self.slide_tiles) - - def __getitem__(self, idx: int) -> Sample: - original_image = self.slide_tiles[idx] - # Apply non-disruptive transformations such as rotation, flip - if self.transforms is not None: - original_image = self.transforms(image=original_image)["image"] - - # Create "wrong" image to use as input. Outputs image in float 0-1 - modified_image = self.modify(image=original_image)["image"] - original_image = original_image / 255.0 - - if self.normalize: - original_image = self.normalize(image=original_image)["image"] - modified_image = self.normalize(image=modified_image)["image"] - - original_image = self.to_tensor(image=original_image)["image"] - modified_image = self.to_tensor(image=modified_image)["image"] - - return modified_image, original_image - - - -class _StainNormalizationPredictSlideTiles(Dataset[PredictSample]): - def __init__( - self, - slide_metadata: pd.Series, - tiles: pd.DataFrame, - modify: Transform3D, - normalize: Transform3D | None = None, - transforms: Transform3D | None = None, - ) -> None: - super().__init__() - self.slide_tiles = OpenSlideTilesDataset( - slide_path=slide_metadata.path, - level=slide_metadata.level, - tile_extent_x=slide_metadata.tile_extent_x, - tile_extent_y=slide_metadata.tile_extent_y, - tiles=tiles, - ) - self.modify = modify - self.normalize = normalize - self.transforms = transforms - self.to_tensor = ToTensorV2() - - def __len__(self) -> int: - return len(self.slide_tiles) - - def __getitem__(self, idx: int) -> PredictSample: - original_image_255 = self.slide_tiles[idx] - # Apply non-disruptive transformations such as rotation, flip - if self.transforms is not None: - original_image_255 = self.transforms(image=original_image_255)["image"] - - # Create "wrong" image to use as input. Outputs image in float 0-1 - modified_image_raw = self.modify(image=original_image_255)["image"] - modified_image = modified_image_raw - original_image = original_image_255 / 255.0 - - if self.normalize: - original_image = self.normalize(image=original_image)["image"] - modified_image = self.normalize(image=modified_image)["image"] - - original_image = self.to_tensor(image=original_image)["image"] - modified_image = self.to_tensor(image=modified_image)["image"] - - - return modified_image, {"original_image": original_image_255, "modified_image": modified_image_raw, "index": idx} - diff --git a/stain_normalization/data/datasets/test_dataset.py b/stain_normalization/data/datasets/test_dataset.py new file mode 100644 index 0000000..95363d4 --- /dev/null +++ b/stain_normalization/data/datasets/test_dataset.py @@ -0,0 +1,80 @@ +from collections.abc import Iterable + +import numpy as np +import pandas as pd +from albumentations import Transform3D +from albumentations.pytorch import ToTensorV2 +from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset +from torch.utils.data import Dataset + +from stain_normalization.typing import PredictSample, Sample + +class TestDataset(MetaTiledSlides[PredictSample]): + def __init__( + self, + uris: Iterable[str], + modify: Transform3D, + normalize: Transform3D | None = None, + ) -> None: + self.modify = modify + self.normalize = normalize + super().__init__(uris=uris) + + def generate_datasets(self) -> Iterable[Dataset[PredictSample]]: + return ( + _TestSlideTiles( + slide, + tiles=self.filter_tiles_by_slide(slide["id"]), + modify=self.modify, + normalize=self.normalize, + ) + for _, slide in self.slides.iterrows() + ) + + +class _TestSlideTiles(Dataset[PredictSample]): + def __init__( + self, + slide_metadata: pd.Series, + tiles: pd.DataFrame, + modify: Transform3D, + normalize: Transform3D | None = None, + ) -> None: + super().__init__() + self.slide_tiles = OpenSlideTilesDataset( + slide_path=slide_metadata.path, + level=slide_metadata.level, + tile_extent_x=slide_metadata.tile_extent_x, + tile_extent_y=slide_metadata.tile_extent_y, + tiles=tiles, + ) + self.modify = modify + self.normalize = normalize + self.to_tensor = ToTensorV2() + + def __len__(self) -> int: + return len(self.slide_tiles) + + def __getitem__(self, idx: int) -> PredictSample: + original_image_255 = self.slide_tiles[idx] + + # Create "wrong" image to use as input. Outputs image in float 0-1 + modified_image_raw = self.modify(image=original_image_255)["image"] + modified_image = modified_image_raw + original_image = original_image_255 / 255.0 + + if self.normalize: + original_image = self.normalize(image=original_image)["image"] + modified_image = self.normalize(image=modified_image)["image"] + + original_image = self.to_tensor(image=original_image)["image"] + modified_image = self.to_tensor(image=modified_image)["image"] + + + return (modified_image, + {"original_image_tensor":original_image, + "original_image": original_image_255, + "modified_image": modified_image_raw, + "index": idx} + ) + diff --git a/stain_normalization/data/datasets/train_dataset.py b/stain_normalization/data/datasets/train_dataset.py new file mode 100644 index 0000000..45187d2 --- /dev/null +++ b/stain_normalization/data/datasets/train_dataset.py @@ -0,0 +1,75 @@ +from collections.abc import Iterable + +import numpy as np +import pandas as pd +from albumentations import Transform3D +from albumentations.pytorch import ToTensorV2 +from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset +from torch.utils.data import Dataset + +from stain_normalization.typing import Sample + + +class TrainDataset(MetaTiledSlides[Sample]): + def __init__( + self, + uris: Iterable[str], + modify: Transform3D, + normalize: Transform3D | None = None, + ) -> None: + self.modify = modify + self.normalize = normalize + super().__init__(uris=uris) + + def generate_datasets(self) -> Iterable[Dataset[Sample]]: + return ( + _TrainSlideTiles( + slide, + tiles=self.filter_tiles_by_slide(slide["id"]), + modify=self.modify, + normalize=self.normalize, + ) + for _, slide in self.slides.iterrows() + ) + + +class _TrainSlideTiles(Dataset[Sample]): + def __init__( + self, + slide_metadata: pd.Series, + tiles: pd.DataFrame, + modify: Transform3D, + normalize: Transform3D | None = None, + ) -> None: + super().__init__() + self.slide_tiles = OpenSlideTilesDataset( + slide_path=slide_metadata.path, + level=slide_metadata.level, + tile_extent_x=slide_metadata.tile_extent_x, + tile_extent_y=slide_metadata.tile_extent_y, + tiles=tiles, + ) + self.modify = modify + self.normalize = normalize + self.to_tensor = ToTensorV2() + + def __len__(self) -> int: + return len(self.slide_tiles) + + def __getitem__(self, idx: int) -> Sample: + original_image = self.slide_tiles[idx] + + # Create "wrong" image to use as input. Outputs image in float 0-1 + modified_image = self.modify(image=original_image)["image"] + original_image = original_image / 255.0 + + if self.normalize: + original_image = self.normalize(image=original_image)["image"] + modified_image = self.normalize(image=modified_image)["image"] + + original_image = self.to_tensor(image=original_image)["image"] + modified_image = self.to_tensor(image=modified_image)["image"] + + return modified_image, original_image + + diff --git a/stain_normalization/data/transformation/__init__.py b/stain_normalization/data/modification/__init__.py similarity index 100% rename from stain_normalization/data/transformation/__init__.py rename to stain_normalization/data/modification/__init__.py diff --git a/stain_normalization/data/transformation/combiend_modification.py b/stain_normalization/data/modification/combiend_modification.py similarity index 100% rename from stain_normalization/data/transformation/combiend_modification.py rename to stain_normalization/data/modification/combiend_modification.py diff --git a/stain_normalization/data/transformation/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py similarity index 57% rename from stain_normalization/data/transformation/exposure_adjustment.py rename to stain_normalization/data/modification/exposure_adjustment.py index 4cc9a41..fe25768 100644 --- a/stain_normalization/data/transformation/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -9,13 +9,8 @@ def __init__(self, brightness_range: tuple[float, float] = (0.8, 1.2), always_ap self.brightness_range = brightness_range def apply(self, img, **params): - hed_img = separate_stains(img, hed_from_rgb) - brightness_factor = np.random.uniform(*self.brightness_range) - h, e, d = hed_img[:, :, 0], hed_img[:, :, 1], hed_img[:, :, 2] - h = np.clip(h * brightness_factor, 0, 1) - e = np.clip(e * brightness_factor, 0, 1) - d = np.clip(d * brightness_factor, 0, 1) + img = img.astype(np.float32) + img = np.clip(img*brightness_factor, 0.0, 1.0) - modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) - return modified_rgb + return img diff --git a/stain_normalization/data/transformation/hed_factor.py b/stain_normalization/data/modification/hed_factor.py similarity index 100% rename from stain_normalization/data/transformation/hed_factor.py rename to stain_normalization/data/modification/hed_factor.py diff --git a/stain_normalization/data/transformation/hvs_modification.py b/stain_normalization/data/modification/hvs_modification.py similarity index 100% rename from stain_normalization/data/transformation/hvs_modification.py rename to stain_normalization/data/modification/hvs_modification.py diff --git a/stain_normalization/modeling/backbone/__init__.py b/stain_normalization/modeling/backbone/__init__.py deleted file mode 100644 index 68da66e..0000000 --- a/stain_normalization/modeling/backbone/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from stain_normalization.modeling.backbone.resnet50 import resnet50 -from stain_normalization.modeling.backbone.vgg16 import vgg16 - - -__all__ = ["resnet50", "vgg16"] \ No newline at end of file diff --git a/stain_normalization/modeling/backbone/resnet50.py b/stain_normalization/modeling/backbone/resnet50.py deleted file mode 100644 index 7705385..0000000 --- a/stain_normalization/modeling/backbone/resnet50.py +++ /dev/null @@ -1,7 +0,0 @@ -import torchvision -from torch import nn - - -def resnet50(weights: str | None = None) -> nn.Module: - resnet = torchvision.models.resnet50(weights=weights) - return nn.Sequential(*(list(resnet.children())[:-2])) diff --git a/stain_normalization/modeling/backbone/vgg16.py b/stain_normalization/modeling/backbone/vgg16.py deleted file mode 100644 index 0864515..0000000 --- a/stain_normalization/modeling/backbone/vgg16.py +++ /dev/null @@ -1,6 +0,0 @@ -from torch import nn -import torchvision - -def vgg16(weights: str | None = None) -> nn.Module: - return torchvision.models.vgg16(weights=weights).features - diff --git a/stain_normalization/modeling/decode_head/__init__.py b/stain_normalization/modeling/decode_head/__init__.py deleted file mode 100644 index 3f19fab..0000000 --- a/stain_normalization/modeling/decode_head/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from stain_normalization.modeling.decode_head.unet import UNetDecoder - - -__all__ = ["UNetDecoder"] \ No newline at end of file diff --git a/stain_normalization/modeling/decode_head/unet.py b/stain_normalization/modeling/decode_head/unet.py deleted file mode 100644 index 57052aa..0000000 --- a/stain_normalization/modeling/decode_head/unet.py +++ /dev/null @@ -1,35 +0,0 @@ -import torch -import torch.nn as nn -import torch.nn.functional as F - -class UNetDecoder(nn.Module): - def __init__(self, in_channels=2048, out_channels=3): - super(UNetDecoder, self).__init__() - - # First upsampling block - self.upconv1 = nn.ConvTranspose2d(in_channels, 1024, kernel_size=2, stride=2) - self.conv1 = nn.Conv2d(1024, 512, kernel_size=3, padding=1) - - # Second upsampling block - self.upconv2 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2) - self.conv2 = nn.Conv2d(256, 128, kernel_size=3, padding=1) - - # Third upsampling block - self.upconv3 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2) - self.conv3 = nn.Conv2d(64, 64, kernel_size=3, padding=1) - - # Fourth upsampling block - self.upconv4 = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2) - self.conv4 = nn.Conv2d(32, 16, kernel_size=3, padding=1) - - # Final upsampling to match 512x512 resolution - self.upconv5 = nn.ConvTranspose2d(16, 8, kernel_size=2, stride=2) - self.conv5 = nn.Conv2d(8, out_channels, kernel_size=1) # 3-channel RGB output - - def forward(self, x): - x = F.relu(self.conv1(self.upconv1(x))) - x = F.relu(self.conv2(self.upconv2(x))) - x = F.relu(self.conv3(self.upconv3(x))) - x = F.relu(self.conv4(self.upconv4(x))) - x = self.conv5(self.upconv5(x)) # No activation; apply outside - return x diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index e921916..25e2e75 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -12,8 +12,8 @@ def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2): self.lambda_gdl = lambda_gdl def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: - Ll1 = F.l1_loss(image, target_image, reduction='mean') # L1 loss - ssim_loss = 1.0 - ssim(image, target_image) # SSIM loss + Ll1 = F.l1_loss(image, target_image, reduction='mean') + ssim_loss = 1.0 - ssim(image, target_image) gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 9906481..7809a03 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -1,16 +1,16 @@ from lightning import LightningModule -from torch import Tensor, nn +from torch import Tensor, nn, stack from torch.optim.optimizer import Optimizer from stain_normalization.modeling import L1SSIMLoss, UNet from stain_normalization.typing import Input, Outputs from torch.optim import Adam from torch.optim.optimizer import Optimizer -from torchmetrics.image import PeakSignalNoiseRatio,StructuralSimilarityIndexMeasure +from torchmetrics.image import StructuralSimilarityIndexMeasure from torchmetrics import MetricCollection from typing import Any class StainNormalizationModel(LightningModule): - def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: + def __init__(self) -> None: super().__init__() self.unet = UNet(in_channels=3,out_channels=3) self.criterion = L1SSIMLoss() @@ -18,7 +18,6 @@ def __init__(self, backbone: nn.Module, decode_head: nn.Module) -> None: self.val_metrics = MetricCollection( { "ssim": StructuralSimilarityIndexMeasure(), - # "psnr": PeakSignalNoiseRatio() } ) self.test_metrics = self.val_metrics.clone(prefix="test/") @@ -49,17 +48,19 @@ def validation_step(self, batch: Input) -> None: on_epoch=True, ) - def test_step(self, batch: Input) -> None: - inputs, targets = batch + def test_step(self, batch: Input) -> Outputs: + inputs, data = batch outputs = self(inputs) + targets = stack([item['original_image_tensor'] for item in data]) self.test_metrics.update(outputs, targets) self.log_dict( self.test_metrics, batch_size=len(inputs), on_epoch=True, ) + return outputs - def predict_step(self, batch: tuple[Tensor, Any], batch_idx: int, dataloader_idx: int = 0) -> Outputs: + def predict_step(self, batch: tuple[Tensor, Any], batch_idx: int) -> Outputs: inputs = batch[0] return self(inputs) diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py index 70c55c4..15088b6 100644 --- a/stain_normalization/typing.py +++ b/stain_normalization/typing.py @@ -2,14 +2,6 @@ from torch import Tensor -# class Metadata(TypedDict): -# slide: str -# x: int -# y: int -# transormation: str -# PredictSample: TypeAlias = tuple[Tensor, Metadata] -# Sample: TypeAlias = tuple[Tensor, Tensor, Metadata] - PredictSample: TypeAlias = tuple[Tensor, Dict[str, Any]] Sample: TypeAlias = tuple[Tensor, Tensor] From 8beb39829e2cd61dbf790d0e1f5d601bd4d95766 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 16 May 2025 13:35:37 +0000 Subject: [PATCH 54/79] chore: formating fix --- job.py | 19 ------------ pdm.lock | 30 ++++++++++--------- preprocessing/mask_generator.py | 4 +-- preprocessing/tiler.py | 3 +- pyproject.toml | 1 - stain_normalization/callbacks/__init__.py | 5 ++-- .../callbacks/analysis_export.py | 9 +++--- stain_normalization/callbacks/save_wsi.py | 5 ++-- stain_normalization/callbacks/tiles_export.py | 5 ++-- stain_normalization/data/data_module.py | 6 ++-- stain_normalization/data/datasets/__init__.py | 5 ++-- .../data/datasets/predict_dataset.py | 4 ++- .../data/datasets/test_dataset.py | 4 +-- .../data/datasets/train_dataset.py | 1 - .../data/modification/__init__.py | 11 +++++-- .../modification/combiend_modification.py | 2 +- .../data/modification/exposure_adjustment.py | 1 - .../data/modification/hed_factor.py | 3 +- .../data/modification/hvs_modification.py | 2 +- stain_normalization/data/utils/collate_fn.py | 2 ++ stain_normalization/modeling/__init__.py | 2 ++ stain_normalization/modeling/l1ssim_loss.py | 5 ++-- stain_normalization/modeling/unet.py | 4 +-- .../stain_normalization_model.py | 14 +++++---- stain_normalization/typing.py | 5 ++-- 25 files changed, 77 insertions(+), 75 deletions(-) delete mode 100644 job.py diff --git a/job.py b/job.py deleted file mode 100644 index 6da6dee..0000000 --- a/job.py +++ /dev/null @@ -1,19 +0,0 @@ -from kube_jobs import Storage, submit_job - - -submit_job( - job_name="stain-normalization-train", - username="xlopatka", - cpu=10, - memory="128Gi", - gpu="A40", - shm="16384Mi", - script=[ - "git clone https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git", - "cd staining", - "git checkout feature/ml-stain-normalization", - "pdm sync --skip=post_install", - "pdm train", - ], - storage=Storage(mou=True), -) diff --git a/pdm.lock b/pdm.lock index 282e879..267b14f 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:5332e3a0a1aebc8df232aacd3e71bbc5bdbaeec0efddc8d0137eafb3cd6c2c32" +content_hash = "sha256:2f62924ed5f088a39fa44fe5eaa436688edca68488cf39f4b0f4da79ca23d64f" [[metadata.targets]] requires_python = ">=3.11" @@ -1914,17 +1914,6 @@ files = [ {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, ] -[[package]] -name = "pkgconfig" -version = "1.5.5" -requires_python = ">=3.3,<4.0" -summary = "Interface Python with pkg-config" -groups = ["default"] -files = [ - {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, - {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, -] - [[package]] name = "platformdirs" version = "4.3.6" @@ -2248,11 +2237,10 @@ files = [ [[package]] name = "pyvips" version = "2.2.3" -summary = "binding for the libvips image processing library, API mode" +summary = "binding for the libvips image processing library, ABI mode" groups = ["default"] dependencies = [ "cffi>=1.0.0", - "pkgconfig", ] files = [ {file = "pyvips-2.2.3.tar.gz", hash = "sha256:43bceced0db492654c93008246a58a508e0373ae1621116b87b322f2ac72212f"}, @@ -2363,6 +2351,20 @@ dependencies = [ "torch>=2.2.0", ] +[[package]] +name = "rationai-staining" +version = "0.1.0" +requires_python = ">=3.11" +git = "ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" +revision = "bd1d704d86468a42d2321e9041c746215255c099" +summary = "" +groups = ["default"] +dependencies = [ + "numpy>=1.26.4", + "pillow>=10.3.0", + "scikit-image>=0.23.2", +] + [[package]] name = "rationai-tiling" version = "1.1.0" diff --git a/preprocessing/mask_generator.py b/preprocessing/mask_generator.py index aa40f73..45cd285 100644 --- a/preprocessing/mask_generator.py +++ b/preprocessing/mask_generator.py @@ -1,9 +1,9 @@ from pathlib import Path + import pyvips import ray from openslide import PROPERTY_NAME_MPP_X, PROPERTY_NAME_MPP_Y, OpenSlide -from rationai.masks import tissue_mask, write_big_tiff -from rationai.masks import process_items +from rationai.masks import process_items, tissue_mask, write_big_tiff # folders: diff --git a/preprocessing/tiler.py b/preprocessing/tiler.py index fb54ac8..5ffb3a4 100644 --- a/preprocessing/tiler.py +++ b/preprocessing/tiler.py @@ -1,4 +1,5 @@ from pathlib import Path + import mlflow import ray from rationai.tiling import tiling @@ -98,7 +99,7 @@ def main() -> None: test_slides_df.to_csv("./data/datasets/test_slides.csv", index=False) test_tiles_df.to_csv("./data/datasets/test_tiles.csv", index=False) - mlflow.set_experiment(experiment_name="Stain Normalization") + mlflow.set_experiment(experiment_name="Stain-Normalization") with mlflow.start_run(run_name="Stain Normalization Dataset") as _: save_mlflow_dataset( slides=train_slides_df, diff --git a/pyproject.toml b/pyproject.toml index e498650..f8be213 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,6 @@ dependencies = [ "rationai-mlkit @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git", "rationai-masks @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git", "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", - "rationai-kube-jobs @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git", "scikit-image>=0.25.2", "openslide-bin>=4.0.0.6", "rationai-staining @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" diff --git a/stain_normalization/callbacks/__init__.py b/stain_normalization/callbacks/__init__.py index f78f0d7..344b24c 100644 --- a/stain_normalization/callbacks/__init__.py +++ b/stain_normalization/callbacks/__init__.py @@ -1,6 +1,7 @@ from stain_normalization.callbacks.analysis_export import AnalysisExport -from stain_normalization.callbacks.tiles_export import TilesExport from stain_normalization.callbacks.save_wsi import SaveWSI +from stain_normalization.callbacks.tiles_export import TilesExport + -__all__ = ["TileExport", "AnalysisExport", "SaveWSI"] +__all__ = ["AnalysisExport", "SaveWSI", "TileExport"] diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index 0abaa8f..bd48d21 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -1,11 +1,12 @@ +from pathlib import Path + import mlflow +import numpy as np import pandas as pd import torch -from pathlib import Path from lightning import Callback, LightningModule, Trainer -import numpy as np -from skimage.metrics import structural_similarity as ssim from rationai.staining import estimate_stain_vectors +from skimage.metrics import structural_similarity as ssim class AnalysisExport(Callback): @@ -91,7 +92,7 @@ def on_test_batch_end( for name, vec, nmi in zip( ["original", "modified", "predicted"], [vec_original, vec_modified, vec_predicted], - [nmi_original, nmi_modified, nmi_predicted] + [nmi_original, nmi_modified, nmi_predicted], strict=False ): vectors = vec.flatten() for j, val in enumerate(vectors): diff --git a/stain_normalization/callbacks/save_wsi.py b/stain_normalization/callbacks/save_wsi.py index 614a466..7bec981 100644 --- a/stain_normalization/callbacks/save_wsi.py +++ b/stain_normalization/callbacks/save_wsi.py @@ -1,8 +1,9 @@ -from lightning.pytorch.callbacks import Callback from pathlib import Path + import torch -from PIL import Image +from lightning.pytorch.callbacks import Callback from omegaconf import DictConfig +from PIL import Image class SaveWSI(Callback): diff --git a/stain_normalization/callbacks/tiles_export.py b/stain_normalization/callbacks/tiles_export.py index d0897bd..724d92e 100644 --- a/stain_normalization/callbacks/tiles_export.py +++ b/stain_normalization/callbacks/tiles_export.py @@ -1,8 +1,9 @@ from pathlib import Path + +import torch from lightning import Callback, LightningModule, Trainer -from PIL import Image from omegaconf import DictConfig -import torch +from PIL import Image class TilesExport(Callback): diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py index c956a65..5fb8521 100644 --- a/stain_normalization/data/data_module.py +++ b/stain_normalization/data/data_module.py @@ -1,14 +1,14 @@ -from typing import Any from collections.abc import Iterable -from torch import Tensor +from typing import Any from hydra.utils import instantiate from lightning import LightningDataModule from omegaconf import DictConfig +from torch import Tensor from torch.utils.data import DataLoader -from stain_normalization.typing import Input from stain_normalization.data.utils import collate_fn +from stain_normalization.typing import Input class DataModule(LightningDataModule): diff --git a/stain_normalization/data/datasets/__init__.py b/stain_normalization/data/datasets/__init__.py index 7047900..a767f70 100644 --- a/stain_normalization/data/datasets/__init__.py +++ b/stain_normalization/data/datasets/__init__.py @@ -1,5 +1,6 @@ -from stain_normalization.data.datasets.train_dataset import TrainDataset from stain_normalization.data.datasets.predict_dataset import PredictDataset from stain_normalization.data.datasets.test_dataset import TestDataset +from stain_normalization.data.datasets.train_dataset import TrainDataset + -__all__ = ["TrainDataset", "PredictDataset", "TestDataset"] +__all__ = ["PredictDataset", "TestDataset", "TrainDataset"] diff --git a/stain_normalization/data/datasets/predict_dataset.py b/stain_normalization/data/datasets/predict_dataset.py index 2e06f88..1871f94 100644 --- a/stain_normalization/data/datasets/predict_dataset.py +++ b/stain_normalization/data/datasets/predict_dataset.py @@ -1,12 +1,14 @@ from collections.abc import Iterable -import numpy as np + import pandas as pd from albumentations import Transform3D from albumentations.pytorch import ToTensorV2 from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset + from stain_normalization.typing import PredictSample + class PredictDataset(MetaTiledSlides[PredictSample]): def __init__( self, diff --git a/stain_normalization/data/datasets/test_dataset.py b/stain_normalization/data/datasets/test_dataset.py index 95363d4..4779d06 100644 --- a/stain_normalization/data/datasets/test_dataset.py +++ b/stain_normalization/data/datasets/test_dataset.py @@ -1,13 +1,13 @@ from collections.abc import Iterable -import numpy as np import pandas as pd from albumentations import Transform3D from albumentations.pytorch import ToTensorV2 from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset -from stain_normalization.typing import PredictSample, Sample +from stain_normalization.typing import PredictSample + class TestDataset(MetaTiledSlides[PredictSample]): def __init__( diff --git a/stain_normalization/data/datasets/train_dataset.py b/stain_normalization/data/datasets/train_dataset.py index 45187d2..d64e26f 100644 --- a/stain_normalization/data/datasets/train_dataset.py +++ b/stain_normalization/data/datasets/train_dataset.py @@ -1,6 +1,5 @@ from collections.abc import Iterable -import numpy as np import pandas as pd from albumentations import Transform3D from albumentations.pytorch import ToTensorV2 diff --git a/stain_normalization/data/modification/__init__.py b/stain_normalization/data/modification/__init__.py index b817f7b..a43111a 100644 --- a/stain_normalization/data/modification/__init__.py +++ b/stain_normalization/data/modification/__init__.py @@ -1,7 +1,12 @@ +from stain_normalization.data.transformation.combiend_modification import ( + CombinedModifications, +) +from stain_normalization.data.transformation.exposure_adjustment import ( + ExposureAdjustment, +) from stain_normalization.data.transformation.hed_factor import HEDFactor -from stain_normalization.data.transformation.exposure_adjustment import ExposureAdjustment from stain_normalization.data.transformation.hvs_modification import HVSModification -from stain_normalization.data.transformation.combiend_modification import CombinedModifications -__all__ = ["HEDFactor", "ExposureAdjustment", "HVSModification", "CombinedModifications"] + +__all__ = ["CombinedModifications", "ExposureAdjustment", "HEDFactor", "HVSModification"] diff --git a/stain_normalization/data/modification/combiend_modification.py b/stain_normalization/data/modification/combiend_modification.py index 610ebcb..773d804 100644 --- a/stain_normalization/data/modification/combiend_modification.py +++ b/stain_normalization/data/modification/combiend_modification.py @@ -1,7 +1,7 @@ import numpy as np from albumentations import ImageOnlyTransform from skimage import exposure -from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed +from skimage.color import combine_stains, hed_from_rgb, rgb_from_hed, separate_stains class CombinedModifications(ImageOnlyTransform): diff --git a/stain_normalization/data/modification/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py index fe25768..bd0cc1a 100644 --- a/stain_normalization/data/modification/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -1,6 +1,5 @@ import numpy as np from albumentations import ImageOnlyTransform -from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed class ExposureAdjustment(ImageOnlyTransform): diff --git a/stain_normalization/data/modification/hed_factor.py b/stain_normalization/data/modification/hed_factor.py index 80af22d..6fe8c40 100644 --- a/stain_normalization/data/modification/hed_factor.py +++ b/stain_normalization/data/modification/hed_factor.py @@ -1,6 +1,7 @@ import numpy as np from albumentations import ImageOnlyTransform -from skimage.color import separate_stains, combine_stains, hed_from_rgb, rgb_from_hed +from skimage.color import combine_stains, hed_from_rgb, rgb_from_hed, separate_stains + class HEDFactor(ImageOnlyTransform): def __init__(self, diff --git a/stain_normalization/data/modification/hvs_modification.py b/stain_normalization/data/modification/hvs_modification.py index 21e36d5..71f2138 100644 --- a/stain_normalization/data/modification/hvs_modification.py +++ b/stain_normalization/data/modification/hvs_modification.py @@ -2,7 +2,7 @@ import numpy as np from albumentations import ImageOnlyTransform -from skimage.color import rgb2hsv, hsv2rgb +from skimage.color import hsv2rgb, rgb2hsv class HVSModification(ImageOnlyTransform): diff --git a/stain_normalization/data/utils/collate_fn.py b/stain_normalization/data/utils/collate_fn.py index 667897e..3455e79 100644 --- a/stain_normalization/data/utils/collate_fn.py +++ b/stain_normalization/data/utils/collate_fn.py @@ -1,6 +1,8 @@ from typing import Any + import torch from torch import Tensor + def collate_fn(batch: list[tuple[Tensor, Any]]) -> tuple[Tensor, list[Any]]: return torch.stack([x[0] for x in batch]), [x[1] for x in batch] diff --git a/stain_normalization/modeling/__init__.py b/stain_normalization/modeling/__init__.py index 2c4be67..e199cc5 100644 --- a/stain_normalization/modeling/__init__.py +++ b/stain_normalization/modeling/__init__.py @@ -1,3 +1,5 @@ from .l1ssim_loss import L1SSIMLoss from .unet import UNet + + __all__ = ["L1SSIMLoss", "UNet"] \ No newline at end of file diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 25e2e75..263ffaf 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -1,8 +1,9 @@ -import torch.nn.functional as F +from math import exp + import torch import torch.nn as nn +import torch.nn.functional as F from torch.autograd import Variable -from math import exp class L1SSIMLoss(nn.Module): diff --git a/stain_normalization/modeling/unet.py b/stain_normalization/modeling/unet.py index 485bc9b..f83735d 100644 --- a/stain_normalization/modeling/unet.py +++ b/stain_normalization/modeling/unet.py @@ -1,5 +1,4 @@ -""" -Model created using segmentation_models_pytorch library: +"""Model created using segmentation_models_pytorch library: # Adapted U-Net implementation based on https://github.com/milesial/Pytorch-UNet Ronneberger, O., Fischer, P., & Brox, T. (2015). @@ -12,6 +11,7 @@ import torch.nn as nn import torch.nn.functional as F + class DoubleConv(nn.Module): """(convolution => [BN] => ReLU) * 2""" diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index 7809a03..f4a0b05 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -1,13 +1,15 @@ +from typing import Any + from lightning import LightningModule -from torch import Tensor, nn, stack +from torch import Tensor, stack +from torch.optim import Adam from torch.optim.optimizer import Optimizer +from torchmetrics import MetricCollection +from torchmetrics.image import StructuralSimilarityIndexMeasure + from stain_normalization.modeling import L1SSIMLoss, UNet from stain_normalization.typing import Input, Outputs -from torch.optim import Adam -from torch.optim.optimizer import Optimizer -from torchmetrics.image import StructuralSimilarityIndexMeasure -from torchmetrics import MetricCollection -from typing import Any + class StainNormalizationModel(LightningModule): def __init__(self) -> None: diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py index 15088b6..c507266 100644 --- a/stain_normalization/typing.py +++ b/stain_normalization/typing.py @@ -1,8 +1,9 @@ -from typing import TypeAlias, TypedDict, Dict, Any +from typing import Any, TypeAlias from torch import Tensor -PredictSample: TypeAlias = tuple[Tensor, Dict[str, Any]] + +PredictSample: TypeAlias = tuple[Tensor, dict[str, Any]] Sample: TypeAlias = tuple[Tensor, Tensor] Input: TypeAlias = Sample From 082e5e13b07193b1faaea75374baab458df0d6cc Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 16 May 2025 14:05:33 +0000 Subject: [PATCH 55/79] chore: formating fix --- preprocessing/mask_generator.py | 51 ++++++++++--- preprocessing/tiler.py | 73 ++++++++++++++----- stain_normalization/callbacks/__init__.py | 3 +- .../callbacks/analysis_export.py | 15 ++-- stain_normalization/callbacks/save_wsi.py | 13 ++-- stain_normalization/callbacks/tiles_export.py | 24 +++--- stain_normalization/data/data_module.py | 10 +-- .../data/datasets/predict_dataset.py | 28 +++---- .../data/datasets/test_dataset.py | 23 +++--- .../data/datasets/train_dataset.py | 10 +-- .../data/modification/__init__.py | 8 +- .../modification/combiend_modification.py | 18 ++++- .../data/modification/exposure_adjustment.py | 11 ++- .../data/modification/hed_factor.py | 23 ++++-- .../data/modification/hvs_modification.py | 7 +- stain_normalization/modeling/__init__.py | 6 +- stain_normalization/modeling/l1ssim_loss.py | 67 ++++++++++------- stain_normalization/modeling/unet.py | 48 ++++++------ .../stain_normalization_model.py | 10 +-- stain_normalization/typing.py | 2 - 20 files changed, 280 insertions(+), 170 deletions(-) diff --git a/preprocessing/mask_generator.py b/preprocessing/mask_generator.py index 45cd285..0c0bc98 100644 --- a/preprocessing/mask_generator.py +++ b/preprocessing/mask_generator.py @@ -24,10 +24,8 @@ def process_slide(slide_path: Path) -> None: # extract proper spatial resulution based on desired level using OpenSlide with OpenSlide(slide_path) as slide: downsample = slide.level_downsamples[LEVEL] - xres = 1000 / \ - (float(slide.properties[PROPERTY_NAME_MPP_X]) * downsample) - yres = 1000 / \ - (float(slide.properties[PROPERTY_NAME_MPP_Y]) * downsample) + xres = 1000 / (float(slide.properties[PROPERTY_NAME_MPP_X]) * downsample) + yres = 1000 / (float(slide.properties[PROPERTY_NAME_MPP_Y]) * downsample) slide = pyvips.Image.new_from_file(slide_path, level=LEVEL) mask = tissue_mask(slide) @@ -37,10 +35,45 @@ def process_slide(slide_path: Path) -> None: BROKEN_SLIDES = { - 'P-2016_3829-04-1.mrxs', 'P-2016_3732-06-1.mrxs', 'P-2016_3732-03-1.mrxs', 'P-2016_3760-06-1.mrxs', 'P-2016_3629-13-1.mrxs', 'P-2016_3926-03-1.mrxs', - 'P-2016_3852-02-1.mrxs', 'P-2016_3988-07-1.mrxs', 'P-2016_3852-01-1.mrxs', - 'P-2016_3851-02-1.mrxs', 'P-2016_3629-12-1.mrxs', 'P-2016_3667-10-0.mrxs', 'P-2016_3606-04-1.mrxs', 'P-2016_3597-10-1.mrxs', 'P-2016_3988-10-1.mrxs', 'P-2016_3829-01-1.mrxs', 'P-2016_3926-02-1.mrxs', 'P-2019_3025-03-1.mrxs', - 'P-2016_3760-04-1.mrxs', 'P-2016_3732-04-1.mrxs', 'P-2016_3667-09-1.mrxs', 'P-2019_3292-06-1.mrxs', 'P-2016_3988-02-1.mrxs', 'P-2016_3667-11-0.mrxs', 'P-2016_3606-05-1.mrxs', 'P-2016_3851-09-1.mrxs', 'P-2016_3627-09-1.mrxs', 'P-2016_3606-03-1.mrxs', 'P-2016_3627-10-1.mrxs', 'P-2016_3852-03-1.mrxs', 'P-2016_3851-07-1.mrxs', 'P-2016_3829-03-1.mrxs', 'P-2016_3627-06-1.mrxs', 'P-2016_3597-09-1.mrxs', 'P-2016_3926-01-1.mrxs', 'P-2016_3629-11-1.mrxs', 'P-2016_3760-03-1.mrxs'} + "P-2016_3829-04-1.mrxs", + "P-2016_3732-06-1.mrxs", + "P-2016_3732-03-1.mrxs", + "P-2016_3760-06-1.mrxs", + "P-2016_3629-13-1.mrxs", + "P-2016_3926-03-1.mrxs", + "P-2016_3852-02-1.mrxs", + "P-2016_3988-07-1.mrxs", + "P-2016_3852-01-1.mrxs", + "P-2016_3851-02-1.mrxs", + "P-2016_3629-12-1.mrxs", + "P-2016_3667-10-0.mrxs", + "P-2016_3606-04-1.mrxs", + "P-2016_3597-10-1.mrxs", + "P-2016_3988-10-1.mrxs", + "P-2016_3829-01-1.mrxs", + "P-2016_3926-02-1.mrxs", + "P-2019_3025-03-1.mrxs", + "P-2016_3760-04-1.mrxs", + "P-2016_3732-04-1.mrxs", + "P-2016_3667-09-1.mrxs", + "P-2019_3292-06-1.mrxs", + "P-2016_3988-02-1.mrxs", + "P-2016_3667-11-0.mrxs", + "P-2016_3606-05-1.mrxs", + "P-2016_3851-09-1.mrxs", + "P-2016_3627-09-1.mrxs", + "P-2016_3606-03-1.mrxs", + "P-2016_3627-10-1.mrxs", + "P-2016_3852-03-1.mrxs", + "P-2016_3851-07-1.mrxs", + "P-2016_3829-03-1.mrxs", + "P-2016_3627-06-1.mrxs", + "P-2016_3597-09-1.mrxs", + "P-2016_3926-01-1.mrxs", + "P-2016_3629-11-1.mrxs", + "P-2016_3760-03-1.mrxs", +} + def main() -> None: folders = [ @@ -49,7 +82,7 @@ def main() -> None: # "Prospective negative cases", #DONE # "Prospective test cases", # DONE # "Prospective tumor cases" # DONE - ] + ] for folder in folders: slides = [] diff --git a/preprocessing/tiler.py b/preprocessing/tiler.py index 5ffb3a4..87f7062 100644 --- a/preprocessing/tiler.py +++ b/preprocessing/tiler.py @@ -56,20 +56,56 @@ def handler(slide_path: Path) -> TiledSlideMetadata: return slide, tiles + BROKEN_SLIDES = { - 'P-2016_3829-04-1.mrxs', 'P-2016_3732-06-1.mrxs', 'P-2016_3732-03-1.mrxs', 'P-2016_3760-06-1.mrxs', 'P-2016_3629-13-1.mrxs', 'P-2016_3926-03-1.mrxs', - 'P-2016_3852-02-1.mrxs', 'P-2016_3988-07-1.mrxs', 'P-2016_3852-01-1.mrxs', - 'P-2016_3851-02-1.mrxs', 'P-2016_3629-12-1.mrxs', 'P-2016_3667-10-0.mrxs', 'P-2016_3606-04-1.mrxs', 'P-2016_3597-10-1.mrxs', 'P-2016_3988-10-1.mrxs', 'P-2016_3829-01-1.mrxs', 'P-2016_3926-02-1.mrxs', 'P-2019_3025-03-1.mrxs', - 'P-2016_3760-04-1.mrxs', 'P-2016_3732-04-1.mrxs', 'P-2016_3667-09-1.mrxs', 'P-2019_3292-06-1.mrxs', 'P-2016_3988-02-1.mrxs', 'P-2016_3667-11-0.mrxs', 'P-2016_3606-05-1.mrxs', 'P-2016_3851-09-1.mrxs', 'P-2016_3627-09-1.mrxs', 'P-2016_3606-03-1.mrxs', 'P-2016_3627-10-1.mrxs', 'P-2016_3852-03-1.mrxs', 'P-2016_3851-07-1.mrxs', 'P-2016_3829-03-1.mrxs', 'P-2016_3627-06-1.mrxs', 'P-2016_3597-09-1.mrxs', 'P-2016_3926-01-1.mrxs', 'P-2016_3629-11-1.mrxs', 'P-2016_3760-03-1.mrxs'} + "P-2016_3829-04-1.mrxs", + "P-2016_3732-06-1.mrxs", + "P-2016_3732-03-1.mrxs", + "P-2016_3760-06-1.mrxs", + "P-2016_3629-13-1.mrxs", + "P-2016_3926-03-1.mrxs", + "P-2016_3852-02-1.mrxs", + "P-2016_3988-07-1.mrxs", + "P-2016_3852-01-1.mrxs", + "P-2016_3851-02-1.mrxs", + "P-2016_3629-12-1.mrxs", + "P-2016_3667-10-0.mrxs", + "P-2016_3606-04-1.mrxs", + "P-2016_3597-10-1.mrxs", + "P-2016_3988-10-1.mrxs", + "P-2016_3829-01-1.mrxs", + "P-2016_3926-02-1.mrxs", + "P-2019_3025-03-1.mrxs", + "P-2016_3760-04-1.mrxs", + "P-2016_3732-04-1.mrxs", + "P-2016_3667-09-1.mrxs", + "P-2019_3292-06-1.mrxs", + "P-2016_3988-02-1.mrxs", + "P-2016_3667-11-0.mrxs", + "P-2016_3606-05-1.mrxs", + "P-2016_3851-09-1.mrxs", + "P-2016_3627-09-1.mrxs", + "P-2016_3606-03-1.mrxs", + "P-2016_3627-10-1.mrxs", + "P-2016_3852-03-1.mrxs", + "P-2016_3851-07-1.mrxs", + "P-2016_3829-03-1.mrxs", + "P-2016_3627-06-1.mrxs", + "P-2016_3597-09-1.mrxs", + "P-2016_3926-01-1.mrxs", + "P-2016_3629-11-1.mrxs", + "P-2016_3760-03-1.mrxs", +} + def main() -> None: folders = [ "archive tumor cases", - "archive negative cases", - "Prospective negative cases", - "Prospective test cases", - "Prospective tumor cases" - ] + "archive negative cases", + "Prospective negative cases", + "Prospective test cases", + "Prospective tumor cases", + ] slides = [] for folder in folders: @@ -78,18 +114,13 @@ def main() -> None: continue slides.append(slide) - slides, test_slides = train_test_split( - slides, test_size=0.2 - ) + slides, test_slides = train_test_split(slides, test_size=0.2) train_slides, val_slides = train_test_split(slides, test_size=0.1) - train_slides_df, train_tiles_df = tiling( - slides=train_slides, handler=handler) - val_slides_df, val_tiles_df = tiling( - slides=list(val_slides), handler=handler) - test_slides_df, test_tiles_df = tiling( - slides=list(test_slides), handler=handler) - + train_slides_df, train_tiles_df = tiling(slides=train_slides, handler=handler) + val_slides_df, val_tiles_df = tiling(slides=list(val_slides), handler=handler) + test_slides_df, test_tiles_df = tiling(slides=list(test_slides), handler=handler) + train_slides_df.to_csv("./data/datasets/train_slides.csv", index=False) train_tiles_df.to_csv("./data/datasets/train_tiles.csv", index=False) @@ -107,7 +138,9 @@ def main() -> None: dataset_name="Stain Normalization - train", ) save_mlflow_dataset( - slides=val_slides_df, tiles=val_tiles_df, dataset_name="Stain Normalization - val" + slides=val_slides_df, + tiles=val_tiles_df, + dataset_name="Stain Normalization - val", ) save_mlflow_dataset( slides=test_slides_df, diff --git a/stain_normalization/callbacks/__init__.py b/stain_normalization/callbacks/__init__.py index 344b24c..86a8ce0 100644 --- a/stain_normalization/callbacks/__init__.py +++ b/stain_normalization/callbacks/__init__.py @@ -3,5 +3,4 @@ from stain_normalization.callbacks.tiles_export import TilesExport -__all__ = ["AnalysisExport", "SaveWSI", "TileExport"] - +__all__ = ["AnalysisExport", "SaveWSI", "TilesExport"] diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index bd48d21..3bfbf01 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -40,13 +40,14 @@ def _compare_vectors(self, vec1: np.ndarray, vec2: np.ndarray) -> float: def _compute_ssim(self, img1: np.ndarray, img2: np.ndarray) -> float: return float(ssim(img1, img2, channel_axis=-1, data_range=255)) - def _compute_nmi(self, img: np.ndarray): # normalized median intensity + def _compute_nmi(self, img: np.ndarray): # normalized median intensity avg_rgb = img.mean(axis=2) median_val = np.median(avg_rgb) p95_val = np.percentile(avg_rgb, 95) nmi = median_val / p95_val if p95_val != 0 else 0 return nmi + def on_test_batch_end( self, trainer: Trainer, @@ -73,7 +74,6 @@ def on_test_batch_end( ssim_mod = self._compute_ssim(original_np, modified_np) ssim_pred = self._compute_ssim(original_np, predicted_np) - nmi_original = self.compute_nmi(original_np) nmi_modified = self.compute_nmi(modified_np) nmi_predicted = self.compute_nmi(predicted_np) @@ -92,15 +92,20 @@ def on_test_batch_end( for name, vec, nmi in zip( ["original", "modified", "predicted"], [vec_original, vec_modified, vec_predicted], - [nmi_original, nmi_modified, nmi_predicted], strict=False + [nmi_original, nmi_modified, nmi_predicted], + strict=False, ): vectors = vec.flatten() for j, val in enumerate(vectors): raw_row[f"{name}_vec_{j}"] = val raw_row[f"{name}_nmi"] = nmi - self.df_diff = pd.concat([self.df_diff, pd.DataFrame([diff_row])], ignore_index=True) - self.df_raw = pd.concat([self.df_raw, pd.DataFrame([raw_row])], ignore_index=True) + self.df_diff = pd.concat( + [self.df_diff, pd.DataFrame([diff_row])], ignore_index=True + ) + self.df_raw = pd.concat( + [self.df_raw, pd.DataFrame([raw_row])], ignore_index=True + ) def on_predict_end( self, diff --git a/stain_normalization/callbacks/save_wsi.py b/stain_normalization/callbacks/save_wsi.py index 7bec981..b74ba83 100644 --- a/stain_normalization/callbacks/save_wsi.py +++ b/stain_normalization/callbacks/save_wsi.py @@ -7,7 +7,9 @@ class SaveWSI(Callback): - def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> None: + def __init__( + self, output_dir: str | Path, normalization_config: DictConfig + ) -> None: super().__init__() self.output_root = Path(output_dir) self.mean = torch.tensor(normalization_config.mean).view(3, 1, 1) @@ -28,15 +30,14 @@ def on_predict_batch_end( batch_idx: int, dataloader_idx: int = 0, ) -> None: - for b in range(len(outputs)): predicted_image = outputs[b] metadata = batch[1][b] - + slide_name = metadata["slide_name"] level = metadata["level"] original_image = Image.fromarray(metadata["original_image"].astype("uint8")) - filename = f'{metadata["xy"]}.png' + filename = f"{metadata['xy']}.png" base_folder = self.output_root / str(slide_name) / str(level) predicted_folder = base_folder / "predicted" @@ -49,5 +50,7 @@ def on_predict_batch_end( predicted_image = self.denormalize(predicted_image).clamp(0, 1) predicted_image = (predicted_image * 255).byte() - predicted_image = Image.fromarray(predicted_image.permute(1, 2, 0).cpu().numpy()) + predicted_image = Image.fromarray( + predicted_image.permute(1, 2, 0).cpu().numpy() + ) predicted_image.save(predicted_folder / filename) diff --git a/stain_normalization/callbacks/tiles_export.py b/stain_normalization/callbacks/tiles_export.py index 724d92e..0c44f07 100644 --- a/stain_normalization/callbacks/tiles_export.py +++ b/stain_normalization/callbacks/tiles_export.py @@ -7,7 +7,9 @@ class TilesExport(Callback): - def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> None: + def __init__( + self, output_dir: str | Path, normalization_config: DictConfig + ) -> None: super().__init__() self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) @@ -15,19 +17,19 @@ def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> normalization = normalization_config self.mean = torch.tensor(normalization.mean).view(3, 1, 1) self.std = torch.tensor(normalization.std).view(3, 1, 1) - + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: device = tensor.device std = self.std.to(device) mean = self.mean.to(device) return (tensor * std) + mean - + def tensor_to_image(self, tensor: torch.Tensor) -> Image.Image: - tensor = self.denormalize(tensor) - tensor = tensor.clamp(0, 1) + tensor = self.denormalize(tensor) + tensor = tensor.clamp(0, 1) tensor = (tensor * 255).byte() - return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) - + return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) + def on_test_batch_end( self, trainer: Trainer, @@ -62,9 +64,13 @@ def _save_images(self, outputs, batch, is_predict: bool) -> None: predicted_image.save(self.output_dir / f"{name}.png") if not is_predict: - original_image = Image.fromarray(data[b]["original_image"].astype("uint8")) + original_image = Image.fromarray( + data[b]["original_image"].astype("uint8") + ) original_image.save(self.output_dir / f"{name}_original.png") if "modified_image" in data[b]: - modified_image = Image.fromarray((data[b]["modified_image"] * 255).astype("uint8")) + modified_image = Image.fromarray( + (data[b]["modified_image"] * 255).astype("uint8") + ) modified_image.save(self.output_dir / f"{name}_modified.png") diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py index 5fb8521..eb1f7ae 100644 --- a/stain_normalization/data/data_module.py +++ b/stain_normalization/data/data_module.py @@ -52,16 +52,16 @@ def val_dataloader(self) -> Iterable[Input]: def test_dataloader(self) -> Iterable[Input]: return DataLoader( - self.test, - batch_size=self.batch_size, + self.test, + batch_size=self.batch_size, num_workers=self.num_workers, collate_fn=collate_fn, ) def predict_dataloader(self) -> Iterable[tuple[Tensor, list[dict[str, Any]]]]: return DataLoader( - self.predict, - batch_size=self.batch_size, + self.predict, + batch_size=self.batch_size, num_workers=self.num_workers, collate_fn=collate_fn, - ) \ No newline at end of file + ) diff --git a/stain_normalization/data/datasets/predict_dataset.py b/stain_normalization/data/datasets/predict_dataset.py index 1871f94..ebd85fb 100644 --- a/stain_normalization/data/datasets/predict_dataset.py +++ b/stain_normalization/data/datasets/predict_dataset.py @@ -13,7 +13,7 @@ class PredictDataset(MetaTiledSlides[PredictSample]): def __init__( self, uris: Iterable[str], - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: self.normalize = normalize super().__init__(uris=uris) @@ -34,7 +34,7 @@ def __init__( self, slide_metadata: pd.Series, tiles: pd.DataFrame, - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: super().__init__() self.slide_tiles = OpenSlideTilesDataset( @@ -44,7 +44,7 @@ def __init__( tile_extent_y=slide_metadata.tile_extent_y, tiles=tiles, ) - + self.normalize = normalize self.to_tensor = ToTensorV2() @@ -58,19 +58,19 @@ def __getitem__(self, idx: int) -> PredictSample: x = self.slide_tiles.tiles.iloc[idx]["x"] y = self.slide_tiles.tiles.iloc[idx]["y"] - input_image = input_image_255 / 255.0 + input_image = input_image_255 / 255.0 if self.normalize: input_image = self.normalize(image=input_image)["image"] - - input_image = self.to_tensor(image=input_image)["image"] - - return input_image, {"original_image": input_image_255, - "modified_image": None, - "slide_name": slide_name, - "level":level , - "index": idx, - "xy":f"{x}_{y}", - "name":f"{slide_name}-{x}-{y}"} + input_image = self.to_tensor(image=input_image)["image"] + return input_image, { + "original_image": input_image_255, + "modified_image": None, + "slide_name": slide_name, + "level": level, + "index": idx, + "xy": f"{x}_{y}", + "name": f"{slide_name}-{x}-{y}", + } diff --git a/stain_normalization/data/datasets/test_dataset.py b/stain_normalization/data/datasets/test_dataset.py index 4779d06..151b373 100644 --- a/stain_normalization/data/datasets/test_dataset.py +++ b/stain_normalization/data/datasets/test_dataset.py @@ -14,7 +14,7 @@ def __init__( self, uris: Iterable[str], modify: Transform3D, - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: self.modify = modify self.normalize = normalize @@ -38,7 +38,7 @@ def __init__( slide_metadata: pd.Series, tiles: pd.DataFrame, modify: Transform3D, - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: super().__init__() self.slide_tiles = OpenSlideTilesDataset( @@ -61,7 +61,7 @@ def __getitem__(self, idx: int) -> PredictSample: # Create "wrong" image to use as input. Outputs image in float 0-1 modified_image_raw = self.modify(image=original_image_255)["image"] modified_image = modified_image_raw - original_image = original_image_255 / 255.0 + original_image = original_image_255 / 255.0 if self.normalize: original_image = self.normalize(image=original_image)["image"] @@ -69,12 +69,13 @@ def __getitem__(self, idx: int) -> PredictSample: original_image = self.to_tensor(image=original_image)["image"] modified_image = self.to_tensor(image=modified_image)["image"] - - - return (modified_image, - {"original_image_tensor":original_image, - "original_image": original_image_255, - "modified_image": modified_image_raw, - "index": idx} - ) + return ( + modified_image, + { + "original_image_tensor": original_image, + "original_image": original_image_255, + "modified_image": modified_image_raw, + "index": idx, + }, + ) diff --git a/stain_normalization/data/datasets/train_dataset.py b/stain_normalization/data/datasets/train_dataset.py index d64e26f..2a0fab7 100644 --- a/stain_normalization/data/datasets/train_dataset.py +++ b/stain_normalization/data/datasets/train_dataset.py @@ -14,7 +14,7 @@ def __init__( self, uris: Iterable[str], modify: Transform3D, - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: self.modify = modify self.normalize = normalize @@ -38,7 +38,7 @@ def __init__( slide_metadata: pd.Series, tiles: pd.DataFrame, modify: Transform3D, - normalize: Transform3D | None = None, + normalize: Transform3D | None = None, ) -> None: super().__init__() self.slide_tiles = OpenSlideTilesDataset( @@ -60,7 +60,7 @@ def __getitem__(self, idx: int) -> Sample: # Create "wrong" image to use as input. Outputs image in float 0-1 modified_image = self.modify(image=original_image)["image"] - original_image = original_image / 255.0 + original_image = original_image / 255.0 if self.normalize: original_image = self.normalize(image=original_image)["image"] @@ -68,7 +68,5 @@ def __getitem__(self, idx: int) -> Sample: original_image = self.to_tensor(image=original_image)["image"] modified_image = self.to_tensor(image=modified_image)["image"] - - return modified_image, original_image - + return modified_image, original_image diff --git a/stain_normalization/data/modification/__init__.py b/stain_normalization/data/modification/__init__.py index a43111a..1d8962b 100644 --- a/stain_normalization/data/modification/__init__.py +++ b/stain_normalization/data/modification/__init__.py @@ -8,5 +8,9 @@ from stain_normalization.data.transformation.hvs_modification import HVSModification -__all__ = ["CombinedModifications", "ExposureAdjustment", "HEDFactor", "HVSModification"] - +__all__ = [ + "CombinedModifications", + "ExposureAdjustment", + "HEDFactor", + "HVSModification", +] diff --git a/stain_normalization/data/modification/combiend_modification.py b/stain_normalization/data/modification/combiend_modification.py index 773d804..18dbaf3 100644 --- a/stain_normalization/data/modification/combiend_modification.py +++ b/stain_normalization/data/modification/combiend_modification.py @@ -5,7 +5,13 @@ class CombinedModifications(ImageOnlyTransform): - def __init__(self, intensity_range=(0.4, 1.5), brightness_range=(-0.4, 0.4), always_apply=True, p=1.0): + def __init__( + self, + intensity_range=(0.4, 1.5), + brightness_range=(-0.4, 0.4), + always_apply=True, + p=1.0, + ): super().__init__(always_apply, p) self.intensity_range = intensity_range self.brightness_range = brightness_range @@ -19,9 +25,13 @@ def modify_channel(channel, intensity_range, brightness_range): return np.clip(channel, 0, 1) hed_image = separate_stains(hed_img, hed_from_rgb) - h = modify_channel(hed_image[:, :, 0], self.intensity_range, self.brightness_range) - e = modify_channel(hed_image[:, :, 1], self.intensity_range, self.brightness_range) + h = modify_channel( + hed_image[:, :, 0], self.intensity_range, self.brightness_range + ) + e = modify_channel( + hed_image[:, :, 1], self.intensity_range, self.brightness_range + ) d = hed_image[:, :, 2] # Skip modification for D channel modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) - return modified_rgb \ No newline at end of file + return modified_rgb diff --git a/stain_normalization/data/modification/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py index bd0cc1a..6e0899e 100644 --- a/stain_normalization/data/modification/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -3,13 +3,18 @@ class ExposureAdjustment(ImageOnlyTransform): - def __init__(self, brightness_range: tuple[float, float] = (0.8, 1.2), always_apply: bool = True, p: float = 1): + def __init__( + self, + brightness_range: tuple[float, float] = (0.8, 1.2), + always_apply: bool = True, + p: float = 1, + ): super().__init__(always_apply, p) self.brightness_range = brightness_range def apply(self, img, **params): brightness_factor = np.random.uniform(*self.brightness_range) img = img.astype(np.float32) - img = np.clip(img*brightness_factor, 0.0, 1.0) - + img = np.clip(img * brightness_factor, 0.0, 1.0) + return img diff --git a/stain_normalization/data/modification/hed_factor.py b/stain_normalization/data/modification/hed_factor.py index 6fe8c40..c8e90b2 100644 --- a/stain_normalization/data/modification/hed_factor.py +++ b/stain_normalization/data/modification/hed_factor.py @@ -4,25 +4,32 @@ class HEDFactor(ImageOnlyTransform): - def __init__(self, - h_range: tuple[float, float] = (0.8, 1.2), - e_range: tuple[float, float] = (0.8, 1.2), - always_apply: bool = True, - p: float = 1.0): + def __init__( + self, + h_range: tuple[float, float] = (0.8, 1.2), + e_range: tuple[float, float] = (0.8, 1.2), + always_apply: bool = True, + p: float = 1.0, + ): super().__init__(always_apply, p) self.h_range = h_range self.e_range = e_range - def apply(self, img, **params): + def apply(self, img, **params): h_factor = np.random.uniform(*self.h_range) e_factor = np.random.uniform(*self.e_range) return self.multiply_channels(img, e_factor, h_factor) - def multiply_channels(self, image, e_factor=1.1, h_factor=1.1,): + def multiply_channels( + self, + image, + e_factor=1.1, + h_factor=1.1, + ): hed_image = separate_stains(image, hed_from_rgb) h = hed_image[:, :, 0] * h_factor e = hed_image[:, :, 1] * e_factor - d = hed_image[:, :, 2] + d = hed_image[:, :, 2] modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) return modified_rgb diff --git a/stain_normalization/data/modification/hvs_modification.py b/stain_normalization/data/modification/hvs_modification.py index 71f2138..8c47003 100644 --- a/stain_normalization/data/modification/hvs_modification.py +++ b/stain_normalization/data/modification/hvs_modification.py @@ -1,5 +1,3 @@ - - import numpy as np from albumentations import ImageOnlyTransform from skimage.color import hsv2rgb, rgb2hsv @@ -12,9 +10,8 @@ def __init__( saturation_range: tuple[float, float] = (0.8, 1.5), value_range: tuple[float, float] = (0.8, 1.3), always_apply: bool = True, - p: float = 1.0 + p: float = 1.0, ): - super().__init__(always_apply, p) self.hue_shift_range = hue_shift_range self.saturation_range = saturation_range @@ -32,4 +29,4 @@ def apply(self, img, **params): modified_rgb = hsv2rgb(hsv_image) - return modified_rgb \ No newline at end of file + return modified_rgb diff --git a/stain_normalization/modeling/__init__.py b/stain_normalization/modeling/__init__.py index e199cc5..7a8746c 100644 --- a/stain_normalization/modeling/__init__.py +++ b/stain_normalization/modeling/__init__.py @@ -1,5 +1,5 @@ -from .l1ssim_loss import L1SSIMLoss -from .unet import UNet +from stain_normalization.modeling.l1ssim_loss import L1SSIMLoss +from stain_normalization.modeling.unet import UNet -__all__ = ["L1SSIMLoss", "UNet"] \ No newline at end of file +__all__ = ["L1SSIMLoss", "UNet"] diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 263ffaf..9cad241 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -6,22 +6,24 @@ from torch.autograd import Variable -class L1SSIMLoss(nn.Module): +class L1SSIMLoss(nn.Module): def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2): super().__init__() self.lambda_dssim = lambda_dssim self.lambda_gdl = lambda_gdl def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: - Ll1 = F.l1_loss(image, target_image, reduction='mean') - ssim_loss = 1.0 - ssim(image, target_image) + l1 = F.l1_loss(image, target_image, reduction="mean") + ssim_loss = 1.0 - ssim(image, target_image) gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges - total_loss = (1.0 - self.lambda_dssim) * Ll1 + \ - self.lambda_dssim * ssim_loss + \ - self.lambda_gdl * gdl_loss - + total_loss = ( + (1.0 - self.lambda_dssim) * l1 + + self.lambda_dssim * ssim_loss + + self.lambda_gdl * gdl_loss + ) + return total_loss @@ -34,24 +36,28 @@ def gradient(x): image_dx, image_dy = gradient(image) target_dx, target_dy = gradient(target_image) - loss_x = F.l1_loss(image_dx, target_dx, reduction='mean') - loss_y = F.l1_loss(image_dy, target_dy, reduction='mean') + loss_x = F.l1_loss(image_dx, target_dx, reduction="mean") + loss_y = F.l1_loss(image_dy, target_dy, reduction="mean") return loss_x + loss_y def gaussian(window_size, sigma): - gauss = torch.Tensor([exp(-(x - window_size // 2) ** 2 / - float(2 * sigma ** 2)) for x in range(window_size)]) + gauss = torch.Tensor( + [ + exp(-((x - window_size // 2) ** 2) / float(2 * sigma**2)) + for x in range(window_size) + ] + ) return gauss / gauss.sum() def create_window(window_size, channel): - _1D_window = gaussian(window_size, 1.5).unsqueeze(1) - _2D_window = _1D_window.mm( - _1D_window.t()).float().unsqueeze(0).unsqueeze(0) - window = Variable(_2D_window.expand( - channel, 1, window_size, window_size).contiguous()) + _1d_window = gaussian(window_size, 1.5).unsqueeze(1) + _2d_window = _1d_window.mm(_1d_window.t()).float().unsqueeze(0).unsqueeze(0) + window = Variable( + _2d_window.expand(channel, 1, window_size, window_size).contiguous() + ) return window @@ -74,18 +80,23 @@ def _ssim(img1, img2, window, window_size, channel, size_average=True): mu2_sq = mu2.pow(2) mu1_mu2 = mu1 * mu2 - sigma1_sq = F.conv2d(img1 * img1, window, - padding=window_size // 2, groups=channel) - mu1_sq - sigma2_sq = F.conv2d(img2 * img2, window, - padding=window_size // 2, groups=channel) - mu2_sq - sigma12 = F.conv2d(img1 * img2, window, - padding=window_size // 2, groups=channel) - mu1_mu2 - - C1 = 0.01 ** 2 - C2 = 0.03 ** 2 - - ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / \ - ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)) + sigma1_sq = ( + F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq + ) + sigma2_sq = ( + F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq + ) + sigma12 = ( + F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel) + - mu1_mu2 + ) + + c1 = 0.01**2 + c2 = 0.03**2 + + ssim_map = ((2 * mu1_mu2 + c1) * (2 * sigma12 + c2)) / ( + (mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2) + ) if size_average: return ssim_map.mean() diff --git a/stain_normalization/modeling/unet.py b/stain_normalization/modeling/unet.py index f83735d..a5f5d2b 100644 --- a/stain_normalization/modeling/unet.py +++ b/stain_normalization/modeling/unet.py @@ -1,9 +1,9 @@ -"""Model created using segmentation_models_pytorch library: -# Adapted U-Net implementation based on https://github.com/milesial/Pytorch-UNet +"""Model created using segmentation_models_pytorch library. -Ronneberger, O., Fischer, P., & Brox, T. (2015). -U-Net: Convolutional Networks for Biomedical Image Segmentation. -arXiv:1505.04597 [cs.CV]. +Adapted U-Net implementation based on https://github.com/milesial/Pytorch-UNet +Ronneberger, O., Fischer, P., & Brox, T. (2015). +U-Net: Convolutional Networks for Biomedical Image Segmentation. +arXiv:1505.04597 [cs.CV]. Retrieved from https://arxiv.org/abs/1505.04597. """ @@ -13,7 +13,7 @@ class DoubleConv(nn.Module): - """(convolution => [BN] => ReLU) * 2""" + """(convolution => [BN] => ReLU) * 2.""" def __init__(self, in_channels, out_channels, mid_channels=None): super().__init__() @@ -25,7 +25,7 @@ def __init__(self, in_channels, out_channels, mid_channels=None): nn.ReLU(inplace=True), nn.Conv2d(mid_channels, out_channels, kernel_size=3, padding=1, bias=False), nn.BatchNorm2d(out_channels), - nn.ReLU(inplace=True) + nn.ReLU(inplace=True), ) def forward(self, x): @@ -33,13 +33,12 @@ def forward(self, x): class Down(nn.Module): - """Downscaling with maxpool then double conv""" + """Downscaling with maxpool then double conv.""" def __init__(self, in_channels, out_channels): super().__init__() self.maxpool_conv = nn.Sequential( - nn.MaxPool2d(2), - DoubleConv(in_channels, out_channels) + nn.MaxPool2d(2), DoubleConv(in_channels, out_channels) ) def forward(self, x): @@ -47,27 +46,28 @@ def forward(self, x): class Up(nn.Module): - """Upscaling then double conv""" + """Upscaling then double conv.""" def __init__(self, in_channels, out_channels, bilinear=True): super().__init__() # if bilinear, use the normal convolutions to reduce the number of channels if bilinear: - self.up = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True) + self.up = nn.Upsample(scale_factor=2, mode="bilinear", align_corners=True) self.conv = DoubleConv(in_channels, out_channels, in_channels // 2) else: - self.up = nn.ConvTranspose2d(in_channels, in_channels // 2, kernel_size=2, stride=2) + self.up = nn.ConvTranspose2d( + in_channels, in_channels // 2, kernel_size=2, stride=2 + ) self.conv = DoubleConv(in_channels, out_channels) def forward(self, x1, x2): x1 = self.up(x1) # input is CHW - diffY = x2.size()[2] - x1.size()[2] - diffX = x2.size()[3] - x1.size()[3] + diffy = x2.size()[2] - x1.size()[2] + diffx = x2.size()[3] - x1.size()[3] - x1 = F.pad(x1, [diffX // 2, diffX - diffX // 2, - diffY // 2, diffY - diffY // 2]) + x1 = F.pad(x1, [diffx // 2, diffx - diffx // 2, diffy // 2, diffy - diffy // 2]) # if you have padding issues, see # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd @@ -77,7 +77,7 @@ def forward(self, x1, x2): class OutConv(nn.Module): def __init__(self, in_channels, out_channels): - super(OutConv, self).__init__() + super().__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=1) def forward(self, x): @@ -86,18 +86,18 @@ def forward(self, x): class UNet(nn.Module): def __init__(self, in_channels=3, out_channels=3, bilinear=True): - super(UNet, self).__init__() + super().__init__() self.in_conv = DoubleConv(in_channels, 64) self.down1 = Down(64, 128) self.down2 = Down(128, 256) self.down3 = Down(256, 512) factor = 2 if bilinear else 1 - self.down4 = (Down(512, 1024 // factor)) - self.up1 = (Up(1024, 512 // factor, bilinear)) - self.up2 = (Up(512, 256 // factor, bilinear)) - self.up3 = (Up(256, 128 // factor, bilinear)) - self.up4 = (Up(128, 64, bilinear)) + self.down4 = Down(512, 1024 // factor) + self.up1 = Up(1024, 512 // factor, bilinear) + self.up2 = Up(512, 256 // factor, bilinear) + self.up3 = Up(256, 128 // factor, bilinear) + self.up4 = Up(128, 64, bilinear) self.out_conv = OutConv(64, out_channels) def forward(self, x): diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index f4a0b05..b84372c 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -14,14 +14,14 @@ class StainNormalizationModel(LightningModule): def __init__(self) -> None: super().__init__() - self.unet = UNet(in_channels=3,out_channels=3) - self.criterion = L1SSIMLoss() + self.unet = UNet(in_channels=3, out_channels=3) + self.criterion = L1SSIMLoss() self.val_metrics = MetricCollection( { "ssim": StructuralSimilarityIndexMeasure(), } - ) + ) self.test_metrics = self.val_metrics.clone(prefix="test/") self.val_metrics.prefix = "validation/" @@ -53,13 +53,13 @@ def validation_step(self, batch: Input) -> None: def test_step(self, batch: Input) -> Outputs: inputs, data = batch outputs = self(inputs) - targets = stack([item['original_image_tensor'] for item in data]) + targets = stack([item["original_image_tensor"] for item in data]) self.test_metrics.update(outputs, targets) self.log_dict( self.test_metrics, batch_size=len(inputs), on_epoch=True, - ) + ) return outputs def predict_step(self, batch: tuple[Tensor, Any], batch_idx: int) -> Outputs: diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py index c507266..a379a3c 100644 --- a/stain_normalization/typing.py +++ b/stain_normalization/typing.py @@ -9,5 +9,3 @@ Input: TypeAlias = Sample Outputs: TypeAlias = Tensor - - From 137fa370d5be88c917623fd7bf4b320edd85c110 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 16 May 2025 14:07:47 +0000 Subject: [PATCH 56/79] chore: formating fix --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f8be213..a758313 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "Stain Normalization" version = "0.1.0" -authors = ["Adam Lopatka"] +authors = [{name = "Adam Lopatka"}] requires-python = ">=3.11" readme = "README.md" license = { file = "LICENSE" } From 7d6aee234fdcd7a878923aafb5f760ccfbf3cc84 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sun, 18 May 2025 01:58:48 +0000 Subject: [PATCH 57/79] chore: remove kubejobs --- configs/default.yaml | 43 +++++++++++++--------- pdm.lock | 86 +------------------------------------------- 2 files changed, 28 insertions(+), 101 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 0076175..9a6b082 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -11,30 +11,41 @@ seed: ${random_seed:} mode: predict checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt + +callbacks: + model_checkpoint: + _target_: lightning.pytorch.callbacks.ModelCheckpoint + save_top_k: 1 + monitor: validation/loss + mode: min + + tiles_export: + _target_: stain_normalization.callbacks.TilesExport + output_dir: ${output_dir} + normalization_config: ${data.test.normalize} + + analysis_export: + _target_: stain_normalization.callbacks.AnalysisExport + output_dir: ${output_dir} + normalization_config: ${data.test.normalize} + + save_wsi: + _target_: stain_normalization.callbacks.SaveWSI + output_dir: ${output_dir} + normalization_config: ${data.predict.normalize} + trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 callbacks: - - _target_: lightning.pytorch.callbacks.ModelCheckpoint - save_top_k: 1 - monitor: validation/loss - mode: min - - _target_: stain_normalization.callbacks.TilesExport - output_dir: ${output_dir} - normalization_config: ${data.test.normalize} - - - _target_: stain_normalization.callbacks.AnalysisExport - output_dir: ${output_dir} - normalization_config: ${data.test.normalize} - - - _target_: stain_normalization.callbacks.SaveWSI - output_dir: ${output_dir} - normalization_config: ${data.predict.normalize} + - ${callbacks.model_checkpoint} + - ${callbacks.tiles_export} + data: batch_size: 64 - num_workers: 32 + num_workers: 48 metadata: user: xlopatka diff --git a/pdm.lock b/pdm.lock index 267b14f..9434e64 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:2f62924ed5f088a39fa44fe5eaa436688edca68488cf39f4b0f4da79ca23d64f" +content_hash = "sha256:3b136c97eed3fb433ad9cd3f25569a59cb6da6d85820f1a20158ce14eb886796" [[metadata.targets]] requires_python = ">=3.11" @@ -493,16 +493,6 @@ files = [ {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, ] -[[package]] -name = "durationpy" -version = "0.9" -summary = "Module for converting between datetime.timedelta and Go's Duration strings." -groups = ["default"] -files = [ - {file = "durationpy-0.9-py3-none-any.whl", hash = "sha256:e65359a7af5cedad07fb77a2dd3f390f8eb0b74cb845589fa6c057086834dd38"}, - {file = "durationpy-0.9.tar.gz", hash = "sha256:fd3feb0a69a0057d582ef643c355c40d2fa1c942191f914d12203b1a01ac722a"}, -] - [[package]] name = "filelock" version = "3.17.0" @@ -1007,30 +997,6 @@ files = [ {file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"}, ] -[[package]] -name = "kubernetes" -version = "32.0.1" -requires_python = ">=3.6" -summary = "Kubernetes python client" -groups = ["default"] -dependencies = [ - "certifi>=14.05.14", - "durationpy>=0.7", - "google-auth>=1.0.1", - "oauthlib>=3.2.2", - "python-dateutil>=2.5.3", - "pyyaml>=5.4.1", - "requests", - "requests-oauthlib", - "six>=1.9.0", - "urllib3>=1.24.2", - "websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0", -] -files = [ - {file = "kubernetes-32.0.1-py2.py3-none-any.whl", hash = "sha256:35282ab8493b938b08ab5526c7ce66588232df00ef5e1dbe88a419107dc10998"}, - {file = "kubernetes-32.0.1.tar.gz", hash = "sha256:42f43d49abd437ada79a79a16bd48a604d3471a117a8347e87db693f2ba0ba28"}, -] - [[package]] name = "lazy-loader" version = "0.4" @@ -1675,17 +1641,6 @@ files = [ {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, ] -[[package]] -name = "oauthlib" -version = "3.2.2" -requires_python = ">=3.6" -summary = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" -groups = ["default"] -files = [ - {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, - {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, -] - [[package]] name = "omegaconf" version = "2.3.0" @@ -2301,19 +2256,6 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -[[package]] -name = "rationai-kube-jobs" -version = "0.1.0" -requires_python = ">=3.11" -git = "ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/kube-jobs.git" -revision = "7ce565cc35bfd1abe30db2e1e4e606e65dda8c84" -summary = "A simple CLI tool for managing Kubernetes jobs." -groups = ["default"] -dependencies = [ - "click>=8.1.7", - "kubernetes>=31.0.0", -] - [[package]] name = "rationai-masks" version = "1.1.0" @@ -2448,21 +2390,6 @@ files = [ {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] -[[package]] -name = "requests-oauthlib" -version = "2.0.0" -requires_python = ">=3.4" -summary = "OAuthlib authentication support for Requests." -groups = ["default"] -dependencies = [ - "oauthlib>=3.0.0", - "requests>=2.0.0", -] -files = [ - {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, - {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, -] - [[package]] name = "rpds-py" version = "0.23.1" @@ -3105,17 +3032,6 @@ files = [ {file = "waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f"}, ] -[[package]] -name = "websocket-client" -version = "1.8.0" -requires_python = ">=3.8" -summary = "WebSocket client for Python with low level API options" -groups = ["default"] -files = [ - {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, - {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, -] - [[package]] name = "werkzeug" version = "3.1.3" From 054114269af32a9d515b3c45765e9905f0d79c24 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Mon, 19 May 2025 02:54:17 +0000 Subject: [PATCH 58/79] chore: naming fix --- configs/data/modify/test.yaml | 8 +- configs/data/modify/train.yaml | 8 +- configs/default.yaml | 8 +- .../callbacks/analysis_export.py | 156 ++++++++++-------- .../data/modification/__init__.py | 8 +- 5 files changed, 107 insertions(+), 81 deletions(-) diff --git a/configs/data/modify/test.yaml b/configs/data/modify/test.yaml index 8024799..9491339 100644 --- a/configs/data/modify/test.yaml +++ b/configs/data/modify/test.yaml @@ -1,15 +1,15 @@ _target_: albumentations.OneOf p: 1.0 transforms: - - _target_: stain_normalization.data.transformation.HEDFactor + - _target_: stain_normalization.data.modification.HEDFactor h_range: [0.8, 1.2] e_range: [0.8, 1.2] - - _target_: stain_normalization.data.transformation.ExposureAdjustment + - _target_: stain_normalization.data.modification.ExposureAdjustment brightness_range: [0.8, 1.2] - - _target_: stain_normalization.data.transformation.HVSModification + - _target_: stain_normalization.data.modification.HVSModification hue_shift_range: [-0.4, 0.4] saturation_range: [0.8, 1.5] value_range: [0.8, 1.3] - - _target_: stain_normalization.data.transformation.CombinedModifications + - _target_: stain_normalization.data.modification.CombinedModifications intensity_range: [0.65, 1.35] brightness_range: [-0.4, 0.4] \ No newline at end of file diff --git a/configs/data/modify/train.yaml b/configs/data/modify/train.yaml index 8024799..9491339 100644 --- a/configs/data/modify/train.yaml +++ b/configs/data/modify/train.yaml @@ -1,15 +1,15 @@ _target_: albumentations.OneOf p: 1.0 transforms: - - _target_: stain_normalization.data.transformation.HEDFactor + - _target_: stain_normalization.data.modification.HEDFactor h_range: [0.8, 1.2] e_range: [0.8, 1.2] - - _target_: stain_normalization.data.transformation.ExposureAdjustment + - _target_: stain_normalization.data.modification.ExposureAdjustment brightness_range: [0.8, 1.2] - - _target_: stain_normalization.data.transformation.HVSModification + - _target_: stain_normalization.data.modification.HVSModification hue_shift_range: [-0.4, 0.4] saturation_range: [0.8, 1.5] value_range: [0.8, 1.3] - - _target_: stain_normalization.data.transformation.CombinedModifications + - _target_: stain_normalization.data.modification.CombinedModifications intensity_range: [0.65, 1.35] brightness_range: [-0.4, 0.4] \ No newline at end of file diff --git a/configs/default.yaml b/configs/default.yaml index 9a6b082..2542909 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -8,7 +8,7 @@ defaults: - _self_ seed: ${random_seed:} -mode: predict +mode: test checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt @@ -40,12 +40,12 @@ trainer: log_every_n_steps: 5 callbacks: - ${callbacks.model_checkpoint} - - ${callbacks.tiles_export} + - ${callbacks.analysis_export} data: - batch_size: 64 - num_workers: 48 + batch_size: 80 + num_workers: 8 metadata: user: xlopatka diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index 3bfbf01..1328fe1 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -10,6 +10,8 @@ class AnalysisExport(Callback): + """Callback for exporting analysis metrics during testing.""" + def __init__(self, output_dir: str | Path, normalization_config) -> None: super().__init__() self.output_dir = Path(output_dir) @@ -32,87 +34,111 @@ def tensor_to_image(self, tensor: torch.Tensor) -> np.ndarray: return (tensor * 255).byte().permute(1, 2, 0).cpu().numpy() def _estimate_vectors(self, img: np.ndarray) -> np.ndarray: + """Estimate stain vectors for a given image.""" return estimate_stain_vectors(img, i0=240, alpha=1, beta=0.15) def _compare_vectors(self, vec1: np.ndarray, vec2: np.ndarray) -> float: + """Compute Euclidean distance between two stain vector estimates.""" return float(np.linalg.norm(vec1 - vec2)) def _compute_ssim(self, img1: np.ndarray, img2: np.ndarray) -> float: + """Compute Structural Similarity Index (SSIM) between two images.""" return float(ssim(img1, img2, channel_axis=-1, data_range=255)) - def _compute_nmi(self, img: np.ndarray): # normalized median intensity + def _compute_nmi(self, img: np.ndarray) -> float: + """Compute Normalized Median Intensity (NMI) of an image.""" avg_rgb = img.mean(axis=2) median_val = np.median(avg_rgb) p95_val = np.percentile(avg_rgb, 95) - nmi = median_val / p95_val if p95_val != 0 else 0 - return nmi - - -def on_test_batch_end( - self, - trainer: Trainer, - pl_module: LightningModule, - outputs: list[torch.Tensor], - batch: tuple[torch.Tensor, list], - batch_idx: int, - dataloader_idx: int = 0, -) -> None: - for b in range(len(outputs)): - predicted_tensor = outputs[b] - original_np = batch[1][b]["original_image"].astype("uint8") - modified_np = (batch[1][b]["modified_image"] * 255).astype("uint8") - index = batch[1][b]["index"] - predicted_np = self.tensor_to_image(predicted_tensor) - - vec_original = self._estimate_vectors(original_np) - vec_modified = self._estimate_vectors(modified_np) - vec_predicted = self._estimate_vectors(predicted_np) - - vec_diff_mod = self._compare_vectors(vec_original, vec_modified) - vec_diff_pred = self._compare_vectors(vec_original, vec_predicted) - - ssim_mod = self._compute_ssim(original_np, modified_np) - ssim_pred = self._compute_ssim(original_np, predicted_np) - - nmi_original = self.compute_nmi(original_np) - nmi_modified = self.compute_nmi(modified_np) - nmi_predicted = self.compute_nmi(predicted_np) - - diff_row = { - "index": index, - "vector_diff_modified_vs_original": vec_diff_mod, - "vector_diff_predicted_vs_original": vec_diff_pred, - "ssim_modified_vs_original": ssim_mod, - "ssim_predicted_vs_original": ssim_pred, - "nmi_diff_modified_vs_original": nmi_modified - nmi_original, - "nmi_diff_predicted_vs_original": nmi_predicted - nmi_original, - } - - raw_row = {"index": index} - for name, vec, nmi in zip( - ["original", "modified", "predicted"], - [vec_original, vec_modified, vec_predicted], - [nmi_original, nmi_modified, nmi_predicted], - strict=False, - ): - vectors = vec.flatten() - for j, val in enumerate(vectors): - raw_row[f"{name}_vec_{j}"] = val - raw_row[f"{name}_nmi"] = nmi - - self.df_diff = pd.concat( - [self.df_diff, pd.DataFrame([diff_row])], ignore_index=True - ) - self.df_raw = pd.concat( - [self.df_raw, pd.DataFrame([raw_row])], ignore_index=True - ) - - def on_predict_end( + return median_val / p95_val if p95_val != 0 else 0.0 + + def _compute_pcc(self, img1: np.ndarray, img2: np.ndarray) -> float: + """Compute Pearson Correlation Coefficient (PCC) between two images.""" + img1_flat = img1.flatten().astype(np.float64) + img2_flat = img2.flatten().astype(np.float64) + if img1_flat.size == 0 or img2_flat.size == 0: + return 0.0 + + return float(np.corrcoef(img1_flat, img2_flat)[0, 1]) + + def on_test_batch_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list[dict]], + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + """Called at the end of each test batch. + + Computes metrics for each sample and accumulates results. + """ + for b in range(len(outputs)): + predicted_tensor = outputs[b] + original_img = batch[1][b]["original_image"].astype("uint8") + modified_img = (batch[1][b]["modified_image"] * 255).astype("uint8") + index = batch[1][b]["index"] + predicted_img = self.tensor_to_image(predicted_tensor) + + vec_original = self._estimate_vectors(original_img) + vec_modified = self._estimate_vectors(modified_img) + vec_predicted = self._estimate_vectors(predicted_img) + + vec_diff_mod = self._compare_vectors(vec_original, vec_modified) + vec_diff_pred = self._compare_vectors(vec_original, vec_predicted) + + ssim_mod = self._compute_ssim(original_img, modified_img) + ssim_pred = self._compute_ssim(original_img, predicted_img) + + nmi_original = self._compute_nmi(original_img) + nmi_modified = self._compute_nmi(modified_img) + nmi_predicted = self._compute_nmi(predicted_img) + + pcc_mod = self._compute_pcc(original_img, modified_img) + pcc_pred = self._compute_pcc(original_img, predicted_img) + + diff_row = { + "index": index, + "vector_diff_modified_vs_original": vec_diff_mod, + "vector_diff_predicted_vs_original": vec_diff_pred, + "ssim_modified_vs_original": ssim_mod, + "ssim_predicted_vs_original": ssim_pred, + "nmi_diff_modified_vs_original": nmi_modified - nmi_original, + "nmi_diff_predicted_vs_original": nmi_predicted - nmi_original, + "pcc_modified_vs_original": pcc_mod, + "pcc_predicted_vs_original": pcc_pred, + } + + raw_row = {"index": index} + for name, vec, nmi in zip( + ["original", "modified", "predicted"], + [vec_original, vec_modified, vec_predicted], + [nmi_original, nmi_modified, nmi_predicted], + strict=False, + ): + vectors = vec.flatten() + for j, val in enumerate(vectors): + raw_row[f"{name}_vec_{j}"] = val + raw_row[f"{name}_nmi"] = nmi + + self.df_diff = pd.concat( + [self.df_diff, pd.DataFrame([diff_row])], ignore_index=True + ) + self.df_raw = pd.concat( + [self.df_raw, pd.DataFrame([raw_row])], ignore_index=True + ) + + def on_test_end( self, trainer: Trainer, pl_module: LightningModule, outputs: list, ) -> None: + """Called at the end of testing. + + Saves the collected metrics as CSV files and logs them as mlflow artifacts. + """ diff_path = self.output_dir / "analysis_differences.csv" raw_path = self.output_dir / "analysis_raw_vectors.csv" diff --git a/stain_normalization/data/modification/__init__.py b/stain_normalization/data/modification/__init__.py index 1d8962b..0e01429 100644 --- a/stain_normalization/data/modification/__init__.py +++ b/stain_normalization/data/modification/__init__.py @@ -1,11 +1,11 @@ -from stain_normalization.data.transformation.combiend_modification import ( +from stain_normalization.data.modification.combiend_modification import ( CombinedModifications, ) -from stain_normalization.data.transformation.exposure_adjustment import ( +from stain_normalization.data.modification.exposure_adjustment import ( ExposureAdjustment, ) -from stain_normalization.data.transformation.hed_factor import HEDFactor -from stain_normalization.data.transformation.hvs_modification import HVSModification +from stain_normalization.data.modification.hed_factor import HEDFactor +from stain_normalization.data.modification.hvs_modification import HVSModification __all__ = [ From b3cc69885f0802abaf06689100820d954ccbf8f6 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni.cz> Date: Mon, 19 May 2025 08:30:43 +0200 Subject: [PATCH 59/79] chore: add comments and fix formating --- preprocessing/tiler.py | 1 - .../modification/combiend_modification.py | 50 +++++++++++++------ .../data/modification/exposure_adjustment.py | 23 ++++++++- .../data/modification/hed_factor.py | 33 ++++++++---- .../data/modification/hvs_modification.py | 25 +++++++++- stain_normalization/modeling/l1ssim_loss.py | 5 ++ stain_normalization/modeling/unet.py | 11 ++-- 7 files changed, 113 insertions(+), 35 deletions(-) diff --git a/preprocessing/tiler.py b/preprocessing/tiler.py index 87f7062..55c5cda 100644 --- a/preprocessing/tiler.py +++ b/preprocessing/tiler.py @@ -150,5 +150,4 @@ def main() -> None: if __name__ == "__main__": - # pass main() diff --git a/stain_normalization/data/modification/combiend_modification.py b/stain_normalization/data/modification/combiend_modification.py index 18dbaf3..7188798 100644 --- a/stain_normalization/data/modification/combiend_modification.py +++ b/stain_normalization/data/modification/combiend_modification.py @@ -1,37 +1,57 @@ import numpy as np from albumentations import ImageOnlyTransform +from numpy.typing import NDArray from skimage import exposure from skimage.color import combine_stains, hed_from_rgb, rgb_from_hed, separate_stains class CombinedModifications(ImageOnlyTransform): + """Apply combined modifications to the H&E channels in HED color space. + + Attributes: + intensity_range: Range of multiplicative factors to scale stain channel intensities. + brightness_range: Range for gamma correction to simulate brightness shift. + always_apply: Whether the transformation should always be applied. + p: Probability of applying the transformation. + """ + def __init__( self, - intensity_range=(0.4, 1.5), - brightness_range=(-0.4, 0.4), - always_apply=True, - p=1.0, + intensity_range: tuple[float, float] = (0.4, 1.5), + brightness_range: tuple[float, float] = (-0.4, 0.4), + always_apply: bool = True, + p: float = 1.0, ): super().__init__(always_apply, p) self.intensity_range = intensity_range self.brightness_range = brightness_range - def apply(self, hed_img, **params): - def modify_channel(channel, intensity_range, brightness_range): - intensity_scale = np.random.uniform(*intensity_range) - channel = channel * intensity_scale - brightness_shift = np.random.uniform(*brightness_range) - channel = exposure.adjust_gamma(channel, gamma=1 + brightness_shift) - return np.clip(channel, 0, 1) + def apply(self, img: NDArray, **params) -> NDArray: + """Apply intensity and brightness adjustments to H and E channels. + + Args: + img: Image to which the transformation will be applied. + params: Additional parameters (unused). - hed_image = separate_stains(hed_img, hed_from_rgb) - h = modify_channel( + Returns: + Modified RGB image as a float32 NumPy array with values in [0.0, 1.0]. + """ + hed_image = separate_stains(img, hed_from_rgb) + h = self.modify_channel( hed_image[:, :, 0], self.intensity_range, self.brightness_range ) - e = modify_channel( + e = self.modify_channel( hed_image[:, :, 1], self.intensity_range, self.brightness_range ) - d = hed_image[:, :, 2] # Skip modification for D channel + d = hed_image[:, :, 2] modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) + return modified_rgb + + def modify_channel(self, channel: NDArray[np.float32]) -> NDArray[np.float32]: + intensity_scale = np.random.uniform(*self.intensity_range) + channel = channel * intensity_scale + brightness_shift = np.random.uniform(*self.brightness_range) + channel = exposure.adjust_gamma(channel, gamma=1 + brightness_shift) + return np.clip(channel, 0, 1) diff --git a/stain_normalization/data/modification/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py index 6e0899e..eb4215a 100644 --- a/stain_normalization/data/modification/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -1,8 +1,19 @@ import numpy as np from albumentations import ImageOnlyTransform +from numpy.typing import NDArray class ExposureAdjustment(ImageOnlyTransform): + """Adjust the exposure of an image by scaling its brightness. + + Attributes: + brightness_range: Range specifying the lower and upper bounds for the + random brightness scaling factor. Values less than 1.0 darken the image, + while values greater than 1.0 brighten it. + always_apply: Whether this transformation should always be applied. + p: Probability of applying the transformation. + """ + def __init__( self, brightness_range: tuple[float, float] = (0.8, 1.2), @@ -12,7 +23,17 @@ def __init__( super().__init__(always_apply, p) self.brightness_range = brightness_range - def apply(self, img, **params): + def apply(self, img: NDArray, **params) -> NDArray: + """Apply brightness scaling to the image. + + Args: + img: Input image whose brightness will be adjusted. + params: Additional parameters. + + Returns: + RGB image with adjusted brightness as a float32 + NumPy array with values in [0.0, 1.]. + """ brightness_factor = np.random.uniform(*self.brightness_range) img = img.astype(np.float32) img = np.clip(img * brightness_factor, 0.0, 1.0) diff --git a/stain_normalization/data/modification/hed_factor.py b/stain_normalization/data/modification/hed_factor.py index c8e90b2..6617a85 100644 --- a/stain_normalization/data/modification/hed_factor.py +++ b/stain_normalization/data/modification/hed_factor.py @@ -1,9 +1,19 @@ import numpy as np from albumentations import ImageOnlyTransform +from numpy.typing import NDArray from skimage.color import combine_stains, hed_from_rgb, rgb_from_hed, separate_stains class HEDFactor(ImageOnlyTransform): + """Adjust the intensity of Hematoxylin and Eosin stains in HED color space. + + Attributes: + h_intensity_range: Range for the random intensity adjustment factor for the Hematoxylin channel. + e_intensity_range: Range for the random intensity adjustment factor for the Eosin channel. + always_apply: Whether this transformation should always be applied. + p: Probability of applying the transformation. + """ + def __init__( self, h_range: tuple[float, float] = (0.8, 1.2), @@ -15,21 +25,24 @@ def __init__( self.h_range = h_range self.e_range = e_range - def apply(self, img, **params): + def apply(self, img: NDArray, **params) -> NDArray: + """Apply the modification to the image. + + Args: + img: Image to which the transformation will be applied. + params: Additional parameters. + + Returns: + RGB image with modified Hematoxylin and Eosin channels + as a float32 NumPy array with values in [0.0, 1.]. + """ h_factor = np.random.uniform(*self.h_range) e_factor = np.random.uniform(*self.e_range) - return self.multiply_channels(img, e_factor, h_factor) - - def multiply_channels( - self, - image, - e_factor=1.1, - h_factor=1.1, - ): - hed_image = separate_stains(image, hed_from_rgb) + hed_image = separate_stains(img, hed_from_rgb) h = hed_image[:, :, 0] * h_factor e = hed_image[:, :, 1] * e_factor d = hed_image[:, :, 2] modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) + return modified_rgb diff --git a/stain_normalization/data/modification/hvs_modification.py b/stain_normalization/data/modification/hvs_modification.py index 8c47003..0ae293c 100644 --- a/stain_normalization/data/modification/hvs_modification.py +++ b/stain_normalization/data/modification/hvs_modification.py @@ -1,9 +1,22 @@ import numpy as np from albumentations import ImageOnlyTransform +from numpy.typing import NDArray from skimage.color import hsv2rgb, rgb2hsv class HVSModification(ImageOnlyTransform): + """Randomly modify hue, saturation, and value (brightness) of an image in HSV color space. + + Attributes: + hue_shift_range: Range of values to randomly shift the hue channel. + Values are wrapped around the [0, 1) interval (modulo 1.0). + saturation_range: Range for randomly scaling the saturation channel. + Values >1.0 increase saturation, <1.0 decrease it. + value_range: Range for randomly scaling the value (brightness) channel. + always_apply: Whether the transformation is always applied. + p: Probability of applying the transformation. + """ + def __init__( self, hue_shift_range: tuple[float, float] = (-0.2, 0.2), @@ -17,7 +30,17 @@ def __init__( self.saturation_range = saturation_range self.value_range = value_range - def apply(self, img, **params): + def apply(self, img: NDArray, **params) -> NDArray: + """Apply the modifications to an image. + + Args: + img: Image to which the transformation will be applied. + params: Additional parameters. + + Returns: + RGB image with HVS modifiedications as a float32 + NumPy array with values in [0.0, 1.]. + """ hue_shift = np.random.uniform(*self.hue_shift_range) saturation_scale = np.random.uniform(*self.saturation_range) value_scale = np.random.uniform(*self.value_range) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 9cad241..620e51f 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -1,3 +1,8 @@ +"""Original SSIM code based on pytorch-ssim by Evan Su (MIT License). + +https://github.com/Po-Hsun-Su/pytorch-ssim . +""" + from math import exp import torch diff --git a/stain_normalization/modeling/unet.py b/stain_normalization/modeling/unet.py index a5f5d2b..77f9b32 100644 --- a/stain_normalization/modeling/unet.py +++ b/stain_normalization/modeling/unet.py @@ -1,10 +1,11 @@ -"""Model created using segmentation_models_pytorch library. +"""Adapted U-Net implementation based on the GitHub repository. -Adapted U-Net implementation based on https://github.com/milesial/Pytorch-UNet +https://github.com/milesial/Pytorch-UNet . +Original U-Net architecture proposed in the paper. Ronneberger, O., Fischer, P., & Brox, T. (2015). U-Net: Convolutional Networks for Biomedical Image Segmentation. arXiv:1505.04597 [cs.CV]. -Retrieved from https://arxiv.org/abs/1505.04597. +Retrieved from https://arxiv.org/abs/1505.04597 . """ import torch @@ -63,14 +64,10 @@ def __init__(self, in_channels, out_channels, bilinear=True): def forward(self, x1, x2): x1 = self.up(x1) - # input is CHW diffy = x2.size()[2] - x1.size()[2] diffx = x2.size()[3] - x1.size()[3] x1 = F.pad(x1, [diffx // 2, diffx - diffx // 2, diffy // 2, diffy - diffy // 2]) - # if you have padding issues, see - # https://github.com/HaiyongJiang/U-Net-Pytorch-Unstructured-Buggy/commit/0e854509c2cea854e247a9c615f175f76fbb2e3a - # https://github.com/xiaopeng-liao/Pytorch-UNet/commit/8ebac70e633bac59fc22bb5195e513d5832fb3bd x = torch.cat([x2, x1], dim=1) return self.conv(x) From 1bbce8082e72fe9ad1e45793a0705265571c840a Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni.cz> Date: Mon, 19 May 2025 08:31:06 +0200 Subject: [PATCH 60/79] feat: added demo --- README.md | 42 +++++++---------- demo.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ pdm.lock | 117 +++++++---------------------------------------- pyproject.toml | 2 +- 4 files changed, 156 insertions(+), 127 deletions(-) create mode 100644 demo.py diff --git a/README.md b/README.md index 71036c8..a6d034d 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,34 @@ # Stain Normalization -export MLFLOW_TRACKING_USERNAME= +Tento repozitár slúži ako doplnkový materiál k bakalárskej práci **"Normalizácia farbenia histopatologických snímkov pomocou neuronových sietí"**. +Celý kód nie je možné spustiť samostatne, pretože vyžaduje prístup k citlivým dátam a k platforme na správu strojového učenia MLflow. Avšak je možné spustiť demo, ku ktorému je pripravených pár vzoriek na demonštráciu. -[![PyTorch Lightning](https://img.shields.io/badge/pytorch-lightning-blue.svg?logo=PyTorch%20Lightning)](https://github.com/Lightning-AI/lightning) -[![License](https://img.shields.io/badge/License-MIT-red.svg)](https://gitlab.ics.muni.cz/rationai/digital-pathology/pathology/patch-camelyon/-/blob/master/LICENSE) +## Demo +Demo skript umožňuje načítať jeden obrázok alebo celý priečinok, normalizovať ich pomocou predtrénovaného modelu a uložiť výsledné obrázky do určeného priečinka. -The main goal ... +## Priložené dáta +- **Originálne obrázky** (v priečinku `./demo_data/original`) – referenčné vzorky. +- **Upravené obrázky** (v priečinku `./demo_data/modified`) – referenčné obrázky s modifikovaným sfarbením, ktoré sa následne modelom znormalizujú späť k originálnemu vzhľadu. +- **Obrázky z iného datasetu** (v priečinku `./demo_data/to_predict`) – ukazujú, ako model dokáže prispôsobiť farby vstupov tak, aby zodpovedali farebnému štýlu trénovacích dát. +- **Model checkpoint** -## Getting Started +## Spustenie dema -### Installation +Projekt je spravovaný pomocou nástroja **pdm**, ktorý umožňuje jednoduchú správu závislostí a prostredia. Stačí nainštalovať závislosti pomocou: -Install [PDM](https://pdm.fming.dev/) package manager and install all the dependencies using the following command: ```bash pdm install ``` - -### Preprocessing - -```bash -export MLFLOW_TRACKING_USERNAME= -pdm run preprocessing/generate_tissue_mask.py -pdm run preprocessing/tiling.py -``` - -### Training +a potom spustiť demo skript: ```bash -export MLFLOW_TRACKING_USERNAME= -pdm fit model/backbone=(vgg16|resnet18) +pdm run python demo.py --input ./demo_data/modified ``` -### Testing - -```bash -export MLFLOW_TRACKING_USERNAME= -pdm test model/backbone=(vgg16|resnet18) 'checkpoint=""' -``` +## Dostupné arguemnty: +- **input**: cesta k obrázku alebo priečinku s obrázkami na normalizáciu (default ./demo_data/modified) +- **output**: priečinok, kam sa uložia normalizované obrázky (default ./demo_data) +- **use_cpu**: defaultne nadstavené na použitie GPU ak je dostupná, avšak ak by nastali problémy odporúčam použivať iba CPU \ No newline at end of file diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..69ca771 --- /dev/null +++ b/demo.py @@ -0,0 +1,122 @@ +import argparse +from pathlib import Path + +import albumentations as A +import numpy as np +import torch +from albumentations.pytorch import ToTensorV2 +from PIL import Image + +from stain_normalization.stain_normalization_model import StainNormalizationModel + + +class StainNormalizerDemo: + CHECKPOINT_PATH = "./demo_data/checkpoint.ckpt" + MEAN = (0.780361961, 0.614529804, 0.725567843) + STD = (0.144428627, 0.183275686, 0.140768627) + + NORMALIZE_TRANSFORM = A.Normalize(mean=MEAN, std=STD, max_pixel_value=1) + TO_TENSOR = ToTensorV2() + + def __init__(self, use_cpu=True): + self.device = torch.device( + "cpu" if use_cpu else ("cuda" if torch.cuda.is_available() else "cpu") + ) + print(f"Using device: {self.device}") + + self.model = StainNormalizationModel() + checkpoint = torch.load(self.CHECKPOINT_PATH, map_location=self.device) + if "state_dict" in checkpoint: + self.model.load_state_dict(checkpoint["state_dict"]) + else: + self.model.load_state_dict(checkpoint) + self.model.to(self.device) + self.model.eval() + + def load_image(self, path: Path) -> torch.Tensor: + img = Image.open(path).convert("RGB") + img_np = np.array(img).astype(np.float32) / 255.0 + normalized = self.NORMALIZE_TRANSFORM(image=img_np)["image"] + tensor = self.TO_TENSOR(image=normalized)["image"].to(self.device).unsqueeze(0) + return tensor + + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: + mean = torch.tensor(self.MEAN).view(3, 1, 1).to(tensor.device) + std = torch.tensor(self.STD).view(3, 1, 1).to(tensor.device) + return tensor * std + mean + + def tensor_to_image(self, tensor: torch.Tensor) -> Image.Image: + tensor = self.denormalize(tensor) + tensor = tensor.clamp(0, 1) + tensor = (tensor * 255).byte() + return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) + + def save_image(self, tensor: torch.Tensor, path: Path): + img = self.tensor_to_image(tensor.squeeze(0)) + img.save(path) + + def predict_image(self, input_path: Path, output_path: Path): + with torch.no_grad(): + input_tensor = self.load_image(input_path) + output = self.model(input_tensor) + self.save_image(output, output_path) + print(f"Saved normalized image to {output_path}") + + +def main(): + parser = argparse.ArgumentParser(description="Stain Normalization Demo") + parser.add_argument( + "--input", + type=str, + default="./demo_data/modified", + help="Input image or folder path", + ) + parser.add_argument( + "--output", + type=str, + default="./demo_data", + help="Output folder path", + ) + parser.add_argument( + "--use_cpu", + action="store_true", + help="Force CPU even if GPU available", + ) + args = parser.parse_args() + + normalizer = StainNormalizerDemo(use_cpu=args.use_cpu) + + input_path = Path(args.input) + output_path = Path(args.output) + + if not output_path.exists(): + output_path.mkdir(parents=True) + + if input_path.is_file(): + out_filename = input_path.stem + "_normalized" + input_path.suffix + out_path = output_path / out_filename + normalizer.predict_image(input_path, out_path) + + elif input_path.is_dir(): + norm_folder = output_path / "normalized" + norm_folder.mkdir(exist_ok=True) + + input_files = sorted( + f + for f in input_path.iterdir() + if f.is_file() and f.suffix.lower() in {".png", ".jpg", ".jpeg"} + ) + if not input_files: + print(f"No image files found in {input_path}.") + return + for in_path in input_files: + out_filename = in_path.stem + "_normalized" + in_path.suffix + out_path = norm_folder / out_filename + normalizer.predict_image(in_path, out_path) + + else: + raise ValueError(f"Input path {input_path} does not exist.") + + +if __name__ == "__main__": + main() diff --git a/pdm.lock b/pdm.lock index 9434e64..c53931a 100644 --- a/pdm.lock +++ b/pdm.lock @@ -4,11 +4,8 @@ [metadata] groups = ["default", "dev"] strategy = ["inherit_metadata"] -lock_version = "4.5.0" -content_hash = "sha256:3b136c97eed3fb433ad9cd3f25569a59cb6da6d85820f1a20158ce14eb886796" - -[[metadata.targets]] -requires_python = ">=3.11" +lock_version = "4.4.2" +content_hash = "sha256:d9fbd23622ea9172dda4f468af65fdfdb8d70bea316aaed2d1898878e365ad57" [[package]] name = "aiohappyeyeballs" @@ -30,7 +27,6 @@ groups = ["default"] dependencies = [ "aiohappyeyeballs>=2.3.0", "aiosignal>=1.1.2", - "async-timeout<6.0,>=4.0; python_version < \"3.11\"", "attrs>=17.3.0", "frozenlist>=1.1.1", "multidict<7.0,>=4.5", @@ -114,7 +110,6 @@ dependencies = [ "opencv-python-headless>=4.9.0.80", "simsimd>=5.9.2", "stringzilla>=3.10.4", - "typing-extensions>=4.9.0; python_version < \"3.10\"", ] files = [ {file = "albucore-0.0.23-py3-none-any.whl", hash = "sha256:99274ac0c15a1a7d9a726df9d54d5ab70d9d0c189e2a935399dba3d4bafad415"}, @@ -130,12 +125,10 @@ groups = ["default"] dependencies = [ "PyYAML", "albucore==0.0.23", - "eval-type-backport; python_version < \"3.10\"", "numpy>=1.24.4", "opencv-python-headless>=4.9.0.80", "pydantic>=2.9.2", "scipy>=1.10.0", - "typing-extensions>=4.9.0; python_version < \"3.10\"", ] files = [ {file = "albumentations-2.0.5-py3-none-any.whl", hash = "sha256:1fc253942d34dd7c07652bf6511049c8bb7d522baec7f1fe355df16293c3c7b6"}, @@ -164,9 +157,6 @@ version = "0.7.0" requires_python = ">=3.8" summary = "Reusable constraint types to use with typing.Annotated" groups = ["default"] -dependencies = [ - "typing-extensions>=4.0.0; python_version < \"3.9\"", -] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -177,9 +167,6 @@ name = "antlr4-python3-runtime" version = "4.9.3" summary = "ANTLR 4.9.3 runtime for Python 3.7" groups = ["default"] -dependencies = [ - "typing; python_version < \"3.5\"", -] files = [ {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, ] @@ -342,10 +329,6 @@ version = "8.1.8" requires_python = ">=3.7" summary = "Composable command line interface toolkit" groups = ["default"] -dependencies = [ - "colorama; platform_system == \"Windows\"", - "importlib-metadata; python_version < \"3.8\"", -] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -362,18 +345,6 @@ files = [ {file = "cloudpickle-3.1.1.tar.gz", hash = "sha256:b216fa8ae4019d5482a8ac3c95d8f6346115d8835911fd4aefd1a445e4242c64"}, ] -[[package]] -name = "colorama" -version = "0.4.6" -requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -summary = "Cross-platform colored terminal text." -groups = ["default"] -marker = "platform_system == \"Windows\"" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - [[package]] name = "contourpy" version = "1.3.1" @@ -484,7 +455,6 @@ requires_python = ">=3.8" summary = "A Python library for the Docker Engine API." groups = ["default"] dependencies = [ - "pywin32>=304; sys_platform == \"win32\"", "requests>=2.26.0", "urllib3>=1.26.0", ] @@ -515,7 +485,6 @@ dependencies = [ "Werkzeug>=3.1", "blinker>=1.9", "click>=8.1.3", - "importlib-metadata>=3.6; python_version < \"3.10\"", "itsdangerous>=2.2", ] files = [ @@ -663,7 +632,6 @@ summary = "GitPython is a Python library used to interact with Git repositories" groups = ["default"] dependencies = [ "gitdb<5,>=4.0.1", - "typing-extensions>=3.7.4.3; python_version < \"3.8\"", ] files = [ {file = "GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110"}, @@ -708,9 +676,6 @@ version = "3.2.6" requires_python = "<4,>=3.6" summary = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." groups = ["default"] -dependencies = [ - "typing-extensions<5,>=4; python_version < \"3.10\"", -] files = [ {file = "graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"}, {file = "graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab"}, @@ -724,7 +689,6 @@ summary = "Relay library for graphql-core" groups = ["default"] dependencies = [ "graphql-core<3.3,>=3.2", - "typing-extensions<5,>=4.1; python_version < \"3.8\"", ] files = [ {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"}, @@ -784,7 +748,6 @@ summary = "WSGI HTTP Server for UNIX" groups = ["default"] marker = "platform_system != \"Windows\"" dependencies = [ - "importlib-metadata; python_version < \"3.8\"", "packaging", ] files = [ @@ -799,7 +762,6 @@ summary = "A framework for elegantly configuring complex applications" groups = ["default"] dependencies = [ "antlr4-python3-runtime==4.9.*", - "importlib-resources; python_version < \"3.9\"", "omegaconf<2.4,>=2.2", "packaging", ] @@ -852,7 +814,6 @@ requires_python = ">=3.8" summary = "Read metadata from Python packages" groups = ["default"] dependencies = [ - "typing-extensions>=3.6.4; python_version < \"3.8\"", "zipp>=3.20", ] files = [ @@ -904,9 +865,7 @@ summary = "An implementation of JSON Schema validation for Python" groups = ["default"] dependencies = [ "attrs>=22.2.0", - "importlib-resources>=1.4.0; python_version < \"3.9\"", "jsonschema-specifications>=2023.03.6", - "pkgutil-resolve-name>=1.3.10; python_version < \"3.9\"", "referencing>=0.28.4", "rpds-py>=0.7.1", ] @@ -1004,7 +963,6 @@ requires_python = ">=3.7" summary = "Makes it easy to load subpackages and functions on demand." groups = ["default"] dependencies = [ - "importlib-metadata; python_version < \"3.8\"", "packaging", ] files = [ @@ -1041,7 +999,6 @@ requires_python = ">=3.9" summary = "Lightning toolbox for across the our ecosystem." groups = ["default"] dependencies = [ - "importlib-metadata>=4.0.0; python_version < \"3.8\"", "packaging>=17.1", "setuptools", "typing-extensions", @@ -1071,9 +1028,6 @@ version = "3.7" requires_python = ">=3.8" summary = "Python implementation of John Gruber's Markdown." groups = ["default"] -dependencies = [ - "importlib-metadata>=4.4; python_version < \"3.10\"", -] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -1183,7 +1137,6 @@ groups = ["default"] dependencies = [ "Flask<4", "Jinja2<4,>=2.11; platform_system != \"Windows\"", - "Jinja2<4,>=3.0; platform_system == \"Windows\"", "alembic!=1.10.0,<2", "docker<8,>=4.0.0", "graphene<4", @@ -1197,7 +1150,6 @@ dependencies = [ "scikit-learn<2", "scipy<2", "sqlalchemy<3,>=1.4.0", - "waitress<4; platform_system == \"Windows\"", ] files = [ {file = "mlflow-2.20.3-py3-none-any.whl", hash = "sha256:efafe5d4d17b53be1ae02c7d8708a5e4bbde4bd3aecd2bd68b64a3c4175e9dc6"}, @@ -1292,9 +1244,6 @@ version = "6.1.0" requires_python = ">=3.8" summary = "multidict implementation" groups = ["default"] -dependencies = [ - "typing-extensions>=4.1.0; python_version < \"3.11\"", -] files = [ {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, @@ -1353,7 +1302,6 @@ summary = "Optional static typing for Python" groups = ["dev"] dependencies = [ "mypy-extensions>=1.0.0", - "tomli>=1.1.0; python_version < \"3.11\"", "typing-extensions>=4.6.0", ] files = [ @@ -1536,9 +1484,6 @@ requires_python = ">=3" summary = "CUFFT native runtime libraries" groups = ["default"] marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" -dependencies = [ - "nvidia-nvjitlink-cu12", -] files = [ {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, @@ -1650,7 +1595,6 @@ groups = ["default"] dependencies = [ "PyYAML>=5.1.0", "antlr4-python3-runtime==4.9.*", - "dataclasses; python_version == \"3.6\"", ] files = [ {file = "omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b"}, @@ -1664,14 +1608,10 @@ requires_python = ">=3.6" summary = "Wrapper package for OpenCV python bindings." groups = ["default"] dependencies = [ - "numpy>=1.13.3; python_version < \"3.7\"", "numpy>=1.17.0; python_version >= \"3.7\"", "numpy>=1.17.3; python_version >= \"3.8\"", - "numpy>=1.19.3; python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\"", "numpy>=1.19.3; python_version >= \"3.9\"", - "numpy>=1.21.0; python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\"", "numpy>=1.21.2; python_version >= \"3.10\"", - "numpy>=1.21.4; python_version >= \"3.10\" and platform_system == \"Darwin\"", "numpy>=1.23.5; python_version >= \"3.11\"", "numpy>=1.26.0; python_version >= \"3.12\"", ] @@ -1780,8 +1720,6 @@ requires_python = ">=3.9" summary = "Powerful data structures for data analysis, time series, and statistics" groups = ["default"] dependencies = [ - "numpy>=1.22.4; python_version < \"3.11\"", - "numpy>=1.23.2; python_version == \"3.11\"", "numpy>=1.26.0; python_version >= \"3.12\"", "python-dateutil>=2.8.2", "pytz>=2020.1", @@ -1869,6 +1807,17 @@ files = [ {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, ] +[[package]] +name = "pkgconfig" +version = "1.5.5" +requires_python = ">=3.3,<4.0" +summary = "Interface Python with pkg-config" +groups = ["default"] +files = [ + {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, + {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, +] + [[package]] name = "platformdirs" version = "4.3.6" @@ -2192,33 +2141,16 @@ files = [ [[package]] name = "pyvips" version = "2.2.3" -summary = "binding for the libvips image processing library, ABI mode" +summary = "binding for the libvips image processing library, API mode" groups = ["default"] dependencies = [ "cffi>=1.0.0", + "pkgconfig", ] files = [ {file = "pyvips-2.2.3.tar.gz", hash = "sha256:43bceced0db492654c93008246a58a508e0373ae1621116b87b322f2ac72212f"}, ] -[[package]] -name = "pywin32" -version = "308" -summary = "Python for Window Extensions" -groups = ["default"] -marker = "sys_platform == \"win32\"" -files = [ - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, -] - [[package]] name = "pyyaml" version = "6.0.2" @@ -2297,7 +2229,7 @@ dependencies = [ name = "rationai-staining" version = "0.1.0" requires_python = ">=3.11" -git = "ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" +git = "https://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" revision = "bd1d704d86468a42d2321e9041c746215255c099" summary = "" groups = ["default"] @@ -2714,7 +2646,6 @@ summary = "Database Abstraction Library" groups = ["default"] dependencies = [ "greenlet!=0.4.17; (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_version < \"3.14\"", - "importlib-metadata; python_version < \"3.8\"", "typing-extensions>=4.6.0", ] files = [ @@ -2950,9 +2881,6 @@ version = "4.67.1" requires_python = ">=3.7" summary = "Fast, Extensible Progress Meter" groups = ["default"] -dependencies = [ - "colorama; platform_system == \"Windows\"", -] files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -3012,7 +2940,6 @@ groups = ["dev"] dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", - "importlib-metadata>=6.6; python_version < \"3.8\"", "platformdirs<5,>=3.9.1", ] files = [ @@ -3020,18 +2947,6 @@ files = [ {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, ] -[[package]] -name = "waitress" -version = "3.0.2" -requires_python = ">=3.9.0" -summary = "Waitress WSGI server" -groups = ["default"] -marker = "platform_system == \"Windows\"" -files = [ - {file = "waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e"}, - {file = "waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f"}, -] - [[package]] name = "werkzeug" version = "3.1.3" diff --git a/pyproject.toml b/pyproject.toml index a758313..d2acf8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "rationai-tiling @ git+https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.git", "scikit-image>=0.25.2", "openslide-bin>=4.0.0.6", - "rationai-staining @ git+ssh://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git" + "rationai-staining @ git+https://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/staining.git", ] [tool.pdm.dev-dependencies] From a36d502fb15f93c00ade4373528eee8ed61f015b Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni.cz> Date: Mon, 19 May 2025 17:10:17 +0200 Subject: [PATCH 61/79] fix: formating --- .../data/modification/combiend_modification.py | 8 ++------ .../data/modification/exposure_adjustment.py | 2 +- stain_normalization/data/modification/hed_factor.py | 2 +- stain_normalization/data/modification/hvs_modification.py | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/stain_normalization/data/modification/combiend_modification.py b/stain_normalization/data/modification/combiend_modification.py index 7188798..6eebbc3 100644 --- a/stain_normalization/data/modification/combiend_modification.py +++ b/stain_normalization/data/modification/combiend_modification.py @@ -37,12 +37,8 @@ def apply(self, img: NDArray, **params) -> NDArray: Modified RGB image as a float32 NumPy array with values in [0.0, 1.0]. """ hed_image = separate_stains(img, hed_from_rgb) - h = self.modify_channel( - hed_image[:, :, 0], self.intensity_range, self.brightness_range - ) - e = self.modify_channel( - hed_image[:, :, 1], self.intensity_range, self.brightness_range - ) + h = self.modify_channel(hed_image[:, :, 0]) + e = self.modify_channel(hed_image[:, :, 1]) d = hed_image[:, :, 2] modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) diff --git a/stain_normalization/data/modification/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py index eb4215a..69e9e5c 100644 --- a/stain_normalization/data/modification/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -31,7 +31,7 @@ def apply(self, img: NDArray, **params) -> NDArray: params: Additional parameters. Returns: - RGB image with adjusted brightness as a float32 + RGB image with adjusted brightness as a float32 NumPy array with values in [0.0, 1.]. """ brightness_factor = np.random.uniform(*self.brightness_range) diff --git a/stain_normalization/data/modification/hed_factor.py b/stain_normalization/data/modification/hed_factor.py index 6617a85..790982a 100644 --- a/stain_normalization/data/modification/hed_factor.py +++ b/stain_normalization/data/modification/hed_factor.py @@ -33,7 +33,7 @@ def apply(self, img: NDArray, **params) -> NDArray: params: Additional parameters. Returns: - RGB image with modified Hematoxylin and Eosin channels + RGB image with modified Hematoxylin and Eosin channels as a float32 NumPy array with values in [0.0, 1.]. """ h_factor = np.random.uniform(*self.h_range) diff --git a/stain_normalization/data/modification/hvs_modification.py b/stain_normalization/data/modification/hvs_modification.py index 0ae293c..53e4697 100644 --- a/stain_normalization/data/modification/hvs_modification.py +++ b/stain_normalization/data/modification/hvs_modification.py @@ -38,7 +38,7 @@ def apply(self, img: NDArray, **params) -> NDArray: params: Additional parameters. Returns: - RGB image with HVS modifiedications as a float32 + RGB image with HVS modifiedications as a float32 NumPy array with values in [0.0, 1.]. """ hue_shift = np.random.uniform(*self.hue_shift_range) From cdd39a6f5a4157b3d2cae6477b5254ff7551a153 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Mon, 19 May 2025 23:09:38 +0000 Subject: [PATCH 62/79] fix: arguments --- stain_normalization/callbacks/analysis_export.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index 1328fe1..59e34de 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -133,7 +133,6 @@ def on_test_end( self, trainer: Trainer, pl_module: LightningModule, - outputs: list, ) -> None: """Called at the end of testing. From b8a928c53f1c60982dd65e9c2eb771da273cdcce Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Nov 2025 03:06:50 +0000 Subject: [PATCH 63/79] feat: add brightness loss and analysis --- configs/default.yaml | 13 +- .../callbacks/analysis_export.py | 18 +++ .../data/modification/hed_factor.py | 6 +- stain_normalization/modeling/l1ssim_loss.py | 141 ++++++++++-------- .../stain_normalization_model.py | 2 + 5 files changed, 108 insertions(+), 72 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 2542909..7ca7078 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -8,14 +8,14 @@ defaults: - _self_ seed: ${random_seed:} -mode: test -checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt +mode: fit +checkpoint: null callbacks: model_checkpoint: _target_: lightning.pytorch.callbacks.ModelCheckpoint - save_top_k: 1 + save_top_k: 2 monitor: validation/loss mode: min @@ -38,19 +38,20 @@ trainer: enable_checkpointing: True max_epochs: 30 log_every_n_steps: 5 + val_check_interval: 0.5 + callbacks: - ${callbacks.model_checkpoint} - ${callbacks.analysis_export} - data: - batch_size: 80 + batch_size: 16 num_workers: 8 metadata: user: xlopatka experiment_name: Stain-Normalization - run_name: Debuging + run_name: fit bright description: Stain Normalization hyperparams: {} diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index 59e34de..f1e307d 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -7,6 +7,8 @@ from lightning import Callback, LightningModule, Trainer from rationai.staining import estimate_stain_vectors from skimage.metrics import structural_similarity as ssim +from skimage.color import rgb2lab +from skimage.metrics import peak_signal_noise_ratio class AnalysisExport(Callback): @@ -60,6 +62,17 @@ def _compute_pcc(self, img1: np.ndarray, img2: np.ndarray) -> float: return 0.0 return float(np.corrcoef(img1_flat, img2_flat)[0, 1]) + + def _compute_lab_brightness_psnr(self, img1: np.ndarray, img2: np.ndarray) -> float: + """Compute PSNR on the L (lightness) channel in Lab color space. + """ + lab1 = rgb2lab(img1.astype(np.float32) / 255.0) + lab2 = rgb2lab(img2.astype(np.float32) / 255.0) + + L1 = lab1[:, :, 0] + L2 = lab2[:, :, 0] + + return float(peak_signal_noise_ratio(L1, L2, data_range=100.0)) def on_test_batch_end( self, @@ -97,6 +110,9 @@ def on_test_batch_end( pcc_mod = self._compute_pcc(original_img, modified_img) pcc_pred = self._compute_pcc(original_img, predicted_img) + + lab_psnr_mod = self._compute_lab_brightness_psnr(original_img, modified_img) + lab_psnr_pred = self._compute_lab_brightness_psnr(original_img, predicted_img) diff_row = { "index": index, @@ -108,6 +124,8 @@ def on_test_batch_end( "nmi_diff_predicted_vs_original": nmi_predicted - nmi_original, "pcc_modified_vs_original": pcc_mod, "pcc_predicted_vs_original": pcc_pred, + "lab_brightness_psnr_mod_vs_orig": lab_psnr_mod, + "lab_brightness_psnr_pred_vs_orig": lab_psnr_pred, } raw_row = {"index": index} diff --git a/stain_normalization/data/modification/hed_factor.py b/stain_normalization/data/modification/hed_factor.py index 790982a..a5031c9 100644 --- a/stain_normalization/data/modification/hed_factor.py +++ b/stain_normalization/data/modification/hed_factor.py @@ -40,9 +40,9 @@ def apply(self, img: NDArray, **params) -> NDArray: e_factor = np.random.uniform(*self.e_range) hed_image = separate_stains(img, hed_from_rgb) - h = hed_image[:, :, 0] * h_factor - e = hed_image[:, :, 1] * e_factor - d = hed_image[:, :, 2] + h = np.clip(hed_image[:, :, 0] * h_factor, 0, 1) + e = np.clip(hed_image[:, :, 1] * e_factor, 0, 1) + d = hed_image[:, :, 2] # DAB channel unchanged modified_rgb = combine_stains(np.stack((h, e, d), axis=-1), rgb_from_hed) return modified_rgb diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 620e51f..ccaf08d 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -3,8 +3,14 @@ https://github.com/Po-Hsun-Su/pytorch-ssim . """ +""" +The SSIM is based on implementation from gaussian-splatting and slightly simplified (pre-computed windows and removal of unused arguments) +https://github.com/graphdeco-inria/gaussian-splatting/blob/472689c0dc70417448fb451bf529ae532d32c095/utils/loss_utils.py +""" + from math import exp + import torch import torch.nn as nn import torch.nn.functional as F @@ -12,39 +18,67 @@ class L1SSIMLoss(nn.Module): - def __init__(self, lambda_dssim: float = 0.6, lambda_gdl: float = 0.2): + def __init__(self, lambda_dssim: float = 0.6, lambda_l1: float = 0.35, lambda_lum: float = 0.35, lambda_gdl: float = 0.15): super().__init__() - self.lambda_dssim = lambda_dssim - self.lambda_gdl = lambda_gdl + self.lambda_dssim = lambda_dssim + self.lambda_l1 = lambda_l1 + self.lambda_lum = lambda_lum + self.lambda_gdl = lambda_gdl + + # precompute SSIM windows to avoid repetation + self.window_size = 11 + self.channel = 3 + self._1d_window = gaussian(self.window_size, 1.5).unsqueeze(1) + self._2d_window = self._1d_window.mm(self._1d_window.t()).float().unsqueeze(0).unsqueeze(0) + self.window = self._2d_window.expand(self.channel, 1, self.window_size, self.window_size).contiguous() def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tensor: - l1 = F.l1_loss(image, target_image, reduction="mean") - ssim_loss = 1.0 - ssim(image, target_image) - - gdl_loss = gradient_loss(image, target_image) # GDL for sharp edges - + if self.window.device != image.device: + self.window = self.window.to(image.device) + # L1 color loss + l1_loss = F.l1_loss(image, target_image, reduction="mean") + + # SSIM structural loss + ssim_loss = 1.0 - self._ssim(image, target_image, self.window) + + # Gradient loss for edges + gdl_loss = gradient_loss(image, target_image) + + # Luminance / brightness loss + lum_loss = luminance_loss(image, target_image) + + # total weighted loss total_loss = ( - (1.0 - self.lambda_dssim) * l1 + self.lambda_l1 * l1_loss + self.lambda_dssim * ssim_loss + self.lambda_gdl * gdl_loss + + self.lambda_lum * lum_loss ) - + return total_loss - -def gradient_loss(image, target_image): - def gradient(x): - dx = torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :]) # Horizontal gradient - dy = torch.abs(x[:, :, :, :-1] - x[:, :, :, 1:]) # Vertical gradient - return dx, dy - - image_dx, image_dy = gradient(image) - target_dx, target_dy = gradient(target_image) - - loss_x = F.l1_loss(image_dx, target_dx, reduction="mean") - loss_y = F.l1_loss(image_dy, target_dy, reduction="mean") - - return loss_x + loss_y + @torch.compile + def _ssim(self, img1, img2, window): + # Modified _ssim that uses pre-computed window + mu1 = F.conv2d(img1, window, padding=self.window_size // 2, groups=self.channel) + mu2 = F.conv2d(img2, window, padding=self.window_size // 2, groups=self.channel) + + mu1_sq = mu1.pow(2) + mu2_sq = mu2.pow(2) + mu1_mu2 = mu1 * mu2 + + sigma1_sq = F.conv2d(img1 * img1, window, padding=self.window_size // 2, groups=self.channel) - mu1_sq + sigma2_sq = F.conv2d(img2 * img2, window, padding=self.window_size // 2, groups=self.channel) - mu2_sq + sigma12 = F.conv2d(img1 * img2, window, padding=self.window_size // 2, groups=self.channel) - mu1_mu2 + + c1 = 0.01**2 + c2 = 0.03**2 + + ssim_map = ((2 * mu1_mu2 + c1) * (2 * sigma12 + c2)) / ( + (mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2) + ) + + return ssim_map.mean() def gaussian(window_size, sigma): @@ -57,53 +91,34 @@ def gaussian(window_size, sigma): return gauss / gauss.sum() -def create_window(window_size, channel): - _1d_window = gaussian(window_size, 1.5).unsqueeze(1) - _2d_window = _1d_window.mm(_1d_window.t()).float().unsqueeze(0).unsqueeze(0) - window = Variable( - _2d_window.expand(channel, 1, window_size, window_size).contiguous() - ) - return window +def luminance_loss( + pred: torch.Tensor, + target: torch.Tensor, + he_weights=[0.4, 0.1, 0.5]) -> torch.Tensor: + device = pred.device + weights = torch.tensor(he_weights, device=device).view(1, 3, 1, 1) + lum_pred = (pred * weights).sum(dim=1, keepdim=True) + lum_target = (target * weights).sum(dim=1, keepdim=True) -def ssim(img1, img2, window_size=11, size_average=True): - channel = img1.size(-3) - window = create_window(window_size, channel) + lum_loss = F.l1_loss(lum_pred, lum_target) + return lum_loss - if img1.is_cuda: - window = window.cuda(img1.get_device()) - window = window.type_as(img1) +def gradient_loss(image, target_image): + def gradient(x): + dx = torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :]) # Horizontal gradient + dy = torch.abs(x[:, :, :, :-1] - x[:, :, :, 1:]) # Vertical gradient + return dx, dy - return _ssim(img1, img2, window, window_size, channel, size_average) + image_dx, image_dy = gradient(image) + target_dx, target_dy = gradient(target_image) + loss_x = F.l1_loss(image_dx, target_dx, reduction="mean") + loss_y = F.l1_loss(image_dy, target_dy, reduction="mean") -def _ssim(img1, img2, window, window_size, channel, size_average=True): - mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel) - mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel) + return loss_x + loss_y - mu1_sq = mu1.pow(2) - mu2_sq = mu2.pow(2) - mu1_mu2 = mu1 * mu2 - sigma1_sq = ( - F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq - ) - sigma2_sq = ( - F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq - ) - sigma12 = ( - F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel) - - mu1_mu2 - ) - c1 = 0.01**2 - c2 = 0.03**2 - ssim_map = ((2 * mu1_mu2 + c1) * (2 * sigma12 + c2)) / ( - (mu1_sq + mu2_sq + c1) * (sigma1_sq + sigma2_sq + c2) - ) - if size_average: - return ssim_map.mean() - else: - return ssim_map.mean(1).mean(1).mean(1) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index b84372c..bce89f0 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -20,6 +20,8 @@ def __init__(self) -> None: self.val_metrics = MetricCollection( { "ssim": StructuralSimilarityIndexMeasure(), + "l1": MeanAbsoluteError() + } ) self.test_metrics = self.val_metrics.clone(prefix="test/") From 8142cc7aedbfe9b149ad6547e27a5e737e00de2a Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Sat, 29 Nov 2025 03:07:33 +0000 Subject: [PATCH 64/79] feat: update dataset slide paths --- configs/data/datasets/stain_normalization/test.yaml | 2 +- configs/data/datasets/stain_normalization/train.yaml | 2 +- configs/data/datasets/stain_normalization/val.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml index c55810c..9de1949 100644 --- a/configs/data/datasets/stain_normalization/test.yaml +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -3,4 +3,4 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TestDataset -uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - test"] +uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - test"] diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml index e0f2b43..013d820 100644 --- a/configs/data/datasets/stain_normalization/train.yaml +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -3,4 +3,4 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TrainDataset -uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - train"] +uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - train"] diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index b39e255..70842b5 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -3,5 +3,5 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TrainDataset -uris: ["mlflow-artifacts:/79/bc7dfc2258164cd292091c3056609277/artifacts/Stain Normalization - val"] +uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - val"] From b6341fe9d95b312be74cbc802311524de00350e2 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 02:12:55 +0100 Subject: [PATCH 65/79] fix: update dataset path --- configs/data/datasets/stain_normalization/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/data/datasets/stain_normalization/test.yaml b/configs/data/datasets/stain_normalization/test.yaml index 9de1949..be01300 100644 --- a/configs/data/datasets/stain_normalization/test.yaml +++ b/configs/data/datasets/stain_normalization/test.yaml @@ -3,4 +3,4 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TestDataset -uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - test"] +uris: ["mlflow-artifacts:/79/b987e3e7329342fe96906eb3b17bfcc4/artifacts/Stain Normalization - test (updated)"] From de4e59b674c5aa35892e5777f6bf8477318ac8e1 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 02:13:27 +0100 Subject: [PATCH 66/79] fix: update dataset path --- configs/data/datasets/stain_normalization/train.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/data/datasets/stain_normalization/train.yaml b/configs/data/datasets/stain_normalization/train.yaml index 013d820..6754a96 100644 --- a/configs/data/datasets/stain_normalization/train.yaml +++ b/configs/data/datasets/stain_normalization/train.yaml @@ -3,4 +3,4 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TrainDataset -uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - train"] +uris: ["mlflow-artifacts:/79/b987e3e7329342fe96906eb3b17bfcc4/artifacts/Stain Normalization - train (updated)"] From 3584636116573913755d48c1743027117c7bb9b3 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 02:13:49 +0100 Subject: [PATCH 67/79] fix: update dataset path --- configs/data/datasets/stain_normalization/val.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/data/datasets/stain_normalization/val.yaml b/configs/data/datasets/stain_normalization/val.yaml index 70842b5..4c4c13c 100644 --- a/configs/data/datasets/stain_normalization/val.yaml +++ b/configs/data/datasets/stain_normalization/val.yaml @@ -3,5 +3,5 @@ defaults: - /data/normalize@normalize: default _target_: stain_normalization.data.datasets.TrainDataset -uris: ["mlflow-artifacts:/79/5102491687c0413092f194280b9b4287/artifacts/Stain Normalization - val"] +uris: ["mlflow-artifacts:/79/b987e3e7329342fe96906eb3b17bfcc4/artifacts/Stain Normalization - val (updated)"] From b986f3c68f47d8c5a5aeede5f8e21bd0592260b0 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 02:19:15 +0100 Subject: [PATCH 68/79] chore: change batch size --- configs/default.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configs/default.yaml b/configs/default.yaml index 7ca7078..73fa375 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -45,9 +45,9 @@ trainer: - ${callbacks.analysis_export} data: - batch_size: 16 - num_workers: 8 - + batch_size: 64 + num_workers: 10 + metadata: user: xlopatka experiment_name: Stain-Normalization From 87dca95a6dcb5a4313bfe44c6d8ca241fdcba4a3 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 03:07:59 +0100 Subject: [PATCH 69/79] fix: correct python version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d2acf8d..8cba123 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "Stain Normalization" version = "0.1.0" authors = [{name = "Adam Lopatka"}] -requires-python = ">=3.11" +requires-python = ">=3.11,<3.13" readme = "README.md" license = { file = "LICENSE" } dependencies = [ From aaa8d3bf613712697257a1f2affae234d889fe9d Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 03:12:35 +0100 Subject: [PATCH 70/79] fix: add missing import --- stain_normalization/stain_normalization_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index bce89f0..c1f9da1 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -6,6 +6,7 @@ from torch.optim.optimizer import Optimizer from torchmetrics import MetricCollection from torchmetrics.image import StructuralSimilarityIndexMeasure +from torchmetrics.regression import MeanAbsoluteError from stain_normalization.modeling import L1SSIMLoss, UNet from stain_normalization.typing import Input, Outputs From d500e9150dd4b65d7165b41ce193a032a485e791 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 03:19:24 +0100 Subject: [PATCH 71/79] chore: change batch size --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index 73fa375..f177f56 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -45,7 +45,7 @@ trainer: - ${callbacks.analysis_export} data: - batch_size: 64 + batch_size: 32 num_workers: 10 metadata: From 04366653792ac3170436be5a9831225f22044ab1 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Thu, 4 Dec 2025 03:26:17 +0100 Subject: [PATCH 72/79] chore: change batch size --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index f177f56..dee8d7a 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -45,7 +45,7 @@ trainer: - ${callbacks.analysis_export} data: - batch_size: 32 + batch_size: 24 num_workers: 10 metadata: From 18962690899d70ea4acceb3232705a638e27f03b Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Fri, 5 Dec 2025 04:08:52 +0100 Subject: [PATCH 73/79] fix: adjust hyperparameters --- stain_normalization/modeling/l1ssim_loss.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index ccaf08d..03faacc 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -18,7 +18,7 @@ class L1SSIMLoss(nn.Module): - def __init__(self, lambda_dssim: float = 0.6, lambda_l1: float = 0.35, lambda_lum: float = 0.35, lambda_gdl: float = 0.15): + def __init__(self, lambda_dssim: float = 0.6, lambda_l1: float = 0.2, lambda_lum: float = 0.2, lambda_gdl: float = 0.1): super().__init__() self.lambda_dssim = lambda_dssim self.lambda_l1 = lambda_l1 @@ -94,7 +94,7 @@ def gaussian(window_size, sigma): def luminance_loss( pred: torch.Tensor, target: torch.Tensor, - he_weights=[0.4, 0.1, 0.5]) -> torch.Tensor: + he_weights=[0.33, 0.33, 0.33]) -> torch.Tensor: device = pred.device weights = torch.tensor(he_weights, device=device).view(1, 3, 1, 1) From 9c31f5a27bbea3b001d831d9a34f376edd51e228 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:51:27 +0100 Subject: [PATCH 74/79] chore: add checkpoint path --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index dee8d7a..49d76f4 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -9,7 +9,7 @@ defaults: seed: ${random_seed:} mode: fit -checkpoint: null +checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt callbacks: From 03791ffcfc48268b33cf6c8fcc37ec7853ffd060 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:41:30 +0100 Subject: [PATCH 75/79] feat: add brightness los Replaced luminance_loss with brightness_loss and added new brightness_loss function. --- stain_normalization/modeling/l1ssim_loss.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 03faacc..5a94a1f 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -45,7 +45,7 @@ def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tens gdl_loss = gradient_loss(image, target_image) # Luminance / brightness loss - lum_loss = luminance_loss(image, target_image) + lum_loss = brightness_loss(image, target_image) # total weighted loss total_loss = ( @@ -104,6 +104,14 @@ def luminance_loss( lum_loss = F.l1_loss(lum_pred, lum_target) return lum_loss +def brightness_loss(pred, target, he_weights=[0.33, 0.33, 0.33]): + weights = torch.tensor(he_weights, device=device).view(1, 3, 1) + + pred_mean = (pred * weights).mean(dim=[2, 3]) # [B, 3] + target_mean = (target * weights).mean(dim=[2, 3]) # [B, 3] + + return F.l1_loss(pred_mean, target_mean) + def gradient_loss(image, target_image): def gradient(x): dx = torch.abs(x[:, :, :-1, :] - x[:, :, 1:, :]) # Horizontal gradient From e6c19cb286083c0e73a4c510365315e419018706 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Mon, 8 Dec 2025 04:25:45 +0100 Subject: [PATCH 76/79] fix: add missed line Added device handling for brightness loss calculation. --- stain_normalization/modeling/l1ssim_loss.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 5a94a1f..aefec05 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -105,6 +105,7 @@ def luminance_loss( return lum_loss def brightness_loss(pred, target, he_weights=[0.33, 0.33, 0.33]): + device = pred.device weights = torch.tensor(he_weights, device=device).view(1, 3, 1) pred_mean = (pred * weights).mean(dim=[2, 3]) # [B, 3] From a6e54ee11bd9fe43bf0a643d0ded059b54e3dbe1 Mon Sep 17 00:00:00 2001 From: Adam L <55331774+LAdam-ix@users.noreply.github.com> Date: Mon, 8 Dec 2025 04:39:27 +0100 Subject: [PATCH 77/79] fix: dimension in brightness loss Updated brightness_loss function to maintain dimensions. --- stain_normalization/modeling/l1ssim_loss.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index aefec05..474fe14 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -106,10 +106,10 @@ def luminance_loss( def brightness_loss(pred, target, he_weights=[0.33, 0.33, 0.33]): device = pred.device - weights = torch.tensor(he_weights, device=device).view(1, 3, 1) + weights = torch.tensor(he_weights, device=device).view(1, 3, 1, 1) - pred_mean = (pred * weights).mean(dim=[2, 3]) # [B, 3] - target_mean = (target * weights).mean(dim=[2, 3]) # [B, 3] + pred_mean = (pred * weights).mean(dim=[2, 3], keepdim=True) + target_mean = (target * weights).mean(dim=[2, 3], keepdim=True) return F.l1_loss(pred_mean, target_mean) From 4bd95d461b010be593884688518dc645957041d1 Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni,cz> Date: Fri, 12 Dec 2025 00:37:13 +0000 Subject: [PATCH 78/79] chore: update checkpoint --- configs/default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/default.yaml b/configs/default.yaml index 49d76f4..03ba209 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -9,7 +9,7 @@ defaults: seed: ${random_seed:} mode: fit -checkpoint: mlflow-artifacts:/79/f75808f6e14344bb814e5c0659321054/artifacts/checkpoints/epoch=5-step=86273/checkpoint.ckpt +checkpoint: mlflow-artifacts:/79/978f5d5e54844be3b42509cce76793d7/artifacts/checkpoints/epoch=7-step=152375/checkpoint.ckpt callbacks: From 9f5ab8ab0907a0a035815a9a947f63dc28332ece Mon Sep 17 00:00:00 2001 From: Adam Lopatka <524733@mail.muni.cz> Date: Wed, 4 Mar 2026 05:45:56 +0100 Subject: [PATCH 79/79] feat: update analysis methods and WSI assembly --- .gitignore | 1 + analyze_dataset.py | 139 +++++++++ configs/default.yaml | 4 +- pdm.lock | 275 ++++++++++++++++-- preprocessing/mask_generator.py | 72 +---- preprocessing/tiler.py | 80 ++--- pyproject.toml | 2 +- stain_normalization/analysis/__init__.py | 20 ++ stain_normalization/analysis/analyzer.py | 189 ++++++++++++ stain_normalization/callbacks/__init__.py | 5 +- stain_normalization/callbacks/_base.py | 25 ++ .../callbacks/analysis_export.py | 157 ++-------- stain_normalization/callbacks/save_wsi.py | 56 ---- stain_normalization/callbacks/tiles_export.py | 72 +++-- .../callbacks/wsi_assembler.py | 232 +++++++++++++++ stain_normalization/data/data_module.py | 12 +- .../data/datasets/predict_dataset.py | 8 +- .../data/datasets/test_dataset.py | 8 +- .../data/datasets/train_dataset.py | 2 +- .../data/modification/exposure_adjustment.py | 2 + stain_normalization/metrics/__init__.py | 16 + stain_normalization/metrics/image_metrics.py | 56 ++++ stain_normalization/metrics/vector_metrics.py | 75 +++++ stain_normalization/modeling/l1ssim_loss.py | 26 +- .../stain_normalization_model.py | 15 +- stain_normalization/type_aliases.py | 13 + stain_normalization/typing.py | 11 - 27 files changed, 1138 insertions(+), 435 deletions(-) create mode 100644 analyze_dataset.py create mode 100644 stain_normalization/analysis/__init__.py create mode 100644 stain_normalization/analysis/analyzer.py create mode 100644 stain_normalization/callbacks/_base.py delete mode 100644 stain_normalization/callbacks/save_wsi.py create mode 100644 stain_normalization/callbacks/wsi_assembler.py create mode 100644 stain_normalization/metrics/__init__.py create mode 100644 stain_normalization/metrics/image_metrics.py create mode 100644 stain_normalization/metrics/vector_metrics.py create mode 100644 stain_normalization/type_aliases.py delete mode 100644 stain_normalization/typing.py diff --git a/.gitignore b/.gitignore index 1c12553..f1e9425 100644 --- a/.gitignore +++ b/.gitignore @@ -180,3 +180,4 @@ lightning_logs/ # Project /data +/demo_* \ No newline at end of file diff --git a/analyze_dataset.py b/analyze_dataset.py new file mode 100644 index 0000000..d10064f --- /dev/null +++ b/analyze_dataset.py @@ -0,0 +1,139 @@ +"""Compare a dataset against a reference image or between two datasets. + +Usage: + # Compare dataset against a reference image + python analyze_dataset.py --reference ref.png --uri "mlflow-artifacts:/79/..." + + # Compare two datasets (e.g. original vs normalized) + # Assume that both datasets have the same slides and tiles in the same order for paired comparison + python analyze_dataset.py --original "mlflow-artifacts:/79/...original" \ + --compared "mlflow-artifacts:/79/...normalized" + + # Subsample for faster run + python analyze_dataset.py --reference ref.png --uri "mlflow-artifacts:/79/..." --max-tiles 5000 +""" + +import argparse +from pathlib import Path + +import numpy as np +from PIL import Image +from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset +from tqdm import tqdm + +from stain_normalization.analysis import StainAnalyzer +from stain_normalization.analysis.report import REPORT_METRICS + + +def load_image(path: str | Path) -> np.ndarray: + return np.array(Image.open(path).convert("RGB")) + + +def iterate_tiles(slides, tiles): + """Yield (slide_name, tile_uint8, image_id) for each tile.""" + for _, slide in slides.iterrows(): + slide_name = Path(slide.path).stem + slide_tiles = tiles[tiles["slide_id"] == slide["id"]] + + if slide_tiles.empty: + continue + + dataset = OpenSlideTilesDataset( + slide_path=slide.path, + level=slide.level, + tile_extent_x=slide.tile_extent_x, + tile_extent_y=slide.tile_extent_y, + tiles=slide_tiles, + ) + + for i in range(len(dataset)): + image_id = f"{slide_name}_{slide_tiles.iloc[i]['x']}_{slide_tiles.iloc[i]['y']}" + yield slide_name, dataset[i], image_id + + +def run_reference_mode(args): + """Compare all tiles in a dataset against a single reference image.""" + ref_img = load_image(args.reference) + slides, tiles = MetaTiledSlides.load_slides_and_tiles(paths=[], uris=args.uri) + print(f"Dataset: {len(slides)} slides, {len(tiles)} tiles") + print(f"Reference: {args.reference}") + + if args.max_tiles and len(tiles) > args.max_tiles: + tiles = tiles.sample(n=args.max_tiles, random_state=42) + print(f"Subsampled to {args.max_tiles} tiles") + + analyzer = StainAnalyzer(reference=ref_img) + for _, tile, image_id in tqdm(iterate_tiles(slides, tiles), total=len(tiles)): + analyzer.compare(tile, image_id=image_id) + + return analyzer, len(analyzer.results) + + +def run_paired_mode(args): + """Compare matching tiles between two datasets (original vs compared).""" + orig_slides, orig_tiles = MetaTiledSlides.load_slides_and_tiles(paths=[], uris=args.original) + comp_slides, comp_tiles = MetaTiledSlides.load_slides_and_tiles(paths=[], uris=args.compared) + print(f"Original: {len(orig_slides)} slides, {len(orig_tiles)} tiles") + print(f"Compared: {len(comp_slides)} slides, {len(comp_tiles)} tiles") + + if args.max_tiles and len(orig_tiles) > args.max_tiles: + orig_tiles = orig_tiles.sample(n=args.max_tiles, random_state=42) + comp_tiles = comp_tiles.loc[orig_tiles.index] + print(f"Subsampled to {args.max_tiles} tile pairs") + + analyzer = StainAnalyzer() + orig_iter = iterate_tiles(orig_slides, orig_tiles) + comp_iter = iterate_tiles(comp_slides, comp_tiles) + + for (_, orig_tile, image_id), (_, comp_tile, _) in tqdm( + zip(orig_iter, comp_iter), total=len(orig_tiles) + ): + analyzer.compare(comp_tile, image_id=image_id, reference=orig_tile) + + return analyzer, len(analyzer.results) + + +def main(): + parser = argparse.ArgumentParser( + description="Dataset stain analysis", + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument("--output", default="./analysis_output", + help="Output directory (default: ./analysis_output)") + parser.add_argument("--max-tiles", type=int, default=None, + help="Limit number of tiles to analyze") + + # Mode 1: reference image + parser.add_argument("--reference", help="Path to reference image") + parser.add_argument("--uri", nargs="+", help="MLflow dataset URI(s) to analyze") + + # Mode 2: two datasets + parser.add_argument("--original", nargs="+", help="MLflow URI(s) for original dataset") + parser.add_argument("--compared", nargs="+", help="MLflow URI(s) for compared dataset") + + args = parser.parse_args() + + if args.reference and args.uri: + analyzer, count = run_reference_mode(args) + elif args.original and args.compared: + analyzer, count = run_paired_mode(args) + else: + parser.error("Use either (--reference + --uri) or (--original + --compared)") + + if analyzer is None: + return + + print(f"\nAnalyzed {count} tiles") + + analyzer.save_csv(args.output) + print(f"Results saved to: {args.output}/") + + stats = analyzer.get_statistics() + print("\nStatistics:") + for m in REPORT_METRICS: + if m in stats.columns: + print(f" {m:25s}: mean={stats[m]['mean']:.4f} std={stats[m]['std']:.4f}") + + +if __name__ == "__main__": + main() diff --git a/configs/default.yaml b/configs/default.yaml index 03ba209..1ccce2a 100644 --- a/configs/default.yaml +++ b/configs/default.yaml @@ -29,8 +29,8 @@ callbacks: output_dir: ${output_dir} normalization_config: ${data.test.normalize} - save_wsi: - _target_: stain_normalization.callbacks.SaveWSI + wsi_assembler: + _target_: stain_normalization.callbacks.WSIAssembler output_dir: ${output_dir} normalization_config: ${data.predict.normalize} diff --git a/pdm.lock b/pdm.lock index c53931a..80abec9 100644 --- a/pdm.lock +++ b/pdm.lock @@ -4,8 +4,14 @@ [metadata] groups = ["default", "dev"] strategy = ["inherit_metadata"] -lock_version = "4.4.2" -content_hash = "sha256:d9fbd23622ea9172dda4f468af65fdfdb8d70bea316aaed2d1898878e365ad57" +lock_version = "4.5.0" +content_hash = "sha256:474958a455ca9402a3ee96e32c7d3dacdbb307e643b91b2e8a4a80002a33d2b7" + +[[metadata.targets]] +requires_python = "==3.12.5" +platform = "manylinux_2_35_x86_64" +implementation = "cpython" +gil_disabled = false [[package]] name = "aiohappyeyeballs" @@ -13,6 +19,7 @@ version = "2.5.0" requires_python = ">=3.9" summary = "Happy Eyeballs for asyncio" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "aiohappyeyeballs-2.5.0-py3-none-any.whl", hash = "sha256:0850b580748c7071db98bffff6d4c94028d0d3035acc20fd721a0ce7e8cac35d"}, {file = "aiohappyeyeballs-2.5.0.tar.gz", hash = "sha256:18fde6204a76deeabc97c48bdd01d5801cfda5d6b9c8bbeb1aaaee9d648ca191"}, @@ -24,6 +31,7 @@ version = "3.11.13" requires_python = ">=3.9" summary = "Async http client/server framework (asyncio)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "aiohappyeyeballs>=2.3.0", "aiosignal>=1.1.2", @@ -91,6 +99,7 @@ version = "1.3.2" requires_python = ">=3.9" summary = "aiosignal: a list of registered asynchronous callbacks" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "frozenlist>=1.1.0", ] @@ -105,6 +114,7 @@ version = "0.0.23" requires_python = ">=3.9" summary = "High-performance image processing functions for deep learning and computer vision." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.24.4", "opencv-python-headless>=4.9.0.80", @@ -122,6 +132,7 @@ version = "2.0.5" requires_python = ">=3.9" summary = "Fast, flexible, and advanced augmentation library for deep learning, computer vision, and medical imaging. Albumentations offers a wide range of transformations for both 2D (images, masks, bboxes, keypoints) and 3D (volumes, volumetric masks, keypoints) data, with optimized performance and seamless integration into ML workflows." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "PyYAML", "albucore==0.0.23", @@ -141,6 +152,7 @@ version = "1.15.1" requires_python = ">=3.9" summary = "A database migration tool for SQLAlchemy." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "Mako", "SQLAlchemy>=1.4.0", @@ -157,6 +169,7 @@ version = "0.7.0" requires_python = ">=3.8" summary = "Reusable constraint types to use with typing.Annotated" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -167,6 +180,7 @@ name = "antlr4-python3-runtime" version = "4.9.3" summary = "ANTLR 4.9.3 runtime for Python 3.7" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, ] @@ -177,6 +191,7 @@ version = "25.1.0" requires_python = ">=3.8" summary = "Classes Without Boilerplate" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, @@ -188,6 +203,7 @@ version = "1.9.0" requires_python = ">=3.9" summary = "Fast, simple object-to-object and broadcast signaling" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, @@ -199,6 +215,7 @@ version = "5.5.2" requires_python = ">=3.7" summary = "Extensible memoizing collections and decorators" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, @@ -210,6 +227,7 @@ version = "2025.1.31" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -221,6 +239,7 @@ version = "1.17.1" requires_python = ">=3.8" summary = "Foreign Function Interface for Python calling C code." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "pycparser", ] @@ -268,6 +287,7 @@ version = "3.4.0" requires_python = ">=3.8" summary = "Validate configuration and produce human readable error messages." groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -279,6 +299,7 @@ version = "3.4.1" requires_python = ">=3.7" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, @@ -329,6 +350,7 @@ version = "8.1.8" requires_python = ">=3.7" summary = "Composable command line interface toolkit" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -340,6 +362,7 @@ version = "3.1.1" requires_python = ">=3.8" summary = "Pickler class to extend the standard pickle.Pickler functionality" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "cloudpickle-3.1.1-py3-none-any.whl", hash = "sha256:c8c5a44295039331ee9dad40ba100a9c7297b6f988e50e87ccdf3765a668350e"}, {file = "cloudpickle-3.1.1.tar.gz", hash = "sha256:b216fa8ae4019d5482a8ac3c95d8f6346115d8835911fd4aefd1a445e4242c64"}, @@ -351,6 +374,7 @@ version = "1.3.1" requires_python = ">=3.10" summary = "Python library for calculating contours of 2D quadrilateral grids" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.23", ] @@ -404,6 +428,7 @@ version = "0.12.1" requires_python = ">=3.8" summary = "Composable style cycles" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, @@ -415,6 +440,7 @@ version = "0.44.1" requires_python = ">=3.7" summary = "Databricks SDK for Python (Beta)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "google-auth~=2.0", "requests<3,>=2.28.1", @@ -430,6 +456,7 @@ version = "1.2.18" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" summary = "Python @deprecated decorator to deprecate old python classes, functions or methods." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "wrapt<2,>=1.10", ] @@ -443,6 +470,7 @@ name = "distlib" version = "0.3.9" summary = "Distribution utilities" groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, @@ -454,6 +482,7 @@ version = "7.1.0" requires_python = ">=3.8" summary = "A Python library for the Docker Engine API." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "requests>=2.26.0", "urllib3>=1.26.0", @@ -463,12 +492,24 @@ files = [ {file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"}, ] +[[package]] +name = "durationpy" +version = "0.10" +summary = "Module for converting between datetime.timedelta and Go's Duration strings." +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +files = [ + {file = "durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286"}, + {file = "durationpy-0.10.tar.gz", hash = "sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba"}, +] + [[package]] name = "filelock" version = "3.17.0" requires_python = ">=3.9" summary = "A platform independent file lock." groups = ["default", "dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338"}, {file = "filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e"}, @@ -480,6 +521,7 @@ version = "3.1.0" requires_python = ">=3.9" summary = "A simple framework for building complex web applications." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "Jinja2>=3.1.2", "Werkzeug>=3.1", @@ -498,6 +540,7 @@ version = "4.56.0" requires_python = ">=3.8" summary = "Tools to manipulate font files" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df"}, {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c"}, @@ -533,6 +576,7 @@ version = "1.5.0" requires_python = ">=3.8" summary = "A list-like structure which implements collections.abc.MutableSequence" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, @@ -589,6 +633,7 @@ version = "2025.2.0" requires_python = ">=3.8" summary = "File-system specification" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "fsspec-2025.2.0-py3-none-any.whl", hash = "sha256:9de2ad9ce1f85e1931858535bc882543171d197001a0a5eb2ddc04f1781ab95b"}, {file = "fsspec-2025.2.0.tar.gz", hash = "sha256:1c24b16eaa0a1798afa0337aa0db9b256718ab2a89c425371f5628d22c3b6afd"}, @@ -601,6 +646,7 @@ extras = ["http"] requires_python = ">=3.8" summary = "File-system specification" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "aiohttp!=4.0.0a0,!=4.0.0a1", "fsspec==2025.2.0", @@ -616,6 +662,7 @@ version = "4.0.12" requires_python = ">=3.7" summary = "Git Object Database" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "smmap<6,>=3.0.1", ] @@ -630,6 +677,7 @@ version = "3.1.44" requires_python = ">=3.7" summary = "GitPython is a Python library used to interact with Git repositories" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "gitdb<5,>=4.0.1", ] @@ -644,6 +692,7 @@ version = "2.38.0" requires_python = ">=3.7" summary = "Google Authentication Library" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "cachetools<6.0,>=2.0.0", "pyasn1-modules>=0.2.1", @@ -659,6 +708,7 @@ name = "graphene" version = "3.4.3" summary = "GraphQL Framework for Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "graphql-core<3.3,>=3.1", "graphql-relay<3.3,>=3.1", @@ -676,6 +726,7 @@ version = "3.2.6" requires_python = "<4,>=3.6" summary = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f"}, {file = "graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab"}, @@ -687,6 +738,7 @@ version = "3.2.0" requires_python = ">=3.6,<4" summary = "Relay library for graphql-core" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "graphql-core<3.3,>=3.2", ] @@ -701,7 +753,7 @@ version = "3.1.1" requires_python = ">=3.7" summary = "Lightweight in-process concurrent programming" groups = ["default"] -marker = "(platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_version < \"3.14\"" +marker = "(platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_full_version == \"3.12.5\"" files = [ {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, @@ -746,7 +798,7 @@ version = "23.0.0" requires_python = ">=3.7" summary = "WSGI HTTP Server for UNIX" groups = ["default"] -marker = "platform_system != \"Windows\"" +marker = "platform_system != \"Windows\" and python_full_version == \"3.12.5\"" dependencies = [ "packaging", ] @@ -760,6 +812,7 @@ name = "hydra-core" version = "1.3.2" summary = "A framework for elegantly configuring complex applications" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "antlr4-python3-runtime==4.9.*", "omegaconf<2.4,>=2.2", @@ -776,6 +829,7 @@ version = "2.6.8" requires_python = ">=3.9" summary = "File identification library for Python" groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "identify-2.6.8-py2.py3-none-any.whl", hash = "sha256:83657f0f766a3c8d0eaea16d4ef42494b39b34629a4b3192a9d020d349b3e255"}, {file = "identify-2.6.8.tar.gz", hash = "sha256:61491417ea2c0c5c670484fd8abbb34de34cdae1e5f39a73ee65e48e4bb663fc"}, @@ -787,6 +841,7 @@ version = "3.10" requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -798,6 +853,7 @@ version = "2.37.0" requires_python = ">=3.9" summary = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy", "pillow>=8.3.2", @@ -813,6 +869,7 @@ version = "8.5.0" requires_python = ">=3.8" summary = "Read metadata from Python packages" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "zipp>=3.20", ] @@ -827,6 +884,7 @@ version = "2.2.0" requires_python = ">=3.8" summary = "Safely pass data to untrusted environments and back." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, @@ -838,6 +896,7 @@ version = "3.1.6" requires_python = ">=3.7" summary = "A very fast and expressive template engine." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "MarkupSafe>=2.0", ] @@ -852,6 +911,7 @@ version = "1.4.2" requires_python = ">=3.8" summary = "Lightweight pipelining with Python functions" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, @@ -863,6 +923,7 @@ version = "4.23.0" requires_python = ">=3.8" summary = "An implementation of JSON Schema validation for Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "attrs>=22.2.0", "jsonschema-specifications>=2023.03.6", @@ -880,6 +941,7 @@ version = "2024.10.1" requires_python = ">=3.9" summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "referencing>=0.31.0", ] @@ -894,6 +956,7 @@ version = "1.4.8" requires_python = ">=3.10" summary = "A fast implementation of the Cassowary constraint solver" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84"}, {file = "kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561"}, @@ -956,12 +1019,37 @@ files = [ {file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"}, ] +[[package]] +name = "kubernetes" +version = "34.1.0" +requires_python = ">=3.6" +summary = "Kubernetes python client" +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +dependencies = [ + "certifi>=14.05.14", + "durationpy>=0.7", + "google-auth>=1.0.1", + "python-dateutil>=2.5.3", + "pyyaml>=5.4.1", + "requests", + "requests-oauthlib", + "six>=1.9.0", + "urllib3<2.4.0,>=1.24.2", + "websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0", +] +files = [ + {file = "kubernetes-34.1.0-py2.py3-none-any.whl", hash = "sha256:bffba2272534e224e6a7a74d582deb0b545b7c9879d2cd9e4aae9481d1f2cc2a"}, + {file = "kubernetes-34.1.0.tar.gz", hash = "sha256:8fe8edb0b5d290a2f3ac06596b23f87c658977d46b5f8df9d0f4ea83d0003912"}, +] + [[package]] name = "lazy-loader" version = "0.4" requires_python = ">=3.7" summary = "Makes it easy to load subpackages and functions on demand." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "packaging", ] @@ -976,6 +1064,7 @@ version = "2.5.0.post0" requires_python = ">=3.9" summary = "The Deep Learning framework to train, deploy, and ship AI products Lightning fast." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "PyYAML<8.0,>=5.4", "fsspec[http]<2026.0,>=2022.5.0", @@ -998,6 +1087,7 @@ version = "0.13.1" requires_python = ">=3.9" summary = "Lightning toolbox for across the our ecosystem." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "packaging>=17.1", "setuptools", @@ -1014,6 +1104,7 @@ version = "1.3.9" requires_python = ">=3.8" summary = "A super-fast templating language that borrows the best ideas from the existing templating languages." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "MarkupSafe>=0.9.2", ] @@ -1028,6 +1119,7 @@ version = "3.7" requires_python = ">=3.8" summary = "Python implementation of John Gruber's Markdown." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -1039,6 +1131,7 @@ version = "3.0.2" requires_python = ">=3.9" summary = "Safely add untrusted strings to HTML/XML markup." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, @@ -1089,6 +1182,7 @@ version = "3.10.1" requires_python = ">=3.10" summary = "Python plotting package" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "contourpy>=1.0.1", "cycler>=0.10", @@ -1134,6 +1228,7 @@ version = "2.20.3" requires_python = ">=3.9" summary = "MLflow is an open source platform for the complete machine learning lifecycle" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "Flask<4", "Jinja2<4,>=2.11; platform_system != \"Windows\"", @@ -1162,6 +1257,7 @@ version = "2.20.3" requires_python = ">=3.9" summary = "MLflow is an open source platform for the complete machine learning lifecycle" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "cachetools<6,>=5.0.0", "click<9,>=7.0", @@ -1189,7 +1285,7 @@ name = "mpmath" version = "1.3.0" summary = "Python library for arbitrary-precision floating-point arithmetic" groups = ["default"] -marker = "python_version >= \"3.9\"" +marker = "python_full_version == \"3.12.5\"" files = [ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, @@ -1201,6 +1297,7 @@ version = "1.1.0" requires_python = ">=3.8" summary = "MessagePack serializer" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, @@ -1244,6 +1341,7 @@ version = "6.1.0" requires_python = ">=3.8" summary = "multidict implementation" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, @@ -1300,6 +1398,7 @@ version = "1.15.0" requires_python = ">=3.9" summary = "Optional static typing for Python" groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "mypy-extensions>=1.0.0", "typing-extensions>=4.6.0", @@ -1333,6 +1432,7 @@ version = "1.0.0" requires_python = ">=3.5" summary = "Type system extensions for programs checked with the mypy type checker." groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -1344,6 +1444,7 @@ version = "3.4.2" requires_python = ">=3.10" summary = "Python package for creating and manipulating graphs and networks" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, @@ -1355,6 +1456,7 @@ version = "1.9.1" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Node.js virtual environment builder" groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1366,6 +1468,7 @@ version = "2.2.3" requires_python = ">=3.10" summary = "Fundamental package for array computing in Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "numpy-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:16372619ee728ed67a2a606a614f56d3eabc5b86f8b615c79d01957062826ca8"}, {file = "numpy-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5521a06a3148686d9269c53b09f7d399a5725c47bbb5b35747e1cb76326b714b"}, @@ -1416,7 +1519,7 @@ version = "12.4.5.8" requires_python = ">=3" summary = "CUBLAS native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3"}, {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, @@ -1429,7 +1532,7 @@ version = "12.4.127" requires_python = ">=3" summary = "CUDA profiling tools runtime libs." groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a"}, {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, @@ -1442,7 +1545,7 @@ version = "12.4.127" requires_python = ">=3" summary = "NVRTC native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198"}, {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, @@ -1455,7 +1558,7 @@ version = "12.4.127" requires_python = ">=3" summary = "CUDA Runtime native Libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3"}, {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, @@ -1468,7 +1571,7 @@ version = "9.1.0.70" requires_python = ">=3" summary = "cuDNN runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" dependencies = [ "nvidia-cublas-cu12", ] @@ -1483,7 +1586,7 @@ version = "11.2.1.3" requires_python = ">=3" summary = "CUFFT native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, @@ -1496,7 +1599,7 @@ version = "10.3.5.147" requires_python = ">=3" summary = "CURAND native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9"}, {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, @@ -1509,7 +1612,7 @@ version = "11.6.1.9" requires_python = ">=3" summary = "CUDA solver native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" dependencies = [ "nvidia-cublas-cu12", "nvidia-cusparse-cu12", @@ -1527,7 +1630,7 @@ version = "12.3.1.170" requires_python = ">=3" summary = "CUSPARSE native runtime libraries" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" dependencies = [ "nvidia-nvjitlink-cu12", ] @@ -1542,7 +1645,7 @@ name = "nvidia-cusparselt-cu12" version = "0.6.2" summary = "NVIDIA cuSPARSELt" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:067a7f6d03ea0d4841c85f0c6f1991c5dda98211f6302cb83a4ab234ee95bef8"}, {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:df2c24502fd76ebafe7457dbc4716b2fec071aabaed4fb7691a201cde03704d9"}, @@ -1555,7 +1658,7 @@ version = "2.21.5" requires_python = ">=3" summary = "NVIDIA Collective Communication Library (NCCL) Runtime" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, ] @@ -1566,7 +1669,7 @@ version = "12.4.127" requires_python = ">=3" summary = "Nvidia JIT LTO Library" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4abe7fef64914ccfa909bc2ba39739670ecc9e820c83ccc7a6ed414122599b83"}, {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"}, @@ -1579,19 +1682,32 @@ version = "12.4.127" requires_python = ">=3" summary = "NVIDIA Tools Extension" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3"}, {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, ] +[[package]] +name = "oauthlib" +version = "3.3.1" +requires_python = ">=3.8" +summary = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +files = [ + {file = "oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1"}, + {file = "oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9"}, +] + [[package]] name = "omegaconf" version = "2.3.0" requires_python = ">=3.6" summary = "A flexible configuration library" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "PyYAML>=5.1.0", "antlr4-python3-runtime==4.9.*", @@ -1607,6 +1723,7 @@ version = "4.11.0.86" requires_python = ">=3.6" summary = "Wrapper package for OpenCV python bindings." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.17.0; python_version >= \"3.7\"", "numpy>=1.17.3; python_version >= \"3.8\"", @@ -1631,6 +1748,7 @@ version = "4.0.0.6" requires_python = ">=3.8" summary = "Binary build of OpenSlide" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "openslide-bin-4.0.0.6.tar.gz", hash = "sha256:baca4a590cb15c8685f1ee1905d496bb0a23468b969f7066a2126c24c9e9ef39"}, {file = "openslide_bin-4.0.0.6-py3-none-macosx_11_0_universal2.whl", hash = "sha256:f9c4ed0da275202dce531b163d92e1b860d215e779e7620fdd0dd92b7c40764b"}, @@ -1645,6 +1763,7 @@ version = "1.4.1" requires_python = ">=3.8" summary = "Python interface to OpenSlide" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "Pillow", ] @@ -1662,6 +1781,7 @@ version = "1.30.0" requires_python = ">=3.8" summary = "OpenTelemetry Python API" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "deprecated>=1.2.6", "importlib-metadata<=8.5.0,>=6.0", @@ -1677,6 +1797,7 @@ version = "1.30.0" requires_python = ">=3.8" summary = "OpenTelemetry Python SDK" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "opentelemetry-api==1.30.0", "opentelemetry-semantic-conventions==0.51b0", @@ -1693,6 +1814,7 @@ version = "0.51b0" requires_python = ">=3.8" summary = "OpenTelemetry Semantic Conventions" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "deprecated>=1.2.6", "opentelemetry-api==1.30.0", @@ -1708,6 +1830,7 @@ version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1719,6 +1842,7 @@ version = "2.2.3" requires_python = ">=3.9" summary = "Powerful data structures for data analysis, time series, and statistics" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.26.0; python_version >= \"3.12\"", "python-dateutil>=2.8.2", @@ -1762,6 +1886,7 @@ version = "11.1.0" requires_python = ">=3.9" summary = "Python Imaging Library (Fork)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457"}, {file = "pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35"}, @@ -1813,6 +1938,7 @@ version = "1.5.5" requires_python = ">=3.3,<4.0" summary = "Interface Python with pkg-config" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pkgconfig-1.5.5-py3-none-any.whl", hash = "sha256:d20023bbeb42ee6d428a0fac6e0904631f545985a10cdd71a20aa58bc47a4209"}, {file = "pkgconfig-1.5.5.tar.gz", hash = "sha256:deb4163ef11f75b520d822d9505c1f462761b4309b1bb713d08689759ea8b899"}, @@ -1824,6 +1950,7 @@ version = "4.3.6" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -1835,6 +1962,7 @@ version = "4.1.0" requires_python = ">=3.9" summary = "A framework for managing and maintaining multi-language pre-commit hooks." groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "cfgv>=2.0.0", "identify>=1.0.0", @@ -1853,6 +1981,7 @@ version = "0.3.0" requires_python = ">=3.9" summary = "Accelerated property cache" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, @@ -1928,6 +2057,7 @@ version = "5.29.3" requires_python = ">=3.8" summary = "" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888"}, {file = "protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a"}, @@ -1944,6 +2074,7 @@ version = "19.0.1" requires_python = ">=3.9" summary = "Python library for Apache Arrow" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pyarrow-19.0.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:cc55d71898ea30dc95900297d191377caba257612f384207fe9f8293b5850f90"}, {file = "pyarrow-19.0.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:7a544ec12de66769612b2d6988c36adc96fb9767ecc8ee0a4d270b10b1c51e00"}, @@ -1981,6 +2112,7 @@ version = "0.6.1" requires_python = ">=3.8" summary = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, @@ -1992,6 +2124,7 @@ version = "0.4.1" requires_python = ">=3.8" summary = "A collection of ASN.1-based protocols modules" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "pyasn1<0.7.0,>=0.4.6", ] @@ -2006,6 +2139,7 @@ version = "2.22" requires_python = ">=3.8" summary = "C parser in Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -2017,6 +2151,7 @@ version = "2.10.6" requires_python = ">=3.8" summary = "Data validation using Python type hints" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "annotated-types>=0.6.0", "pydantic-core==2.27.2", @@ -2033,6 +2168,7 @@ version = "2.27.2" requires_python = ">=3.8" summary = "Core functionality for Pydantic validation and serialization" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "typing-extensions!=4.7.0,>=4.6.0", ] @@ -2088,6 +2224,7 @@ version = "3.2.1" requires_python = ">=3.9" summary = "pyparsing module - Classes and methods to define and execute parsing grammars" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, @@ -2099,6 +2236,7 @@ version = "2.9.0.post0" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Extensions to the standard Python datetime module" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "six>=1.5", ] @@ -2113,6 +2251,7 @@ version = "2.5.0.post0" requires_python = ">=3.9" summary = "PyTorch Lightning is the lightweight PyTorch wrapper for ML researchers. Scale your models. Write less boilerplate." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "PyYAML>=5.4", "fsspec[http]>=2022.5.0", @@ -2133,6 +2272,7 @@ name = "pytz" version = "2025.1" summary = "World timezone definitions, modern and historical" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, @@ -2143,6 +2283,7 @@ name = "pyvips" version = "2.2.3" summary = "binding for the libvips image processing library, API mode" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "cffi>=1.0.0", "pkgconfig", @@ -2157,6 +2298,7 @@ version = "6.0.2" requires_python = ">=3.8" summary = "YAML parser and emitter for Python" groups = ["default", "dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, @@ -2188,6 +2330,20 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "rationai-kube-jobs" +version = "0.4.0" +requires_python = ">=3.12" +git = "ssh://git@gitlab.ics.muni.cz/rationai/infrastructure/kube-jobs" +revision = "d7a082700a1234f714c0ca3d3d2bf0b9f957c87d" +summary = "A simple CLI tool for managing Kubernetes jobs." +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +dependencies = [ + "click>=8.1.7", + "kubernetes>=31.0.0", +] + [[package]] name = "rationai-masks" version = "1.1.0" @@ -2196,6 +2352,7 @@ git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/masks.git revision = "91b2a2a2e288417e9bdd0fd83ddd4f04af449dec" summary = "" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.9.0", "openslide-python>=1.3.1", @@ -2215,6 +2372,7 @@ git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/mlkit.git revision = "233ead782353b3f23eee75702576f5c004cf300e" summary = "" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "GitPython>=3.1.43", "hydra-core>=1.3.2", @@ -2233,6 +2391,7 @@ git = "https://git@gitlab.ics.muni.cz/rationai/digital-pathology/libraries/stain revision = "bd1d704d86468a42d2321e9041c746215255c099" summary = "" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy>=1.26.4", "pillow>=10.3.0", @@ -2247,6 +2406,7 @@ git = "https://gitlab.ics.muni.cz/rationai/digital-pathology/libraries/tiling.gi revision = "9096ada81542c172908dff5b2766cf729786471b" summary = "" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "mlflow>=2.15.1", "numpy>=1.9.0", @@ -2264,6 +2424,7 @@ version = "2.43.0" requires_python = ">=3.9" summary = "Ray provides a simple, universal API for building distributed applications." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "aiosignal", "click>=7.0", @@ -2295,6 +2456,7 @@ version = "0.36.2" requires_python = ">=3.9" summary = "JSON Referencing + Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "attrs>=22.2.0", "rpds-py>=0.7.0", @@ -2311,6 +2473,7 @@ version = "2.32.3" requires_python = ">=3.8" summary = "Python HTTP for Humans." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "certifi>=2017.4.17", "charset-normalizer<4,>=2", @@ -2322,12 +2485,29 @@ files = [ {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +requires_python = ">=3.4" +summary = "OAuthlib authentication support for Requests." +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +dependencies = [ + "oauthlib>=3.0.0", + "requests>=2.0.0", +] +files = [ + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, +] + [[package]] name = "rpds-py" version = "0.23.1" requires_python = ">=3.9" summary = "Python bindings to Rust's persistent data structures (rpds)" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "rpds_py-0.23.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590"}, {file = "rpds_py-0.23.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4"}, @@ -2390,6 +2570,7 @@ version = "4.9" requires_python = ">=3.6,<4" summary = "Pure-Python RSA implementation" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "pyasn1>=0.1.3", ] @@ -2404,6 +2585,7 @@ version = "0.9.9" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367"}, {file = "ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7"}, @@ -2431,6 +2613,7 @@ version = "0.25.2" requires_python = ">=3.10" summary = "Image processing in Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "imageio!=2.35.0,>=2.33", "lazy-loader>=0.4", @@ -2467,6 +2650,7 @@ version = "1.6.1" requires_python = ">=3.9" summary = "A set of python modules for machine learning and data mining" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "joblib>=1.2.0", "numpy>=1.19.5", @@ -2502,6 +2686,7 @@ version = "1.15.2" requires_python = ">=3.10" summary = "Fundamental algorithms for scientific computing in Python" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy<2.5,>=1.23.5", ] @@ -2545,12 +2730,30 @@ files = [ {file = "scipy-1.15.2.tar.gz", hash = "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec"}, ] +[[package]] +name = "seaborn" +version = "0.13.2" +requires_python = ">=3.8" +summary = "Statistical data visualization" +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +dependencies = [ + "matplotlib!=3.6.1,>=3.4", + "numpy!=1.24.0,>=1.20", + "pandas>=1.2", +] +files = [ + {file = "seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987"}, + {file = "seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7"}, +] + [[package]] name = "setuptools" version = "75.8.2" requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "setuptools-75.8.2-py3-none-any.whl", hash = "sha256:558e47c15f1811c1fa7adbd0096669bf76c1d3f433f58324df69f3f5ecac4e8f"}, {file = "setuptools-75.8.2.tar.gz", hash = "sha256:4880473a969e5f23f2a2be3646b2dfd84af9028716d398e46192f84bc36900d2"}, @@ -2561,6 +2764,7 @@ name = "simsimd" version = "6.2.1" summary = "Portable mixed-precision BLAS-like vector math library for x86 and ARM" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "simsimd-6.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e9614309af75be4d08a051dc61ed5cf41b5239b8303b37dc2f9c8a7223534392"}, {file = "simsimd-6.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea4f0f68be5f85bbcf4322bfdd1b449176cf5fdd99960c546514457635632443"}, @@ -2622,6 +2826,7 @@ version = "1.17.0" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" summary = "Python 2 and 3 compatibility utilities" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -2633,6 +2838,7 @@ version = "5.0.2" requires_python = ">=3.7" summary = "A pure Python implementation of a sliding window memory map manager" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"}, {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, @@ -2644,6 +2850,7 @@ version = "2.0.38" requires_python = ">=3.7" summary = "Database Abstraction Library" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "greenlet!=0.4.17; (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\") and python_version < \"3.14\"", "typing-extensions>=4.6.0", @@ -2683,6 +2890,7 @@ version = "0.5.3" requires_python = ">=3.8" summary = "A non-validating SQL parser." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, @@ -2693,6 +2901,7 @@ name = "stringzilla" version = "3.12.2" summary = "SIMD-accelerated string search, sort, hashes, fingerprints, & edit distances" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "stringzilla-3.12.2-cp311-cp311-macosx_10_11_universal2.whl", hash = "sha256:78363cfa4ac9a232b728dd40f59b0d8b0ef31629708751fbdee9c0117d06500f"}, {file = "stringzilla-3.12.2-cp311-cp311-macosx_10_11_x86_64.whl", hash = "sha256:0ad4ae468411348532fd7cb35c7f0207b37f1a40fc7d7882f63e7b0cfc8ec117"}, @@ -2754,7 +2963,7 @@ version = "1.13.1" requires_python = ">=3.8" summary = "Computer algebra system (CAS) in Python" groups = ["default"] -marker = "python_version >= \"3.9\"" +marker = "python_full_version == \"3.12.5\"" dependencies = [ "mpmath<1.4,>=1.1.0", ] @@ -2769,6 +2978,7 @@ version = "3.5.0" requires_python = ">=3.8" summary = "threadpoolctl" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, @@ -2780,6 +2990,7 @@ version = "2025.2.18" requires_python = ">=3.10" summary = "Read and write TIFF files" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy", ] @@ -2794,6 +3005,7 @@ version = "2.6.0" requires_python = ">=3.9.0" summary = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "filelock", "fsspec", @@ -2838,6 +3050,7 @@ version = "1.6.2" requires_python = ">=3.9" summary = "PyTorch native Metrics" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "lightning-utilities>=0.8.0", "numpy>1.20.0", @@ -2855,6 +3068,7 @@ version = "0.21.0" requires_python = ">=3.9" summary = "image and video datasets and models for torch deep learning" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "numpy", "pillow!=8.3.*,>=5.3.0", @@ -2881,6 +3095,7 @@ version = "4.67.1" requires_python = ">=3.7" summary = "Fast, Extensible Progress Meter" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -2891,7 +3106,7 @@ name = "triton" version = "3.2.0" summary = "A language and compiler for custom Deep Learning operations" groups = ["default"] -marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\"" +marker = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_full_version == \"3.12.5\"" files = [ {file = "triton-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8009a1fb093ee8546495e96731336a33fb8856a38e45bb4ab6affd6dbc3ba220"}, {file = "triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d9b215efc1c26fa7eefb9a157915c92d52e000d2bf83e5f69704047e63f125c"}, @@ -2904,6 +3119,7 @@ version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" groups = ["default", "dev"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2915,6 +3131,7 @@ version = "2025.1" requires_python = ">=2" summary = "Provider of IANA time zone data" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, @@ -2926,6 +3143,7 @@ version = "2.3.0" requires_python = ">=3.9" summary = "HTTP library with thread-safe connection pooling, file post, and more." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -2937,6 +3155,7 @@ version = "20.29.3" requires_python = ">=3.8" summary = "Virtual Python Environment builder" groups = ["dev"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", @@ -2947,12 +3166,25 @@ files = [ {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, ] +[[package]] +name = "websocket-client" +version = "1.9.0" +requires_python = ">=3.9" +summary = "WebSocket client for Python with low level API options" +groups = ["default"] +marker = "python_full_version == \"3.12.5\"" +files = [ + {file = "websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef"}, + {file = "websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98"}, +] + [[package]] name = "werkzeug" version = "3.1.3" requires_python = ">=3.9" summary = "The comprehensive WSGI web application library." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "MarkupSafe>=2.1.1", ] @@ -2967,6 +3199,7 @@ version = "1.17.2" requires_python = ">=3.8" summary = "Module for decorators, wrappers and monkey patching." groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, @@ -3022,6 +3255,7 @@ version = "1.18.3" requires_python = ">=3.9" summary = "Yet another URL library" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" dependencies = [ "idna>=2.0", "multidict>=4.0", @@ -3086,6 +3320,7 @@ version = "3.21.0" requires_python = ">=3.9" summary = "Backport of pathlib-compatible object wrapper for zip files" groups = ["default"] +marker = "python_full_version == \"3.12.5\"" files = [ {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, diff --git a/preprocessing/mask_generator.py b/preprocessing/mask_generator.py index 0c0bc98..234f846 100644 --- a/preprocessing/mask_generator.py +++ b/preprocessing/mask_generator.py @@ -13,8 +13,8 @@ # Prospective test cases # Prospective tumor cases -SLIDES_PATH = "/mnt/data/scans/AI scans/Prostata/" -MASK_DEST = "./data/tissue_masks" +SLIDES_PATH = "/mnt/data/MOU/prostate/tile_level_annotations/" +MASK_DEST = "./mask/tissue_masks" LEVEL = 3 @@ -28,75 +28,17 @@ def process_slide(slide_path: Path) -> None: yres = 1000 / (float(slide.properties[PROPERTY_NAME_MPP_Y]) * downsample) slide = pyvips.Image.new_from_file(slide_path, level=LEVEL) - mask = tissue_mask(slide) + mask = tissue_mask(slide, xres) mask_path = Path(MASK_DEST, f"{Path(slide_path).stem}.tiff") mask_path.parent.mkdir(exist_ok=True, parents=True) - write_big_tiff(mask, path=mask_path, xres=xres, yres=yres) + write_big_tiff(mask, path=mask_path, mpp_x=xres, mpp_y=yres) -BROKEN_SLIDES = { - "P-2016_3829-04-1.mrxs", - "P-2016_3732-06-1.mrxs", - "P-2016_3732-03-1.mrxs", - "P-2016_3760-06-1.mrxs", - "P-2016_3629-13-1.mrxs", - "P-2016_3926-03-1.mrxs", - "P-2016_3852-02-1.mrxs", - "P-2016_3988-07-1.mrxs", - "P-2016_3852-01-1.mrxs", - "P-2016_3851-02-1.mrxs", - "P-2016_3629-12-1.mrxs", - "P-2016_3667-10-0.mrxs", - "P-2016_3606-04-1.mrxs", - "P-2016_3597-10-1.mrxs", - "P-2016_3988-10-1.mrxs", - "P-2016_3829-01-1.mrxs", - "P-2016_3926-02-1.mrxs", - "P-2019_3025-03-1.mrxs", - "P-2016_3760-04-1.mrxs", - "P-2016_3732-04-1.mrxs", - "P-2016_3667-09-1.mrxs", - "P-2019_3292-06-1.mrxs", - "P-2016_3988-02-1.mrxs", - "P-2016_3667-11-0.mrxs", - "P-2016_3606-05-1.mrxs", - "P-2016_3851-09-1.mrxs", - "P-2016_3627-09-1.mrxs", - "P-2016_3606-03-1.mrxs", - "P-2016_3627-10-1.mrxs", - "P-2016_3852-03-1.mrxs", - "P-2016_3851-07-1.mrxs", - "P-2016_3829-03-1.mrxs", - "P-2016_3627-06-1.mrxs", - "P-2016_3597-09-1.mrxs", - "P-2016_3926-01-1.mrxs", - "P-2016_3629-11-1.mrxs", - "P-2016_3760-03-1.mrxs", -} - def main() -> None: - folders = [ - # "archive tumor cases", #DONE - # "archive negative cases", # DONE - # "Prospective negative cases", #DONE - # "Prospective test cases", # DONE - # "Prospective tumor cases" # DONE - ] - - for folder in folders: - slides = [] - for slide in Path(SLIDES_PATH, folder).rglob("*.mrxs"): - if slide.name in BROKEN_SLIDES: - continue - slides.append(slide) - # slides.extend(list(Path(SLIDES_PATH, folder).rglob("*.mrxs"))) - - # slides = list(Path(SLIDES_PATH).rglob("*.mrxs")) - # process_slide(slides[0]) - process_items(slides, process_item=process_slide) - print(f"Processed {len(slides)} slides from {folder} folder") - + slides = list(Path(SLIDES_PATH).rglob("*.mrxs")) + # process_slide(slides[0]) + process_items(slides, process_item=process_slide) if __name__ == "__main__": main() diff --git a/preprocessing/tiler.py b/preprocessing/tiler.py index 55c5cda..f1b1561 100644 --- a/preprocessing/tiler.py +++ b/preprocessing/tiler.py @@ -10,8 +10,9 @@ from sklearn.model_selection import train_test_split -SLIDES_PATH = "/mnt/data/scans/AI scans/Prostata/" -TISSUE_MASKS_PATH = "./data/tissue_masks" +SLIDES_PATH = "/mnt/data/MOU/prostate/tile_level_annotations/" +TISSUE_MASKS_PATH = "./mask/tissue_masks" +TISSUE_MASKS_PATH = "/home/jovyan/staining/demo_data/masks" # level avg_mpp_x avg_mpp_y @@ -25,19 +26,20 @@ # 7 29.936095 29.994331 # 8 59.872189 59.988661 # 9 119.744379 119.97732 -SlideMPP = 0.46 +SlideMPP = 0.23 source = OpenSlideTileSource(mpp=SlideMPP, tile_extent=512, stride=256) -TISSUE_PERCENTAGE = 0.5 +MIN_TISSUE_PERCENTAGE = 0.0 class TissueMask(PyvipsMask[TileMetadata]): def forward_tile( self, tile_labels: TileMetadata, class_overlaps: dict[int, float] ) -> TileMetadata | None: - if class_overlaps.get(0, 0) > TISSUE_PERCENTAGE: + tissue = 1.0 - class_overlaps.get(0, 0) + if tissue <= MIN_TISSUE_PERCENTAGE: return None return tile_labels @@ -57,62 +59,11 @@ def handler(slide_path: Path) -> TiledSlideMetadata: return slide, tiles -BROKEN_SLIDES = { - "P-2016_3829-04-1.mrxs", - "P-2016_3732-06-1.mrxs", - "P-2016_3732-03-1.mrxs", - "P-2016_3760-06-1.mrxs", - "P-2016_3629-13-1.mrxs", - "P-2016_3926-03-1.mrxs", - "P-2016_3852-02-1.mrxs", - "P-2016_3988-07-1.mrxs", - "P-2016_3852-01-1.mrxs", - "P-2016_3851-02-1.mrxs", - "P-2016_3629-12-1.mrxs", - "P-2016_3667-10-0.mrxs", - "P-2016_3606-04-1.mrxs", - "P-2016_3597-10-1.mrxs", - "P-2016_3988-10-1.mrxs", - "P-2016_3829-01-1.mrxs", - "P-2016_3926-02-1.mrxs", - "P-2019_3025-03-1.mrxs", - "P-2016_3760-04-1.mrxs", - "P-2016_3732-04-1.mrxs", - "P-2016_3667-09-1.mrxs", - "P-2019_3292-06-1.mrxs", - "P-2016_3988-02-1.mrxs", - "P-2016_3667-11-0.mrxs", - "P-2016_3606-05-1.mrxs", - "P-2016_3851-09-1.mrxs", - "P-2016_3627-09-1.mrxs", - "P-2016_3606-03-1.mrxs", - "P-2016_3627-10-1.mrxs", - "P-2016_3852-03-1.mrxs", - "P-2016_3851-07-1.mrxs", - "P-2016_3829-03-1.mrxs", - "P-2016_3627-06-1.mrxs", - "P-2016_3597-09-1.mrxs", - "P-2016_3926-01-1.mrxs", - "P-2016_3629-11-1.mrxs", - "P-2016_3760-03-1.mrxs", -} def main() -> None: - folders = [ - "archive tumor cases", - "archive negative cases", - "Prospective negative cases", - "Prospective test cases", - "Prospective tumor cases", - ] - - slides = [] - for folder in folders: - for slide in Path(SLIDES_PATH, folder).rglob("*.mrxs"): - if slide.name in BROKEN_SLIDES: - continue - slides.append(slide) + slides = list(Path(SLIDES_PATH).rglob("*.mrxs")) + slides, test_slides = train_test_split(slides, test_size=0.2) train_slides, val_slides = train_test_split(slides, test_size=0.1) @@ -150,4 +101,15 @@ def main() -> None: if __name__ == "__main__": - main() + #main() + slides = [("/home/jovyan/staining/demo_data/P-2016_0077-08-1_hed_h0.6_e1.5.tiff")] + train_slides_df, train_tiles_df = tiling(slides=slides, handler=handler) + + mlflow.set_experiment(experiment_name="Stain-Normalization") + with mlflow.start_run(run_name="P-2016_0077-08-1_hed all tissue tiles") as _: + save_mlflow_dataset( + slides=train_slides_df, + tiles=train_tiles_df, + dataset_name="P-2016_0077-08-1_hed", + ) + diff --git a/pyproject.toml b/pyproject.toml index 8cba123..22faeae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "Stain Normalization" version = "0.1.0" authors = [{name = "Adam Lopatka"}] -requires-python = ">=3.11,<3.13" +requires-python = "3.12.5" readme = "README.md" license = { file = "LICENSE" } dependencies = [ diff --git a/stain_normalization/analysis/__init__.py b/stain_normalization/analysis/__init__.py new file mode 100644 index 0000000..33f4d99 --- /dev/null +++ b/stain_normalization/analysis/__init__.py @@ -0,0 +1,20 @@ +from .analyzer import StainAnalyzer +from .report import ( + REPORT_METRICS, + aggregate_average, + aggregate_rms, + aggregate_max, + aggregate_penalized_mean, + aggregate_power_mean, +) + + +__all__ = [ + "StainAnalyzer", + "REPORT_METRICS", + "aggregate_average", + "aggregate_rms", + "aggregate_max", + "aggregate_penalized_mean", + "aggregate_power_mean", +] diff --git a/stain_normalization/analysis/analyzer.py b/stain_normalization/analysis/analyzer.py new file mode 100644 index 0000000..9b0b6c5 --- /dev/null +++ b/stain_normalization/analysis/analyzer.py @@ -0,0 +1,189 @@ +"""Stain normalization analysis tool. + +Compares images using selected metrics, accumulates results, +and provides statistics and saving. +""" +from pathlib import Path +from typing import Union, Optional + +import numpy as np +import pandas as pd +from rationai.staining import estimate_stain_vectors +from skimage.metrics import structural_similarity + +from ..metrics.vector_metrics import compare_vectors +from ..metrics.image_metrics import compute_nmi, compute_pcc, compute_lab_brightness_psnr + + +class StainAnalyzer: + """Compare images using selected metrics, accumulate results. + + Args: + reference: Optional fixed reference image. If given, stain vectors + and NMI are pre-computed once. + metrics: Which metrics to compute. None = all. + """ + + AVAILABLE_METRICS = ['vectors', 'ssim', 'pcc', 'nmi', 'lab_psnr'] + PAIRED_ONLY = {'ssim', 'pcc', 'lab_psnr'} + + def __init__( + self, + reference: Optional[np.ndarray] = None, + metrics: Optional[list[str]] = None, + ): + self.metrics = metrics or self.AVAILABLE_METRICS + self._results: list[dict] = [] + + for m in self.metrics: + if m not in self.AVAILABLE_METRICS: + raise ValueError(f"Unknown metric '{m}'. Available: {self.AVAILABLE_METRICS}") + + # if we have reference image, precompute stain vectors and NMI + self._ref_img = reference + self._ref_vectors = None + self._ref_nmi = None + + if reference is not None: + if 'vectors' in self.metrics: + self._ref_vectors = estimate_stain_vectors(reference) + if 'nmi' in self.metrics: + self._ref_nmi = compute_nmi(reference) + + @property + def results(self) -> pd.DataFrame: + """Accumulated comparison results as DataFrame.""" + return pd.DataFrame(self._results) + + def clear(self) -> None: + """Clear accumulated results.""" + self._results.clear() + + def compare( + self, + image: np.ndarray, + image_id: Optional[str] = None, + reference: Optional[np.ndarray] = None, + ) -> dict: + """Compare an image against the reference and store the result. + + Args: + image: Image to compare. + image_id: Optional identifier for this comparison. + reference: Override reference image for this call. + + Returns: + Dict with metric results. + """ + + ref_img = reference if reference is not None else self._ref_img + if ref_img is None: + raise ValueError("No reference image. Pass one to __init__ or to compare().") + + is_paired = reference is not None + + if reference is not None: + ref_vectors = ( + estimate_stain_vectors(ref_img) + if 'vectors' in self.metrics else None + ) + ref_nmi = compute_nmi(ref_img) if 'nmi' in self.metrics else None + else: + ref_vectors = self._ref_vectors + ref_nmi = self._ref_nmi + + result = {'id': image_id} if image_id is not None else {} + + if 'vectors' in self.metrics: + img_vectors = estimate_stain_vectors(image) + vec_result = compare_vectors(ref_vectors, img_vectors) + result.update(vec_result) + img_vectors_paired = ( + img_vectors[[1, 0]] if vec_result['was_swapped'] else img_vectors + ) + for j, val in enumerate(ref_vectors.flatten()): + result[f'ref_vec_{j}'] = float(val) + for j, val in enumerate(img_vectors_paired.flatten()): + result[f'img_vec_{j}'] = float(val) + + if 'ssim' in self.metrics and is_paired: + result['ssim'] = float(structural_similarity( + ref_img, image, channel_axis=-1, data_range=255, + )) + + if 'pcc' in self.metrics and is_paired: + result['pcc'] = compute_pcc(ref_img, image) + + if 'nmi' in self.metrics: + img_nmi = compute_nmi(image) + result['ref_nmi'] = ref_nmi + result['nmi'] = img_nmi + result['nmi_diff'] = img_nmi - ref_nmi + + if 'lab_psnr' in self.metrics and is_paired: + result['lab_brightness_psnr'] = compute_lab_brightness_psnr(ref_img, image) + + self._results.append(result) + return result + + # --- Statistics --- + + def get_statistics(self) -> pd.DataFrame: + """Summary statistics for accumulated results. + + Returns: + DataFrame with mean, std, min, max, percentiles. + """ + df = self.results + numeric_cols = df.select_dtypes(include=[np.number]).columns + return df[numeric_cols].describe(percentiles=[0.05, 0.25, 0.5, 0.75, 0.95]) + + def get_baseline_ranges( + self, + percentile_low: float = 5, + percentile_high: float = 95, + ) -> dict: + """Get acceptable value ranges for each metric. + + Args: + percentile_low: Lower percentile bound. Defaults to 5. + percentile_high: Upper percentile bound. Defaults to 95. + + Returns: + Dict mapping metric names to (low, high) tuples. + """ + df = self.results + numeric_cols = df.select_dtypes(include=[np.number]).columns + return { + col: ( + float(df[col].quantile(percentile_low / 100)), + float(df[col].quantile(percentile_high / 100)), + ) + for col in numeric_cols + } + + def save_csv(self, output_dir: Union[str, Path]) -> Path: + """Save accumulated results and statistics as CSV files. + + Args: + output_dir: Directory to save files into. + + Returns: + Path to the output directory. + """ + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + + self.results.to_csv(output_dir / "results.csv", index=True) + self.get_statistics().to_csv(output_dir / "statistics.csv") + + ranges = self.get_baseline_ranges() + with open(output_dir / "baseline_ranges.txt", 'w') as f: + f.write("Baseline Metric Ranges (5th-95th percentile)\n") + f.write("=" * 55 + "\n\n") + for metric, (low, high) in sorted(ranges.items()): + f.write(f"{metric:30s}: [{low:8.4f}, {high:8.4f}]\n") + + return output_dir + + diff --git a/stain_normalization/callbacks/__init__.py b/stain_normalization/callbacks/__init__.py index 86a8ce0..4aeaf95 100644 --- a/stain_normalization/callbacks/__init__.py +++ b/stain_normalization/callbacks/__init__.py @@ -1,6 +1,7 @@ +from stain_normalization.callbacks._base import NormalizationCallback from stain_normalization.callbacks.analysis_export import AnalysisExport -from stain_normalization.callbacks.save_wsi import SaveWSI from stain_normalization.callbacks.tiles_export import TilesExport +from stain_normalization.callbacks.wsi_assembler import WSIAssembler -__all__ = ["AnalysisExport", "SaveWSI", "TilesExport"] +__all__ = ["AnalysisExport", "NormalizationCallback", "TilesExport", "WSIAssembler"] diff --git a/stain_normalization/callbacks/_base.py b/stain_normalization/callbacks/_base.py new file mode 100644 index 0000000..4dba6cc --- /dev/null +++ b/stain_normalization/callbacks/_base.py @@ -0,0 +1,25 @@ +import numpy as np +import torch +from lightning import Callback +from omegaconf import DictConfig + + +class NormalizationCallback(Callback): + """Base callback providing denormalization helpers for model outputs.""" + + def __init__(self, normalization_config: DictConfig) -> None: + super().__init__() + self.mean = torch.tensor(normalization_config.mean).view(3, 1, 1) + self.std = torch.tensor(normalization_config.std).view(3, 1, 1) + + def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: + """Reverse normalization: tensor → [0, 1] float.""" + device = tensor.device + return (tensor * self.std.to(device)) + self.mean.to(device) + + def tensor_to_image(self, tensor: torch.Tensor) -> np.ndarray: + """Convert model output tensor to uint8 HWC numpy array.""" + return ( + self.denormalize(tensor).clamp(0, 1).mul(255).byte() + .permute(1, 2, 0).cpu().numpy() + ) diff --git a/stain_normalization/callbacks/analysis_export.py b/stain_normalization/callbacks/analysis_export.py index f1e307d..ad0f603 100644 --- a/stain_normalization/callbacks/analysis_export.py +++ b/stain_normalization/callbacks/analysis_export.py @@ -1,78 +1,24 @@ from pathlib import Path import mlflow -import numpy as np -import pandas as pd import torch -from lightning import Callback, LightningModule, Trainer -from rationai.staining import estimate_stain_vectors -from skimage.metrics import structural_similarity as ssim -from skimage.color import rgb2lab -from skimage.metrics import peak_signal_noise_ratio +from lightning import LightningModule, Trainer +from omegaconf import DictConfig +from ..analysis.analyzer import StainAnalyzer +from ._base import NormalizationCallback -class AnalysisExport(Callback): - """Callback for exporting analysis metrics during testing.""" - def __init__(self, output_dir: str | Path, normalization_config) -> None: - super().__init__() +class AnalysisExport(NormalizationCallback): + """Exports analysis metrics during testing.""" + + def __init__(self, output_dir: str | Path, normalization_config: DictConfig) -> None: + super().__init__(normalization_config) self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) - normalization = normalization_config - self.mean = torch.tensor(normalization.mean).view(3, 1, 1) - self.std = torch.tensor(normalization.std).view(3, 1, 1) - - self.df_diff = pd.DataFrame() - self.df_raw = pd.DataFrame() - - def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: - std = self.std.to(tensor.device) - mean = self.mean.to(tensor.device) - return (tensor * std) + mean - - def tensor_to_image(self, tensor: torch.Tensor) -> np.ndarray: - tensor = self.denormalize(tensor).clamp(0, 1) - return (tensor * 255).byte().permute(1, 2, 0).cpu().numpy() - - def _estimate_vectors(self, img: np.ndarray) -> np.ndarray: - """Estimate stain vectors for a given image.""" - return estimate_stain_vectors(img, i0=240, alpha=1, beta=0.15) - - def _compare_vectors(self, vec1: np.ndarray, vec2: np.ndarray) -> float: - """Compute Euclidean distance between two stain vector estimates.""" - return float(np.linalg.norm(vec1 - vec2)) - - def _compute_ssim(self, img1: np.ndarray, img2: np.ndarray) -> float: - """Compute Structural Similarity Index (SSIM) between two images.""" - return float(ssim(img1, img2, channel_axis=-1, data_range=255)) - - def _compute_nmi(self, img: np.ndarray) -> float: - """Compute Normalized Median Intensity (NMI) of an image.""" - avg_rgb = img.mean(axis=2) - median_val = np.median(avg_rgb) - p95_val = np.percentile(avg_rgb, 95) - return median_val / p95_val if p95_val != 0 else 0.0 - - def _compute_pcc(self, img1: np.ndarray, img2: np.ndarray) -> float: - """Compute Pearson Correlation Coefficient (PCC) between two images.""" - img1_flat = img1.flatten().astype(np.float64) - img2_flat = img2.flatten().astype(np.float64) - if img1_flat.size == 0 or img2_flat.size == 0: - return 0.0 - - return float(np.corrcoef(img1_flat, img2_flat)[0, 1]) - - def _compute_lab_brightness_psnr(self, img1: np.ndarray, img2: np.ndarray) -> float: - """Compute PSNR on the L (lightness) channel in Lab color space. - """ - lab1 = rgb2lab(img1.astype(np.float32) / 255.0) - lab2 = rgb2lab(img2.astype(np.float32) / 255.0) - - L1 = lab1[:, :, 0] - L2 = lab2[:, :, 0] - - return float(peak_signal_noise_ratio(L1, L2, data_range=100.0)) + self.mod_analyzer = StainAnalyzer() + self.pred_analyzer = StainAnalyzer() def on_test_batch_end( self, @@ -83,84 +29,27 @@ def on_test_batch_end( batch_idx: int, dataloader_idx: int = 0, ) -> None: - """Called at the end of each test batch. - - Computes metrics for each sample and accumulates results. - """ + """Computes metrics for each sample and accumulates results.""" for b in range(len(outputs)): - predicted_tensor = outputs[b] original_img = batch[1][b]["original_image"].astype("uint8") modified_img = (batch[1][b]["modified_image"] * 255).astype("uint8") - index = batch[1][b]["index"] - predicted_img = self.tensor_to_image(predicted_tensor) - - vec_original = self._estimate_vectors(original_img) - vec_modified = self._estimate_vectors(modified_img) - vec_predicted = self._estimate_vectors(predicted_img) - - vec_diff_mod = self._compare_vectors(vec_original, vec_modified) - vec_diff_pred = self._compare_vectors(vec_original, vec_predicted) - - ssim_mod = self._compute_ssim(original_img, modified_img) - ssim_pred = self._compute_ssim(original_img, predicted_img) + predicted_img = self.tensor_to_image(outputs[b]) - nmi_original = self._compute_nmi(original_img) - nmi_modified = self._compute_nmi(modified_img) - nmi_predicted = self._compute_nmi(predicted_img) - - pcc_mod = self._compute_pcc(original_img, modified_img) - pcc_pred = self._compute_pcc(original_img, predicted_img) - - lab_psnr_mod = self._compute_lab_brightness_psnr(original_img, modified_img) - lab_psnr_pred = self._compute_lab_brightness_psnr(original_img, predicted_img) - - diff_row = { - "index": index, - "vector_diff_modified_vs_original": vec_diff_mod, - "vector_diff_predicted_vs_original": vec_diff_pred, - "ssim_modified_vs_original": ssim_mod, - "ssim_predicted_vs_original": ssim_pred, - "nmi_diff_modified_vs_original": nmi_modified - nmi_original, - "nmi_diff_predicted_vs_original": nmi_predicted - nmi_original, - "pcc_modified_vs_original": pcc_mod, - "pcc_predicted_vs_original": pcc_pred, - "lab_brightness_psnr_mod_vs_orig": lab_psnr_mod, - "lab_brightness_psnr_pred_vs_orig": lab_psnr_pred, - } - - raw_row = {"index": index} - for name, vec, nmi in zip( - ["original", "modified", "predicted"], - [vec_original, vec_modified, vec_predicted], - [nmi_original, nmi_modified, nmi_predicted], - strict=False, - ): - vectors = vec.flatten() - for j, val in enumerate(vectors): - raw_row[f"{name}_vec_{j}"] = val - raw_row[f"{name}_nmi"] = nmi - - self.df_diff = pd.concat( - [self.df_diff, pd.DataFrame([diff_row])], ignore_index=True - ) - self.df_raw = pd.concat( - [self.df_raw, pd.DataFrame([raw_row])], ignore_index=True - ) + self.mod_analyzer.compare(modified_img, reference=original_img) + self.pred_analyzer.compare(predicted_img, reference=original_img) def on_test_end( self, trainer: Trainer, pl_module: LightningModule, ) -> None: - """Called at the end of testing. - - Saves the collected metrics as CSV files and logs them as mlflow artifacts. - """ - diff_path = self.output_dir / "analysis_differences.csv" - raw_path = self.output_dir / "analysis_raw_vectors.csv" + """Saves collected metrics as CSV files and logs them as mlflow artifacts.""" + metrics_dir = self.output_dir / "analysis_metrics" - self.df_diff.to_csv(diff_path, index=False) - self.df_raw.to_csv(raw_path, index=False) + mod_dir = self.mod_analyzer.save_csv(metrics_dir / "modified") + pred_dir = self.pred_analyzer.save_csv(metrics_dir / "predicted") - mlflow.log_artifact(str(diff_path), artifact_path="analysis_metrics") - mlflow.log_artifact(str(raw_path), artifact_path="analysis_metrics") + for f in mod_dir.glob("*"): + mlflow.log_artifact(str(f), artifact_path="analysis_metrics/modified") + for f in pred_dir.glob("*"): + mlflow.log_artifact(str(f), artifact_path="analysis_metrics/predicted") diff --git a/stain_normalization/callbacks/save_wsi.py b/stain_normalization/callbacks/save_wsi.py deleted file mode 100644 index b74ba83..0000000 --- a/stain_normalization/callbacks/save_wsi.py +++ /dev/null @@ -1,56 +0,0 @@ -from pathlib import Path - -import torch -from lightning.pytorch.callbacks import Callback -from omegaconf import DictConfig -from PIL import Image - - -class SaveWSI(Callback): - def __init__( - self, output_dir: str | Path, normalization_config: DictConfig - ) -> None: - super().__init__() - self.output_root = Path(output_dir) - self.mean = torch.tensor(normalization_config.mean).view(3, 1, 1) - self.std = torch.tensor(normalization_config.std).view(3, 1, 1) - - def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: - device = tensor.device - std = self.std.to(device) - mean = self.mean.to(device) - return (tensor * std) + mean - - def on_predict_batch_end( - self, - trainer, - pl_module, - outputs: list[torch.Tensor], - batch: tuple[torch.Tensor, list], - batch_idx: int, - dataloader_idx: int = 0, - ) -> None: - for b in range(len(outputs)): - predicted_image = outputs[b] - metadata = batch[1][b] - - slide_name = metadata["slide_name"] - level = metadata["level"] - original_image = Image.fromarray(metadata["original_image"].astype("uint8")) - filename = f"{metadata['xy']}.png" - - base_folder = self.output_root / str(slide_name) / str(level) - predicted_folder = base_folder / "predicted" - original_folder = base_folder / "original" - - predicted_folder.mkdir(parents=True, exist_ok=True) - original_folder.mkdir(parents=True, exist_ok=True) - - original_image.save(original_folder / filename) - - predicted_image = self.denormalize(predicted_image).clamp(0, 1) - predicted_image = (predicted_image * 255).byte() - predicted_image = Image.fromarray( - predicted_image.permute(1, 2, 0).cpu().numpy() - ) - predicted_image.save(predicted_folder / filename) diff --git a/stain_normalization/callbacks/tiles_export.py b/stain_normalization/callbacks/tiles_export.py index 0c44f07..bfd52f9 100644 --- a/stain_normalization/callbacks/tiles_export.py +++ b/stain_normalization/callbacks/tiles_export.py @@ -1,34 +1,23 @@ from pathlib import Path import torch -from lightning import Callback, LightningModule, Trainer +from lightning import LightningModule, Trainer from omegaconf import DictConfig from PIL import Image +from ._base import NormalizationCallback -class TilesExport(Callback): + +class TilesExport(NormalizationCallback): def __init__( self, output_dir: str | Path, normalization_config: DictConfig ) -> None: - super().__init__() + super().__init__(normalization_config) self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) - normalization = normalization_config - self.mean = torch.tensor(normalization.mean).view(3, 1, 1) - self.std = torch.tensor(normalization.std).view(3, 1, 1) - - def denormalize(self, tensor: torch.Tensor) -> torch.Tensor: - device = tensor.device - std = self.std.to(device) - mean = self.mean.to(device) - return (tensor * std) + mean - def tensor_to_image(self, tensor: torch.Tensor) -> Image.Image: - tensor = self.denormalize(tensor) - tensor = tensor.clamp(0, 1) - tensor = (tensor * 255).byte() - return Image.fromarray(tensor.permute(1, 2, 0).cpu().numpy()) + return Image.fromarray(super().tensor_to_image(tensor)) def on_test_batch_end( self, @@ -39,7 +28,27 @@ def on_test_batch_end( batch_idx: int, dataloader_idx: int = 0, ) -> None: - self._save_images(outputs, batch, is_predict=False) + _, data = batch + for b in range(len(outputs)): + slide_name = data[b]["slide_name"] + xy = data[b]["xy"] + + slide_dir = self.output_dir / slide_name + slide_dir.mkdir(parents=True, exist_ok=True) + + self.tensor_to_image(outputs[b]).save( + slide_dir / f"{xy}_predicted.png" + ) + + original_image = Image.fromarray( + data[b]["original_image"].astype("uint8") + ) + original_image.save(slide_dir / f"{xy}_original.png") + + modified_image = Image.fromarray( + (data[b]["modified_image"] * 255).astype("uint8") + ) + modified_image.save(slide_dir / f"{xy}_modified.png") def on_predict_batch_end( self, @@ -50,27 +59,12 @@ def on_predict_batch_end( batch_idx: int, dataloader_idx: int = 0, ) -> None: - self._save_images(outputs, batch, is_predict=True) - - def _save_images(self, outputs, batch, is_predict: bool) -> None: - inputs, data = batch + _, data = batch for b in range(len(outputs)): - index = data[b].get("index", 0) - - predicted_image = outputs[b] - name = data[b].get("name", str(index)) - predicted_image = self.tensor_to_image(predicted_image) - - predicted_image.save(self.output_dir / f"{name}.png") + slide_name = data[b]["slide_name"] + xy = data[b]["xy"] - if not is_predict: - original_image = Image.fromarray( - data[b]["original_image"].astype("uint8") - ) - original_image.save(self.output_dir / f"{name}_original.png") + slide_dir = self.output_dir / slide_name + slide_dir.mkdir(parents=True, exist_ok=True) - if "modified_image" in data[b]: - modified_image = Image.fromarray( - (data[b]["modified_image"] * 255).astype("uint8") - ) - modified_image.save(self.output_dir / f"{name}_modified.png") + self.tensor_to_image(outputs[b]).save(slide_dir / f"{xy}.png") diff --git a/stain_normalization/callbacks/wsi_assembler.py b/stain_normalization/callbacks/wsi_assembler.py new file mode 100644 index 0000000..31a0745 --- /dev/null +++ b/stain_normalization/callbacks/wsi_assembler.py @@ -0,0 +1,232 @@ +"""Callback for assembling predicted tiles into whole-slide pyramid TIFFs.""" + +# DEV: Key design decisions: +# DEV: - One slide buffer at a time — slides are processed sequentially by ConcatDataset, +# DEV: so we open a buffer on the first tile of a slide and close it when the slide changes. +# DEV: This keeps peak temp disk at ~one slide (~5-10 GB at level 0 with sparse tissue), +# DEV: regardless of how many slides are in the predict set. +# DEV: - Buffers are zero-initialized (sparse mmap) — only pages where tiles actually land +# DEV: get written to disk. White fill for untouched background is applied by pyvips at save. +# DEV: - Running average (uint8 result + uint8 count) instead of float32 sum accumulator. +# DEV: Cuts temp disk ~4x vs the sum approach. Float math is done only per-tile (512x512). +# DEV: - Slide transition is detected per-tile inside the batch loop, not per-batch, +# DEV: so transition batches (last tiles of A + first tiles of B) are handled correctly. + +import tempfile +import traceback +from dataclasses import dataclass +from pathlib import Path + +import numpy as np +import torch +from lightning import LightningModule, Trainer +from omegaconf import DictConfig +from PIL.ImageCms import createProfile + +from ._base import NormalizationCallback + + +def _srgb_icc_bytes() -> bytes: + """Generate sRGB ICC profile bytes for embedding in TIFFs.""" + raw = createProfile("sRGB") + # Pillow < 10: .tobuffer(), Pillow >= 10: .tobytes() + try: + return raw.tobuffer() + except AttributeError: + from PIL.ImageCms import ImageCmsProfile + return ImageCmsProfile(raw).tobytes() + + +@dataclass +class _SlideMeta: + path: str + level: int + extent_x: int + extent_y: int + tile_extent_x: int + tile_extent_y: int + mpp_x: float + mpp_y: float + + +@dataclass +class _SlideBuffers: + meta: _SlideMeta + temp_dir: tempfile.TemporaryDirectory + result_buffer: np.memmap + count_buffer: np.memmap + + +class WSIAssembler(NormalizationCallback): + """Assembles predicted tiles back into whole-slide pyramid TIFFs.""" + + def __init__( + self, + output_dir: str | Path, + normalization_config: DictConfig, + temp_dir: str | Path | None = None, + ) -> None: + super().__init__(normalization_config) + self.output_dir = Path(output_dir) + self.temp_dir = str(temp_dir) if temp_dir else None + self._slide_meta: dict[str, _SlideMeta] = {} + self._active: _SlideBuffers | None = None + self._active_name: str | None = None + + def on_predict_start(self, trainer: Trainer, pl_module: LightningModule) -> None: + self.output_dir.mkdir(parents=True, exist_ok=True) + slides_df = trainer.datamodule.predict.slides + + # Cache metadata only — buffers are opened lazily per slide + for _, row in slides_df.iterrows(): + name = Path(row.path).stem + self._slide_meta[name] = _SlideMeta( + path=row.path, + level=int(row.level), + extent_x=int(row.extent_x), + extent_y=int(row.extent_y), + tile_extent_x=int(row.tile_extent_x), + tile_extent_y=int(row.tile_extent_y), + mpp_x=float(row.mpp_x), + mpp_y=float(row.mpp_y), + ) + + def _open_slide(self, slide_name: str) -> None: + """Allocate memmap buffers for one slide.""" + meta = self._slide_meta[slide_name] + h, w = meta.extent_y, meta.extent_x + + tmp = tempfile.TemporaryDirectory( + prefix=f"wsi_{slide_name}_", dir=self.temp_dir + ) + result_buf = np.memmap( + Path(tmp.name) / "result.raw", + dtype=np.uint8, + mode="w+", + shape=(h, w, 3), + ) + count_buf = np.memmap( + Path(tmp.name) / "count.raw", + dtype=np.uint8, + mode="w+", + shape=(h, w), + ) + + self._active = _SlideBuffers( + meta=meta, + temp_dir=tmp, + result_buffer=result_buf, + count_buffer=count_buf, + ) + self._active_name = slide_name + + def _close_slide(self) -> None: + """Save and free the currently active slide.""" + if self._active is None: + return + try: + self._save_slide(self._active_name, self._active) + except Exception: + traceback.print_exc() + finally: + del self._active.result_buffer + del self._active.count_buffer + self._active.temp_dir.cleanup() + self._active = None + self._active_name = None + + def on_predict_batch_end( + self, + trainer: Trainer, + pl_module: LightningModule, + outputs: list[torch.Tensor], + batch: tuple[torch.Tensor, list[dict]], + batch_idx: int, + dataloader_idx: int = 0, + ) -> None: + for b in range(len(outputs)): + metadata = batch[1][b] + slide_name = metadata["slide_name"] + + if slide_name not in self._slide_meta: + print(f"Unknown slide '{slide_name}', skipping tile.") + continue + + if slide_name != self._active_name: + if self._active_name is not None: + print(f"Slide transition: {self._active_name} → {slide_name}") + self._close_slide() + self._open_slide(slide_name) + + tile = self.tensor_to_image(outputs[b]) + x, y = (int(v) for v in metadata["xy"].split("_")) + self._place_tile(tile, x, y) + + def _place_tile(self, tile: np.ndarray, x: int, y: int) -> None: + """Place a predicted tile into the active slide buffer with overlap averaging.""" + sb = self._active + ex, ey = sb.meta.extent_x, sb.meta.extent_y + + h, w = min(tile.shape[0], ey - y), min(tile.shape[1], ex - x) + tile = tile[:h, :w] + + region = sb.result_buffer[y:y + h, x:x + w] + count = sb.count_buffer[y:y + h, x:x + w] + + # Running average: avg = (old * n + new) / (n + 1) + overlap = count > 0 + if overlap.any(): + n = count[:, :, np.newaxis].astype(np.float32) + blended = np.where( + overlap[:, :, np.newaxis], + (region.astype(np.float32) * n + tile) / (n + 1), + tile, + ) + sb.result_buffer[y:y + h, x:x + w] = np.clip(blended, 0, 255).astype(np.uint8) + else: + sb.result_buffer[y:y + h, x:x + w] = tile + + sb.count_buffer[y:y + h, x:x + w] = count + 1 + + def on_predict_end(self, trainer: Trainer, pl_module: LightningModule) -> None: + self._close_slide() + self._slide_meta.clear() + + def _save_slide(self, slide_name: str, sb: _SlideBuffers) -> None: + # Imported here — module-level import causes OpenSlide segfault (libtiff conflict). + import pyvips + + meta = sb.meta + sb.result_buffer.flush() + sb.count_buffer.flush() + + result_path = Path(sb.temp_dir.name) / "result.raw" + count_path = Path(sb.temp_dir.name) / "count.raw" + + result_img = pyvips.Image.rawload(str(result_path), meta.extent_x, meta.extent_y, 3) + result_img = result_img.copy(interpretation=pyvips.Interpretation.SRGB) + + count_img = pyvips.Image.rawload(str(count_path), meta.extent_x, meta.extent_y, 1) + mask = count_img > 0 + # add white background for untouched areas (count=0) + white = (pyvips.Image.black(meta.extent_x, meta.extent_y, bands=3) + 255).cast( + pyvips.BandFormat.UCHAR + ) + final_img = mask.ifthenelse(result_img, white) + + final_img.set_type( + pyvips.GValue.blob_type, "icc-profile-data", _srgb_icc_bytes() + ) + + output_path = self.output_dir / f"{slide_name}_norm.tiff" + final_img.tiffsave( + str(output_path), + bigtiff=True, + compression=pyvips.enums.ForeignTiffCompression.DEFLATE, + tile=True, + tile_width=512, + tile_height=512, + pyramid=True, + xres=1000.0 / meta.mpp_x, + yres=1000.0 / meta.mpp_y, + ) diff --git a/stain_normalization/data/data_module.py b/stain_normalization/data/data_module.py index eb1f7ae..bd462bf 100644 --- a/stain_normalization/data/data_module.py +++ b/stain_normalization/data/data_module.py @@ -1,14 +1,12 @@ from collections.abc import Iterable -from typing import Any from hydra.utils import instantiate from lightning import LightningDataModule from omegaconf import DictConfig -from torch import Tensor from torch.utils.data import DataLoader from stain_normalization.data.utils import collate_fn -from stain_normalization.typing import Input +from stain_normalization.type_aliases import Batch, PredictBatch class DataModule(LightningDataModule): @@ -32,7 +30,7 @@ def setup(self, stage: str) -> None: case "predict": self.predict = instantiate(self.datasets["predict"]) - def train_dataloader(self) -> Iterable[Input]: + def train_dataloader(self) -> Iterable[Batch]: return DataLoader( self.train, batch_size=self.batch_size, @@ -42,7 +40,7 @@ def train_dataloader(self) -> Iterable[Input]: persistent_workers=self.num_workers > 0, ) - def val_dataloader(self) -> Iterable[Input]: + def val_dataloader(self) -> Iterable[Batch]: return DataLoader( self.val, batch_size=self.batch_size, @@ -50,7 +48,7 @@ def val_dataloader(self) -> Iterable[Input]: persistent_workers=self.num_workers > 0, ) - def test_dataloader(self) -> Iterable[Input]: + def test_dataloader(self) -> Iterable[PredictBatch]: return DataLoader( self.test, batch_size=self.batch_size, @@ -58,7 +56,7 @@ def test_dataloader(self) -> Iterable[Input]: collate_fn=collate_fn, ) - def predict_dataloader(self) -> Iterable[tuple[Tensor, list[dict[str, Any]]]]: + def predict_dataloader(self) -> Iterable[PredictBatch]: return DataLoader( self.predict, batch_size=self.batch_size, diff --git a/stain_normalization/data/datasets/predict_dataset.py b/stain_normalization/data/datasets/predict_dataset.py index ebd85fb..9fc6650 100644 --- a/stain_normalization/data/datasets/predict_dataset.py +++ b/stain_normalization/data/datasets/predict_dataset.py @@ -6,7 +6,7 @@ from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset -from stain_normalization.typing import PredictSample +from stain_normalization.type_aliases import PredictSample class PredictDataset(MetaTiledSlides[PredictSample]): @@ -54,7 +54,6 @@ def __len__(self) -> int: def __getitem__(self, idx: int) -> PredictSample: input_image_255 = self.slide_tiles[idx] slide_name = self.slide_tiles.slide_path.stem - level = self.slide_tiles.level x = self.slide_tiles.tiles.iloc[idx]["x"] y = self.slide_tiles.tiles.iloc[idx]["y"] @@ -66,11 +65,6 @@ def __getitem__(self, idx: int) -> PredictSample: input_image = self.to_tensor(image=input_image)["image"] return input_image, { - "original_image": input_image_255, - "modified_image": None, "slide_name": slide_name, - "level": level, - "index": idx, "xy": f"{x}_{y}", - "name": f"{slide_name}-{x}-{y}", } diff --git a/stain_normalization/data/datasets/test_dataset.py b/stain_normalization/data/datasets/test_dataset.py index 151b373..ef094f9 100644 --- a/stain_normalization/data/datasets/test_dataset.py +++ b/stain_normalization/data/datasets/test_dataset.py @@ -6,7 +6,7 @@ from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset -from stain_normalization.typing import PredictSample +from stain_normalization.type_aliases import PredictSample class TestDataset(MetaTiledSlides[PredictSample]): @@ -57,6 +57,9 @@ def __len__(self) -> int: def __getitem__(self, idx: int) -> PredictSample: original_image_255 = self.slide_tiles[idx] + slide_name = self.slide_tiles.slide_path.stem + x = self.slide_tiles.tiles.iloc[idx]["x"] + y = self.slide_tiles.tiles.iloc[idx]["y"] # Create "wrong" image to use as input. Outputs image in float 0-1 modified_image_raw = self.modify(image=original_image_255)["image"] @@ -76,6 +79,7 @@ def __getitem__(self, idx: int) -> PredictSample: "original_image_tensor": original_image, "original_image": original_image_255, "modified_image": modified_image_raw, - "index": idx, + "slide_name": slide_name, + "xy": f"{x}_{y}", }, ) diff --git a/stain_normalization/data/datasets/train_dataset.py b/stain_normalization/data/datasets/train_dataset.py index 2a0fab7..1d46afe 100644 --- a/stain_normalization/data/datasets/train_dataset.py +++ b/stain_normalization/data/datasets/train_dataset.py @@ -6,7 +6,7 @@ from rationai.mlkit.data.datasets import MetaTiledSlides, OpenSlideTilesDataset from torch.utils.data import Dataset -from stain_normalization.typing import Sample +from stain_normalization.type_aliases import Sample class TrainDataset(MetaTiledSlides[Sample]): diff --git a/stain_normalization/data/modification/exposure_adjustment.py b/stain_normalization/data/modification/exposure_adjustment.py index 69e9e5c..e1ff4c2 100644 --- a/stain_normalization/data/modification/exposure_adjustment.py +++ b/stain_normalization/data/modification/exposure_adjustment.py @@ -36,6 +36,8 @@ def apply(self, img: NDArray, **params) -> NDArray: """ brightness_factor = np.random.uniform(*self.brightness_range) img = img.astype(np.float32) + if img.max() > 1.0: + img = img / 255.0 img = np.clip(img * brightness_factor, 0.0, 1.0) return img diff --git a/stain_normalization/metrics/__init__.py b/stain_normalization/metrics/__init__.py new file mode 100644 index 0000000..0f4f8f3 --- /dev/null +++ b/stain_normalization/metrics/__init__.py @@ -0,0 +1,16 @@ +from .image_metrics import ( + compute_lab_brightness_psnr, + compute_nmi, + compute_pcc, +) +from .vector_metrics import ( + compare_vectors, +) + + +__all__ = [ + "compare_vectors", + "compute_lab_brightness_psnr", + "compute_nmi", + "compute_pcc", +] diff --git a/stain_normalization/metrics/image_metrics.py b/stain_normalization/metrics/image_metrics.py new file mode 100644 index 0000000..28f806d --- /dev/null +++ b/stain_normalization/metrics/image_metrics.py @@ -0,0 +1,56 @@ +import numpy as np +from skimage.color import rgb2lab +from skimage.metrics import peak_signal_noise_ratio + + +def compute_nmi(img: np.ndarray) -> float: + """Normalized Median Intensity — measures relative brightness of an image. + + Args: + img: RGB image. + + Returns: + Ratio of median to 95th percentile intensity. + """ + avg_rgb = img.mean(axis=2) + median_val = np.median(avg_rgb) + p95_val = np.percentile(avg_rgb, 95) + + if p95_val == 0: + return 0.0 + + return float(median_val / p95_val) + + +def compute_pcc(img1: np.ndarray, img2: np.ndarray) -> float: + """Pearson Correlation Coefficient between two images. + + Args: + img1: First image. + img2: Second image. + + Returns: + PCC value, or 0.0 if either image has zero variance. + """ + img1_flat = img1.flatten().astype(np.float64) + img2_flat = img2.flatten().astype(np.float64) + + if np.std(img1_flat) == 0 or np.std(img2_flat) == 0: + return 0.0 + + return float(np.corrcoef(img1_flat, img2_flat)[0, 1]) + + +def compute_lab_brightness_psnr(img1: np.ndarray, img2: np.ndarray) -> float: + """PSNR on the L* channel in Lab color space. + + Args: + img1: First RGB image. + img2: Second RGB image. + + Returns: + PSNR in dB on the lightness channel. + """ + lab1 = rgb2lab(img1.astype(np.float32) / 255.0) + lab2 = rgb2lab(img2.astype(np.float32) / 255.0) + return float(peak_signal_noise_ratio(lab1[:, :, 0], lab2[:, :, 0], data_range=100.0)) diff --git a/stain_normalization/metrics/vector_metrics.py b/stain_normalization/metrics/vector_metrics.py new file mode 100644 index 0000000..1348f72 --- /dev/null +++ b/stain_normalization/metrics/vector_metrics.py @@ -0,0 +1,75 @@ +import numpy as np +from skimage.color import rgb2lab + + +def _od_to_lab(od_vector: np.ndarray) -> np.ndarray: + """Convert optical density vector to Lab color. + + Args: + od_vector: Stain vector in optical density space. + + Returns: + Color in Lab space as [L, a, b]. + """ + # Calculate RGB from optical density by reversing the process in estimate_stain_vectors. + # default i0=240 (transmitted light intensity) + rgb = np.clip(240 * np.exp(-od_vector), 0, 255) / 255.0 + return rgb2lab(rgb.reshape(1, 1, 3)).flatten() + + +def delta_e76(lab1: np.ndarray, lab2: np.ndarray) -> float: + """CIE76 Delta E with dL=0 (chromaticity only). + + CIE76 Delta E is sqrt(dL^2 + da^2 + db^2). We set dL=0 because we compare + dyes not colors, so brightness is irrelevant. + + Args: + lab1: First color in Lab space. + lab2: Second color in Lab space. + + Returns: + sqrt(da^2 + db^2). + """ + da = lab1[1] - lab2[1] + db = lab1[2] - lab2[2] + return float(np.sqrt(da**2 + db**2)) + + +def compare_vectors( + vecs1: np.ndarray, + vecs2: np.ndarray, +) -> dict: + """Compare two sets of stain vectors in Lab chromaticity space. + + Args: + vecs1: Stain vectors from the first image in OD space. + vecs2: Stain vectors from the second image in OD space. + + Returns: + Dict with d_hematoxylin, d_eosin and was_swapped. + Returns NaN distances if either vector set contains NaN. + """ + if np.any(np.isnan(vecs1)) or np.any(np.isnan(vecs2)): + return { + 'd_hematoxylin': float('nan'), 'd_eosin': float('nan'), + 'was_swapped': False, + } + + + sim_straight = np.dot(vecs1[0], vecs2[0]) + np.dot(vecs1[1], vecs2[1]) + sim_swapped = np.dot(vecs1[0], vecs2[1]) + np.dot(vecs1[1], vecs2[0]) + was_swapped = sim_swapped > sim_straight + vecs2_paired = vecs2[[1, 0]] if was_swapped else vecs2 + + lab1_a = _od_to_lab(vecs1[0]) + lab1_b = _od_to_lab(vecs1[1]) + lab2_a = _od_to_lab(vecs2_paired[0]) + lab2_b = _od_to_lab(vecs2_paired[1]) + + return { + 'd_hematoxylin': delta_e76(lab1_a, lab2_a), + 'd_eosin': delta_e76(lab1_b, lab2_b), + 'was_swapped': was_swapped, + } + + diff --git a/stain_normalization/modeling/l1ssim_loss.py b/stain_normalization/modeling/l1ssim_loss.py index 474fe14..be13691 100644 --- a/stain_normalization/modeling/l1ssim_loss.py +++ b/stain_normalization/modeling/l1ssim_loss.py @@ -8,14 +8,11 @@ https://github.com/graphdeco-inria/gaussian-splatting/blob/472689c0dc70417448fb451bf529ae532d32c095/utils/loss_utils.py """ -from math import exp - import torch import torch.nn as nn import torch.nn.functional as F -from torch.autograd import Variable - +from math import exp class L1SSIMLoss(nn.Module): def __init__(self, lambda_dssim: float = 0.6, lambda_l1: float = 0.2, lambda_lum: float = 0.2, lambda_gdl: float = 0.1): @@ -45,14 +42,14 @@ def forward(self, image: torch.Tensor, target_image: torch.Tensor) -> torch.Tens gdl_loss = gradient_loss(image, target_image) # Luminance / brightness loss - lum_loss = brightness_loss(image, target_image) + brig_loss = brightness_loss(image, target_image) # total weighted loss total_loss = ( self.lambda_l1 * l1_loss + self.lambda_dssim * ssim_loss + self.lambda_gdl * gdl_loss - + self.lambda_lum * lum_loss + + self.lambda_lum * brig_loss ) return total_loss @@ -91,21 +88,10 @@ def gaussian(window_size, sigma): return gauss / gauss.sum() -def luminance_loss( - pred: torch.Tensor, - target: torch.Tensor, - he_weights=[0.33, 0.33, 0.33]) -> torch.Tensor: - device = pred.device - weights = torch.tensor(he_weights, device=device).view(1, 3, 1, 1) - - lum_pred = (pred * weights).sum(dim=1, keepdim=True) - lum_target = (target * weights).sum(dim=1, keepdim=True) - - lum_loss = F.l1_loss(lum_pred, lum_target) - return lum_loss - -def brightness_loss(pred, target, he_weights=[0.33, 0.33, 0.33]): +def brightness_loss(pred, target, he_weights=None): device = pred.device + if he_weights is None: + he_weights = [0.33, 0.33, 0.33] weights = torch.tensor(he_weights, device=device).view(1, 3, 1, 1) pred_mean = (pred * weights).mean(dim=[2, 3], keepdim=True) diff --git a/stain_normalization/stain_normalization_model.py b/stain_normalization/stain_normalization_model.py index c1f9da1..7530224 100644 --- a/stain_normalization/stain_normalization_model.py +++ b/stain_normalization/stain_normalization_model.py @@ -1,5 +1,3 @@ -from typing import Any - from lightning import LightningModule from torch import Tensor, stack from torch.optim import Adam @@ -9,7 +7,7 @@ from torchmetrics.regression import MeanAbsoluteError from stain_normalization.modeling import L1SSIMLoss, UNet -from stain_normalization.typing import Input, Outputs +from stain_normalization.type_aliases import Batch, Outputs, PredictBatch class StainNormalizationModel(LightningModule): @@ -22,16 +20,15 @@ def __init__(self) -> None: { "ssim": StructuralSimilarityIndexMeasure(), "l1": MeanAbsoluteError() - } ) self.test_metrics = self.val_metrics.clone(prefix="test/") self.val_metrics.prefix = "validation/" - def forward(self, x: Input) -> Outputs: + def forward(self, x: Tensor) -> Outputs: return self.unet(x) - def training_step(self, batch: Input) -> Tensor: + def training_step(self, batch: Batch) -> Tensor: inputs, targets = batch outputs = self(inputs) @@ -40,7 +37,7 @@ def training_step(self, batch: Input) -> Tensor: return loss - def validation_step(self, batch: Input) -> None: + def validation_step(self, batch: Batch) -> None: inputs, targets = batch outputs = self(inputs) @@ -53,7 +50,7 @@ def validation_step(self, batch: Input) -> None: on_epoch=True, ) - def test_step(self, batch: Input) -> Outputs: + def test_step(self, batch: PredictBatch) -> Outputs: inputs, data = batch outputs = self(inputs) targets = stack([item["original_image_tensor"] for item in data]) @@ -65,7 +62,7 @@ def test_step(self, batch: Input) -> Outputs: ) return outputs - def predict_step(self, batch: tuple[Tensor, Any], batch_idx: int) -> Outputs: + def predict_step(self, batch: PredictBatch, batch_idx: int) -> Outputs: inputs = batch[0] return self(inputs) diff --git a/stain_normalization/type_aliases.py b/stain_normalization/type_aliases.py new file mode 100644 index 0000000..535edda --- /dev/null +++ b/stain_normalization/type_aliases.py @@ -0,0 +1,13 @@ +from typing import Any, TypeAlias + +from torch import Tensor + + +Sample: TypeAlias = tuple[Tensor, Tensor] +PredictSample: TypeAlias = tuple[Tensor, dict[str, Any]] + +# Batches - after collate +Batch: TypeAlias = tuple[Tensor, Tensor] +PredictBatch: TypeAlias = tuple[Tensor, list[dict[str, Any]]] + +Outputs: TypeAlias = Tensor diff --git a/stain_normalization/typing.py b/stain_normalization/typing.py deleted file mode 100644 index a379a3c..0000000 --- a/stain_normalization/typing.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Any, TypeAlias - -from torch import Tensor - - -PredictSample: TypeAlias = tuple[Tensor, dict[str, Any]] -Sample: TypeAlias = tuple[Tensor, Tensor] - -Input: TypeAlias = Sample - -Outputs: TypeAlias = Tensor

+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