diff --git a/.binder/postBuild b/.binder/postBuild old mode 100644 new mode 100755 index c33605a68456c..00e8d39b93549 --- a/.binder/postBuild +++ b/.binder/postBuild @@ -6,9 +6,9 @@ set -e # inside a git checkout of the scikit-learn/scikit-learn repo. This script is # generating notebooks from the scikit-learn python examples. -if [[ ! -f /.dockerenv ]]; then - echo "This script was written for repo2docker and is supposed to run inside a docker container." - echo "Exiting because this script can delete data if run outside of a docker container." +if [[ -z "${REPO_DIR}" ]]; then + echo "This script was written for repo2docker and the REPO_DIR environment variable is supposed to be set." + echo "Exiting because this script can delete data if run outside of a repo2docker context." exit 1 fi @@ -23,7 +23,7 @@ find . -delete GENERATED_NOTEBOOKS_DIR=.generated-notebooks cp -r $TMP_CONTENT_DIR/examples $GENERATED_NOTEBOOKS_DIR -find $GENERATED_NOTEBOOKS_DIR -name '*.py' -exec sphx_glr_python_to_jupyter.py '{}' + +find $GENERATED_NOTEBOOKS_DIR -name '*.py' -exec sphinx_gallery_py2jupyter '{}' + NON_NOTEBOOKS=$(find $GENERATED_NOTEBOOKS_DIR -type f | grep -v '\.ipynb') rm -f $NON_NOTEBOOKS diff --git a/.circleci/config.yml b/.circleci/config.yml index 7a98f88b813ad..4c7bfe009f978 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -107,7 +107,7 @@ jobs: - attach_workspace: at: doc/_build/html - run: ls -ltrh doc/_build/html/stable - - deploy: + - run: command: | if [[ "${CIRCLE_BRANCH}" =~ ^main$|^[0-9]+\.[0-9]+\.X$ ]]; then bash build_tools/circle/push_doc.sh doc/_build/html/stable diff --git a/.coveragerc b/.coveragerc index 31f9fa1b4ceae..0d5f02b3edafc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,8 @@ [run] -branch = True +# Use statement coverage rather than branch coverage because +# COVERAGE_CORE=sysmon can make branch coverage slower rather than faster. See +# https://github.com/nedbat/coveragepy/issues/1812 for more details. +branch = False source = sklearn parallel = True omit = diff --git a/.github/workflows/cuda-ci.yml b/.github/workflows/cuda-ci.yml index 80bebf1437ffc..59c86f15926b1 100644 --- a/.github/workflows/cuda-ci.yml +++ b/.github/workflows/cuda-ci.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v4 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v2.22.0 env: CIBW_BUILD: cp312-manylinux_x86_64 CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 @@ -71,6 +71,6 @@ jobs: conda activate sklearn python -c "import sklearn; sklearn.show_versions()" - SCIPY_ARRAY_API=1 pytest --pyargs sklearn -k 'array_api' + SCIPY_ARRAY_API=1 pytest --pyargs sklearn -k 'array_api' -v # Run in /home/runner to not load sklearn from the checkout repo working-directory: /home/runner diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e2de3bbde583b..0ef75cdcce660 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -31,6 +31,7 @@ jobs: - name: Install dependencies run: | + curl https://raw.githubusercontent.com/${{ github.repository }}/main/build_tools/shared.sh --retry 5 -o ./build_tools/shared.sh source build_tools/shared.sh # Include pytest compatibility with mypy pip install pytest $(get_dep ruff min) $(get_dep mypy min) $(get_dep black min) cython-lint diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml index 584a3dabf9886..e580106f6a7e5 100644 --- a/.github/workflows/publish_pypi.yml +++ b/.github/workflows/publish_pypi.yml @@ -39,13 +39,13 @@ jobs: run: | python build_tools/github/check_wheels.py - name: Publish package to TestPyPI - uses: pypa/gh-action-pypi-publish@fb13cb306901256ace3dab689990e13a5550ffaa # v1.11.0 + uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 with: repository-url: https://test.pypi.org/legacy/ print-hash: true if: ${{ github.event.inputs.pypi_repo == 'testpypi' }} - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@fb13cb306901256ace3dab689990e13a5550ffaa # v1.11.0 + uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 # v1.12.3 if: ${{ github.event.inputs.pypi_repo == 'pypi' }} with: print-hash: true diff --git a/.github/workflows/update-lock-files.yml b/.github/workflows/update-lock-files.yml index 656f608f4814a..0b8fdd0aed322 100644 --- a/.github/workflows/update-lock-files.yml +++ b/.github/workflows/update-lock-files.yml @@ -22,6 +22,9 @@ jobs: - name: scipy-dev update_script_args: "--select-tag scipy-dev" additional_commit_message: "[scipy-dev]" + - name: free-threaded + update_script_args: "--select-tag free-threaded" + additional_commit_message: "[free-threaded]" - name: cirrus-arm update_script_args: "--select-tag arm" additional_commit_message: "[cirrus arm]" diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c3bda80d2ca0c..a690010fce9c4 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -73,6 +73,10 @@ jobs: - os: windows-latest python: 313 platform_id: win_amd64 + - os: windows-latest + python: 313t + platform_id: win_amd64 + free_threaded_support: True # Linux 64 bit manylinux2014 - os: ubuntu-latest diff --git a/README.rst b/README.rst index 4ac297063c26e..e560b2269c17c 100644 --- a/README.rst +++ b/README.rst @@ -187,16 +187,16 @@ Communication - Logos & Branding: https://github.com/scikit-learn/scikit-learn/tree/main/doc/logos - Blog: https://blog.scikit-learn.org - Calendar: https://blog.scikit-learn.org/calendar/ -- Twitter: https://twitter.com/scikit_learn - Stack Overflow: https://stackoverflow.com/questions/tagged/scikit-learn - GitHub Discussions: https://github.com/scikit-learn/scikit-learn/discussions - Website: https://scikit-learn.org - LinkedIn: https://www.linkedin.com/company/scikit-learn +- Bluesky: https://bsky.app/profile/scikit-learn.org +- Mastodon: https://mastodon.social/@sklearn@fosstodon.org - YouTube: https://www.youtube.com/channel/UCJosFjYm0ZYVUARxuOZqnnw/playlists - Facebook: https://www.facebook.com/scikitlearnofficial/ - Instagram: https://www.instagram.com/scikitlearnofficial/ - TikTok: https://www.tiktok.com/@scikit.learn -- Mastodon: https://mastodon.social/@sklearn@fosstodon.org - Discord: https://discord.gg/h9qyrK8Jc8 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fc4010e95176e..c5ad86bf0caa8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -83,10 +83,10 @@ jobs: ) ) matrix: - pylatest_pip_free_threaded: + pylatest_free_threaded: PYTHON_GIL: '0' - DISTRIB: 'pip-free-threaded' - LOCK_FILE: './build_tools/azure/cpython_free_threaded_lock.txt' + DISTRIB: 'conda-free-threaded' + LOCK_FILE: './build_tools/azure/pylatest_free_threaded_linux-64_conda.lock' COVERAGE: 'false' - job: Linux_Nightly_Pyodide diff --git a/build_tools/azure/cpython_free_threaded_lock.txt b/build_tools/azure/cpython_free_threaded_lock.txt deleted file mode 100644 index 91b5021b05b4b..0000000000000 --- a/build_tools/azure/cpython_free_threaded_lock.txt +++ /dev/null @@ -1,35 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.13 -# by the following command: -# -# pip-compile --output-file=/scikit-learn/build_tools/azure/cpython_free_threaded_lock.txt /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -# -execnet==2.1.1 - # via pytest-xdist -iniconfig==2.0.0 - # via pytest -joblib==1.4.2 - # via -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -meson==1.4.1 - # via meson-python -meson-python==0.16.0 - # via -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -ninja==1.11.1.1 - # via -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -packaging==24.0 - # via - # meson-python - # pyproject-metadata - # pytest -pluggy==1.5.0 - # via pytest -pyproject-metadata==0.8.0 - # via meson-python -pytest==8.2.2 - # via - # -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt - # pytest-xdist -pytest-xdist==3.6.1 - # via -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -threadpoolctl==3.5.0 - # via -r /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt diff --git a/build_tools/azure/cpython_free_threaded_requirements.txt b/build_tools/azure/cpython_free_threaded_requirements.txt deleted file mode 100644 index bdcb169bac3ae..0000000000000 --- a/build_tools/azure/cpython_free_threaded_requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -# To generate cpython_free_threaded_lock.txt, use the following command: -# docker run -v $PWD:/scikit-learn -it ubuntu bash -c 'export DEBIAN_FRONTEND=noninteractive; apt-get -yq update; apt-get install software-properties-common ccache -y; add-apt-repository --yes ppa:deadsnakes/nightly; apt-get update -y; apt-get install -y --no-install-recommends python3.13-dev python3.13-venv python3.13-nogil; python3.13t -m venv /venvs/myenv; source /venvs/myenv/bin/activate; pip install pip-tools; pip-compile /scikit-learn/build_tools/azure/cpython_free_threaded_requirements.txt -o /scikit-learn/build_tools/azure/cpython_free_threaded_lock.txt' - -# The reason behind it is that you need python-3.13t to generate the pip lock -# file. For pure Python wheel this does not really matter. But when there are -# cython, numpy and scipy releases that have a CPython 3.13 free-threaded -# wheel, we can add them here and this is important that the Python 3.13 -# free-threaded wheel is picked up in the lock-file -joblib -threadpoolctl -pytest -pytest-xdist -ninja -meson-python diff --git a/build_tools/azure/debian_32bit_lock.txt b/build_tools/azure/debian_32bit_lock.txt index 3a0185eead5d3..35fe32712c20c 100644 --- a/build_tools/azure/debian_32bit_lock.txt +++ b/build_tools/azure/debian_32bit_lock.txt @@ -4,7 +4,7 @@ # # pip-compile --output-file=build_tools/azure/debian_32bit_lock.txt build_tools/azure/debian_32bit_requirements.txt # -coverage[toml]==7.6.4 +coverage[toml]==7.6.10 # via pytest-cov cython==3.0.11 # via -r build_tools/azure/debian_32bit_requirements.txt @@ -12,13 +12,13 @@ iniconfig==2.0.0 # via pytest joblib==1.4.2 # via -r build_tools/azure/debian_32bit_requirements.txt -meson==1.6.0 +meson==1.6.1 # via meson-python meson-python==0.17.1 # via -r build_tools/azure/debian_32bit_requirements.txt -ninja==1.11.1.1 +ninja==1.11.1.3 # via -r build_tools/azure/debian_32bit_requirements.txt -packaging==24.1 +packaging==24.2 # via # meson-python # pyproject-metadata @@ -27,7 +27,7 @@ pluggy==1.5.0 # via pytest pyproject-metadata==0.9.0 # via meson-python -pytest==8.3.3 +pytest==8.3.4 # via # -r build_tools/azure/debian_32bit_requirements.txt # pytest-cov diff --git a/build_tools/azure/install.sh b/build_tools/azure/install.sh index 315c9a4e9d4a1..c009e2972036e 100755 --- a/build_tools/azure/install.sh +++ b/build_tools/azure/install.sh @@ -41,17 +41,6 @@ pre_python_environment_install() { apt-get install -y python3-dev python3-numpy python3-scipy \ python3-matplotlib libopenblas-dev \ python3-virtualenv python3-pandas ccache git - - # TODO for now we use CPython 3.13 from Ubuntu deadsnakes PPA. When CPython - # 3.13 is released (scheduled October 2024) we can use something more - # similar to other conda+pip based builds - elif [[ "$DISTRIB" == "pip-free-threaded" ]]; then - sudo apt-get -yq update - sudo apt-get install -yq ccache - sudo apt-get install -yq software-properties-common - sudo add-apt-repository --yes ppa:deadsnakes/nightly - sudo apt-get update -yq - sudo apt-get install -yq --no-install-recommends python3.13-dev python3.13-venv python3.13-nogil fi } @@ -68,30 +57,27 @@ check_packages_dev_version() { python_environment_install_and_activate() { if [[ "$DISTRIB" == "conda"* ]]; then create_conda_environment_from_lock_file $VIRTUALENV $LOCK_FILE - source activate $VIRTUALENV + activate_environment elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" ]]; then python3 -m virtualenv --system-site-packages --python=python3 $VIRTUALENV - source $VIRTUALENV/bin/activate + activate_environment pip install -r "${LOCK_FILE}" - elif [[ "$DISTRIB" == "pip-free-threaded" ]]; then - python3.13t -m venv $VIRTUALENV - source $VIRTUALENV/bin/activate - pip install -r "${LOCK_FILE}" - # TODO you need pip>=24.1 to find free-threaded wheels. This may be - # removed when the underlying Ubuntu image has pip>=24.1. - pip install 'pip>=24.1' - # TODO When there are CPython 3.13 free-threaded wheels for numpy, - # scipy and cython move them to - # build_tools/azure/cpython_free_threaded_requirements.txt. For now we - # install them from scientific-python-nightly-wheels - dev_anaconda_url=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple - dev_packages="numpy scipy Cython" - pip install --pre --upgrade --timeout=60 --extra-index $dev_anaconda_url $dev_packages --only-binary :all: fi - if [[ "$DISTRIB" == "conda-pip-scipy-dev" ]]; then + # Install additional packages on top of the lock-file in specific cases + if [[ "$DISTRIB" == "conda-free-threaded" ]]; then + # TODO: we install scipy with pip. When there is a conda-forge package, + # we can update build_tools/update_environments_and_lock_files.py and + # remove the line below + pip install scipy --only-binary :all: + # TODO: we install cython 3.1 alpha from pip. When there is a conda-forge package, + # we can update build_tools/update_environments_and_lock_files.py and + # remove the line below + pip install --pre cython --only-binary :all: + + elif [[ "$DISTRIB" == "conda-pip-scipy-dev" ]]; then echo "Installing development dependency wheels" dev_anaconda_url=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple dev_packages="numpy scipy pandas Cython" diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock index fdd6ef65da174..f92b3eb1bf335 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock @@ -3,49 +3,52 @@ # input_hash: 93ee312868bc5df4bdc9b2ef07f938f6a5922dfe2375c4963a7c63d19c5d87f6 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 -https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2023.2.0-h84fe81f_50496.conda#7af9fd0b2d7219f4a4200a34561340f6 -https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda#0424ae29b104430108f5218a66db7260 +https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2024.2.2-ha957f24_16.conda#42b0d14354b5910a9f41e29289914f6b +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.13-5_cp313.conda#381bbd2a92c863f640a55b6ff3c35161 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.3-h024ca30_0.conda#d36687dc90337917a84a96a45111ad59 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.6-h024ca30_0.conda#96e42ccbd3c067c1713ff5f2d2169247 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 -https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_1.conda#e12057a66af8f2a38a839754ca4481e9 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 +https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda#7df50d44d4a14d6c31a2c54f2cd92157 https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df -https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.9.31-hb9d3cd8_0.conda#75f7776e1c9af78287f055ca34797517 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.2-heb4867d_0.conda#2b780c0338fc0ffa678ac82c54af51fd +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.10.6-hb9d3cd8_0.conda#d7d4680337a14001b0e043e96529409b +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda#e2775acf57efd5af15b8e3d1d74d72d3 https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.9.0-hb9d3cd8_1.conda#1e936bd23d737aac62a18e9a1e7f8b18 https://conda.anaconda.org/conda-forge/linux-64/libuv-1.49.2-hb9d3cd8_0.conda#070e3c9ddab77e38799d5c30b109c633 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.8.0-hd3f4568_0.conda#0902512e7a2de9722697fb011db07a54 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.0-hf20e7d7_0.conda#84412135f9c1dd8985741e9c351f499a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.0-hf20e7d7_0.conda#ff265c3736cdac819c8adb844e0557d8 -https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.0-hf20e7d7_0.conda#e54103489d34bd5a106b9298dc28c848 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.8.1-h1a47875_3.conda#55a8561fdbbbd34f50f57d9be12ed084 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.0-h4e1184b_5.conda#3f4c1197462a6df2be6dc8241828fe93 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.1-h4e1184b_4.conda#a5126a90e74ac739b00564a4c7ddcc36 +https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.2-h4e1184b_4.conda#74e8c3e4df4ceae34aa2959df4b28101 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda#d411fc29e338efb48c5fd4576d71d881 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 -https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_h5888daf_1.conda#e1f604644fe8d78e22660e2fec6756bc +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_hbbce691_4.conda#488f260ccda0afaf08acb286db439c2f https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 @@ -54,26 +57,23 @@ https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2# https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 -https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 +https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-h4bc722e_0.conda#aeb98fdeb2e8f25d43ef71fbacbeec80 https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hf672d98_0.conda#be2de152d8073ef1c01b7728475f2fe7 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 -https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.8.0-h166bdaf_0.tar.bz2#ede4266dc02e875fe1ea77b25dd43747 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 -https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe -https://conda.anaconda.org/conda-forge/linux-64/s2n-1.5.6-h0e56266_0.conda#54752411d7559a8bbd4c0204a8f1cf35 -https://conda.anaconda.org/conda-forge/linux-64/sleef-3.7-h1b44611_0.conda#f8b9a3928def0a7f4e37c67045542584 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 +https://conda.anaconda.org/conda-forge/linux-64/s2n-1.5.10-hb5b8611_0.conda#999f3673f2a011f59287f2969e3749e4 +https://conda.anaconda.org/conda-forge/linux-64/sleef-3.7-h1b44611_2.conda#4792f3259c6fdc0b730563a85b211dc0 +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda#3b3e64af585eadfb52bb90b553db5edf https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.15.0-h17eb868_2.conda#bb03f4ce96deea2175fc3ec17b2c1c04 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.15.3-h831e299_5.conda#80dd9f0ddf935290d1dc00ec75ff3023 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb @@ -83,160 +83,154 @@ https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.c https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2#c965a5aa0d5c1c37ffc62dff36e28400 -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda#19e57602824042dfd0446292ef90488b -https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.27.5-h5b01275_2.conda#66ed3107adbdfc25ba70454ba11e6d1e -https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2024.07.02-hbbce691_1.conda#2124de47357b7a516c0a3efd8f88c143 +https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.28.3-h6128344_1.conda#d8703f1ffe5a06356f06467f1d0b9464 +https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2024.07.02-hbbce691_2.conda#b2fede24428726dd867611664fb372e8 https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.21.0-h0e7cc3e_0.conda#dcb95c0a98ba9ff737f7ae482aef7833 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.0-h68c3b0c_2.conda#a08831d82df7546a599095b33f3cae2a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.9.0-hfad4ed3_3.conda#01bc29be557b8c7c1963f7ad7185529a +https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.0-h7959bf6_11.conda#9b3fb60fe57925a92f399bc3fc42eccf +https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.9.2-hefd7a92_4.conda#5ce4df662d32d3123ea8da15571b6f51 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h90cbb55_3.conda#2eeb50cab6652538eee8fc0bc3340c81 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 -https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.2-h690cf93_1.conda#0044701dd48af57d3d5467a704ef9ebd -https://conda.anaconda.org/conda-forge/linux-64/python-3.12.7-hc5c86c4_0_cpython.conda#0515111a9cdf69f83278f7c197db9807 -https://conda.anaconda.org/conda-forge/linux-64/re2-2024.07.02-h77b4e00_1.conda#01093ff37c1b5e6bf9f17c0116747d11 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 +https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.3-h12ee42a_2.conda#4f6f9f3f80354ad185e276c120eac3f0 +https://conda.anaconda.org/conda-forge/linux-64/python-3.13.1-ha99a958_102_cp313.conda#6e7535f1d1faf524e9210d2689b3149b +https://conda.anaconda.org/conda-forge/linux-64/re2-2024.07.02-h9925aae_2.conda#e84ddf12bde691e8ec894b00ea829ddf https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 -https://conda.anaconda.org/conda-forge/noarch/array-api-compat-1.9.1-pyhd8ed1ab_0.conda#f2328337441baa8f669d2a830cfd0097 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.8.0-h56a2c13_4.conda#44a599a9c2c7e5d75e062457ddc6666a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.11.0-h407ecb8_2.conda#f9fcf88ac9d34b2bfe70429064d7744c -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e +https://conda.anaconda.org/conda-forge/noarch/array-api-compat-1.10.0-pyhd8ed1ab_0.conda#e399bc184553ca13cb068d272a995f48 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.8.0-hb921021_15.conda#c79d50f64cffa5ad51ecc1a81057962f +https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.11.0-h11f4f37_12.conda#96c3e0221fa2da97619ee82faa341a73 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d https://conda.anaconda.org/conda-forge/linux-64/ccache-4.10.1-h065aff2_0.conda#d6b48c138e0c8170a6fe9c136e063540 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.7-py312hd8ed1ab_0.conda#f0d1309310498284ab13c9fd73db4781 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.1-py313hd8ed1ab_102.conda#03f9b71509b4a492d7da023bf825ebbd +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb -https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py312h8fd2918_3.conda#21e433caf1bb1e4c95832f8bb731d64c +https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py313hc66aa0d_3.conda#1778443eb12b2da98428fa69152a2a2e https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_0.conda#916f8ec5dd4128cd5f207a3c4c07b2c6 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.10.0-pyhff2d567_0.conda#816dbc4679a64e4417cd1385d661bb31 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 -https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py312h68727a3_0.conda#444266743652a4f1538145e9362f6d3b +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_1.conda#d692e9ba6f92dc51484bf3477e36ce7c +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.12.0-pyhd8ed1ab_0.conda#e041ad4c43ab5e10c74587f95378ebc7 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 +https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py313h33d0bda_0.conda#9862d13a5e466273d5a4738cffcb8d6c https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.10.1-hbbe4b11_0.conda#6e801c50a40301f6978c53976917b277 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd -https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.65.5-hf5c653b_0.conda#3b0048cabc6815a4d8874a0240519d32 -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.11.1-h332b0f4_0.conda#2b3e0081006dc21e8bf53a91c83a055c +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a +https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.67.1-h25350d4_1.conda#0c6497a760b99a926c7c12b74951a39c +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.2-default_h0d58e46_1001.conda#804ca9e91bcaea0824a341d55b1684f2 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda#e71f31f8cfb0a91439f2086fc8aa0461 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py312h178313f_0.conda#a755704ea0e2503f8c227d84829a8e81 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py313h8060acc_1.conda#21b62c55924f01b6eef6827167b46acb https://conda.anaconda.org/conda-forge/linux-64/mpc-1.3.1-h24ddda3_1.conda#aa14b9a5196a6d8dd364164b7ce56acf -https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_0.conda#dbf6e2d89137da32fa6670f3bffc024e +https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_1.conda#3585aa87c43ab15b167b574cd73b057b https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/noarch/networkx-3.4.2-pyhd8ed1ab_1.conda#1d4c088869f206413c59acdd309908b7 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/noarch/networkx-3.4.2-pyh267e887_2.conda#fd40bf7f7f4bc4b647dc8512053d9873 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh145f28c_2.conda#76601b0ccfe1fe13a21a5f8813cb38de +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_1.conda#c0def296b2f6d2dd7b030c2a7f66bb1f https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h66e93f0_1.conda#af648b62462794649066366af4ecd5b0 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py312h66e93f0_1.conda#588486a61153f94c7c13816f7069e440 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py313h536fd9c_0.conda#5f5cbdd527d2e74e270d8b6255ba714f +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda#d17f13df8b65464ca316cbc000a3cb64 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda#2ccd714aa2242315acaf0a67faea780b https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.7.0-hadeddc1_5.conda#429e7497e7f08bc470d2872147d8ef6d +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.7.7-hf454442_0.conda#947c82025693bebd557f782bb5d6b469 https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.14.0-h5cfcd09_0.conda#0a8838771cc2e985cd295e01ae83baf1 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py312h178313f_0.conda#a32fbd2322865ac80c7db74c553f5306 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py312h178313f_1.conda#bbbf5fa5cab622c33907bc8d7eeea9f7 -https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py312h7201bc8_2.conda#af9faf103fb57241246416dc70b466f7 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 -https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.30.0-h438788a_0.conda#ab8466a39822527f7786b0d0b2aac223 -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py312h7b63e92_0.conda#385f46a4df6f97892503a841121a9acf -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.10-py313h8060acc_0.conda#b76045c1b72b2db6e936bc1226a42c99 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.55.3-py313h8060acc_1.conda#f89b4b415c5be34d24f74f30954792b5 +https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py313h11186cd_3.conda#846a773cdc154eda7b86d7f4427432f2 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.5-pyhd8ed1ab_0.conda#2752a6ed44105bfb18c9bef1177d9dcd +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.33.0-h2b5623c_1.conda#61829a8dd5f4e2327e707572065bae41 +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py313h8db990d_0.conda#1e86810c6c3fb6d6aebdba26564eb2e8 +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-hceb3a55_1.conda#ba7726b8df7b9d34ea80e82b097a4893 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f -https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.29.0-h73f0fd4_6.conda#19f6d559f3be939046d2ac5c7b2ded7a +https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.29.7-hd92328a_7.conda#02b95564257d5c3db9c06beccf711f95 https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.10.0-h113e628_0.conda#73f73f60854f325a55f1d31459f2ab73 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.8.0-h736e048_1.conda#13de36be8de3ae3f05ba127631599213 -https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.30.0-h0121fbd_0.conda#ad86b6c98964772688298a727cb20ef8 -https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/linux-64/mkl-2023.2.0-h84fe81f_50496.conda#81d4a1a57d618adf0152db973d93b2ad -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda#cb8a11b6d209e3d85e5094bdbd9ebd9c -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.33.0-h0121fbd_1.conda#b0cfb5044685a7a9fa43ae669124f0a0 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/linux-64/mkl-2024.2.2-ha957f24_16.conda#1459379c79dda834673426504d52b319 +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda#79963c319d1be62c8fd3e34555816e01 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda#68085d736d2b2f54498832b65059875d -https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.407-h6a6dca0_6.conda#3c25988c0b0a2085b4df578b7160d963 +https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.458-hc430e4a_4.conda#aeefac461bea1f126653c1285cf5af08 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.13.0-h3cf044e_1.conda#7eb66060455c7a47d9dcdbfa9f46579b -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-20_linux64_mkl.conda#8bf521f6007b0b0eb91515a1165b5d85 -https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2023.2.0-ha770c72_50496.conda#3b4c50e31ff098b18a450e4f5f860adf -https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.0-h6e8976b_0.conda#6d1c5d2d904d24c17cbb538a95855a4e +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_mkl.conda#60463d3ec26e0860bfc7fc1547e005ef +https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2024.2.2-ha770c72_16.conda#140891ea14285fc634353b31e9e40a95 +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.1-h588cce1_2.conda#5d2f1f29c025a110a43f9946527623ab https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.12.0-ha633028_1.conda#7c1980f89dd41b097549782121a73490 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-20_linux64_mkl.conda#7a2972758a03adc92d856072c71c9170 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-20_linux64_mkl.conda#4db0cd03efcdab535f6f066aca4cddbb -https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.0.2-py312h91f0f75_0.conda#ec3da81d5f9d3612b227e09a650f7bf2 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-18.0.0-ha5db6c2_0_cpu.conda#55f4011e75175bfbbc10f8e5998345d4 -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-20_linux64_mkl.conda#3dea5e9be386b963d7f4368966e238b3 -https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.4.1-cpu_mkl_hc74595f_102.conda#1845dcc1389ff54a038027b96fbce318 -https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py312h58c1407_0.conda#dfdbc12e6d81889ba4c494a23f23eba8 -https://conda.anaconda.org/conda-forge/noarch/array-api-strict-2.1-pyhd8ed1ab_0.conda#15cc819ed82470249cbf1337791bc5ff -https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-20_linux64_mkl.conda#079d50df2338a3d47522d7e84c3dfbf6 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py312h68727a3_2.conda#ff28f374b31937c048107521c814791e -https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-18.0.0-h5888daf_0_cpu.conda#8771a1fcc6d8bf2fd18cc57d778f90a3 -https://conda.anaconda.org/conda-forge/linux-64/libparquet-18.0.0-h6bd9018_0_cpu.conda#f9efb8ef19962dc9d87b29e667a13287 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py312hf9745cd_1.conda#8bce4f6caaf8c5448c7ac86d87e26b4b -https://conda.anaconda.org/conda-forge/linux-64/polars-1.12.0-py312hfe7c9be_0.conda#47b6df7e8b629d1257a6f971b88c15de -https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-18.0.0-py312h01725c0_0_cpu.conda#9100ae6cdd482666b38fa20e7819b385 -https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.4.1-cpu_mkl_py312ha1f5ba4_102.conda#186d21edb5f86bcd6516e3d10edc38c0 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py312h62794b6_1.conda#b43233a9e2f62fb94affe5607ea79473 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.120-mkl.conda#9444330235a4828878cbe9c897ba0aa3 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-18.0.0-h5888daf_0_cpu.conda#5c121a2d50b068076ff4f2b6d68dbca5 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py312hd3ec401_1.conda#2f4f3854f23be30de29e9e4d39758349 -https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py312hc39e661_1.conda#372efc32220f0dfb603e5b31ffaefa23 -https://conda.anaconda.org/conda-forge/linux-64/pytorch-cpu-2.4.1-cpu_mkl_py312h09a6fac_102.conda#3579b30b19e9aa1ed58bd971203c8590 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-18.0.0-he882d9a_0_cpu.conda#1d73c2c8cabb70f9bf1dd36222ef7b25 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.2-py312h7900ff3_1.conda#07d5646ea9f22f4b1c46c2947d1b2f58 -https://conda.anaconda.org/conda-forge/linux-64/pyarrow-18.0.0-py312h9cebb41_0.conda#e110b1f861e749bc1dd48ad5467adab8 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_mkl.conda#760c109bfe25518d6f9af51d7af8b9f3 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-26_linux64_mkl.conda#84112111a50db59ca64153e0054fa73e +https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.1-py313h5f61773_0.conda#689386169e9c1e4879e81384de4d47e9 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-18.1.0-hd595efa_7_cpu.conda#08d4aff5ee6dee9a1b9ab13fca927697 +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-26_linux64_mkl.conda#ffd5d8a606a1bd0e914f276dc44b42ee +https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.5.1-cpu_mkl_he8ec5d7_108.conda#a070bb62918bea542fbb092c2abd7004 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.1-py313hb30382a_0.conda#bacc73d89e22828efedf31fdc4b54b4e +https://conda.anaconda.org/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_1.conda#02e7a32986412d3aaf97095d17120757 +https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-26_linux64_mkl.conda#261acc954f47b7bf11d841ad8dd91d08 +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.1-py313h33d0bda_0.conda#6b6768e7c585d7029f79a04cbc4cbff0 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-18.1.0-hcb10f89_7_cpu.conda#12d84228204c56fec6ed113288014d11 +https://conda.anaconda.org/conda-forge/linux-64/libparquet-18.1.0-h081d1f1_7_cpu.conda#b97013ef4e1dd2cf11594f06d5b5e83a +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py313ha87cce1_1.conda#c5d63dd501db554b84a30dea33824164 +https://conda.anaconda.org/conda-forge/linux-64/polars-1.17.1-py313hae41bca_0.conda#ee6fe8aba7963d1229645a3f831e3744 +https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-18.1.0-py313he5f92c8_0_cpu.conda#5380e12f4468e891911dbbd4248b521a +https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.5.1-cpu_mkl_py313_h90df46e_108.conda#f192f56caccbdbdad81e015a64294e92 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.15.0-py313hc93385a_0.conda#cd05940add8516cad1407b7dac647526 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.126-mkl.conda#4af53f2542f5adbfc2290f084f3a99fa +https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-18.1.0-hcb10f89_7_cpu.conda#0a81eb63d7cd150f598c752e86388d57 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.0-py313h129903b_0.conda#ab5b84154e1d9e41d4f11aea76d74096 +https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py313hf0ab243_1.conda#4c769bf3858f424cb2ecf952175ec600 +https://conda.anaconda.org/conda-forge/linux-64/pytorch-cpu-2.5.1-cpu_mkl_hc60beec_108.conda#8135dc47e3dcbd4b3d83ad5b48e50ecb +https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-18.1.0-h08228c5_7_cpu.conda#e128def53c133e8a23ac00cd4a479335 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.0-py313h78bf25f_0.conda#8db95cf01990edcecf616ed65a986fde +https://conda.anaconda.org/conda-forge/linux-64/pyarrow-18.1.0-py313h78bf25f_0.conda#a11d880ceedc33993c6f5c14a80ea9d3 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock index 9dbaa15306088..d67a5e8ffc606 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_osx-64_conda.lock @@ -2,29 +2,28 @@ # platform: osx-64 # input_hash: e7c2bc2b07721ef735f30d3b1cf0b2a780b5bf5c138d9d18ad174611bfbd32bf @EXPLICIT -https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.8.30-h8857fd0_0.conda#b7e5424e7f06547a903d28e4651dbb21 +https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.12.14-h8857fd0_0.conda#b7b887091c99ed2e74845e75e9128410 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9 https://conda.anaconda.org/conda-forge/noarch/libgfortran-devel_osx-64-13.2.0-h80d4556_3.conda#3a689f0d733e67828ad00eac5f3cf26e https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hd75f5a5_2.conda#6c3628d047e151efba7cf08c5e54d1ca https://conda.anaconda.org/conda-forge/osx-64/libjpeg-turbo-3.0.0-h0dc2134_1.conda#72507f8e3961bc968af17435060b6dd6 -https://conda.anaconda.org/conda-forge/osx-64/libwebp-base-1.4.0-h10d778d_0.conda#b2c0047ea73819d992484faacbbe1c24 https://conda.anaconda.org/conda-forge/osx-64/mkl-include-2023.2.0-h6bab518_50500.conda#835abb8ded5e26f23ea6996259c7972e https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.13-5_cp313.conda#927a2186f1f997ac018d67c4eece90a6 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 -https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2#a72f9d4ea13d55d745ff1ed594747f10 https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda#7ed4301d437b59045be7e051a0308211 -https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda#d68d48a3060eb5abdc1cdc8e2a3a5966 https://conda.anaconda.org/conda-forge/osx-64/libbrotlicommon-1.1.0-h00291cd_2.conda#58f2c4bdd56c46cc7451596e4ae68e0b -https://conda.anaconda.org/conda-forge/osx-64/libcxx-19.1.3-hf95d169_0.conda#86801fc56d4641e3ef7a63f5d996b960 -https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.22-h00291cd_0.conda#a15785ccc62ae2a8febd299424081efb -https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.3-hac325c4_0.conda#c1db99b0a94a2f23bd6ce39e2d314e07 +https://conda.anaconda.org/conda-forge/osx-64/libcxx-19.1.6-hf95d169_1.conda#1bad6c181a0799298aad42fc5a7e98b7 +https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.23-he65b83e_0.conda#120f8f7ba6a8defb59f4253447db4bb4 +https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.4-h240833e_0.conda#20307f4049a735a78a29073be1be2626 +https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.6.3-hd471939_1.conda#f9e9205fed9c664421c1c09f0b90ce6d https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hfdf4475_0.conda#ed625b2e59dff82859c23dd24774156b +https://conda.anaconda.org/conda-forge/osx-64/libwebp-base-1.5.0-h6cf52b4_0.conda#5e0cefc99a231ac46ba21e27ae44689f https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda#003a54a4e32b02f7355b50a837e699da -https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-19.1.3-hf78d878_0.conda#18a8498d57d871da066beaa09263a638 +https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-19.1.6-ha54dae1_0.conda#4fe4d62071f8a3322ffb6588b49ccbb8 https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-hf036a51_1.conda#e102bbf8a6ceeaf429deab8032fc8977 -https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.2-hd23fc13_0.conda#2ff47134c8e292868a4609519b1ea3b6 +https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.0-hc426f3f_1.conda#eaae23dbfc9ec84775097898526c72ea https://conda.anaconda.org/conda-forge/osx-64/pthread-stubs-0.4-h00291cd_1002.conda#8bcf980d2c6b17094961198284b8e862 -https://conda.anaconda.org/conda-forge/osx-64/xorg-libxau-1.0.11-h00291cd_1.conda#c6cc91149a08402bbb313c5dc0142567 +https://conda.anaconda.org/conda-forge/osx-64/xorg-libxau-1.0.12-h6e16a3a_0.conda#4cf40e60b444d56512a64f39d12c20bd https://conda.anaconda.org/conda-forge/osx-64/xorg-libxdmcp-1.1.5-h00291cd_0.conda#9f438e1b6f4e73fd9e6d78bfe7c36743 https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda#427101d13f19c4974552a4e5b072eef1 https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda#d06222822a9144918333346f145b68c6 @@ -34,9 +33,9 @@ https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h00291cd_2.cond https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-17.0.6-h8f8a49f_6.conda#faa013d493ffd2d5f2d2fc6df5f98f2e https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-13.2.0-h2873a65_3.conda#e4fb4d23ec2870ff3c40d10afe305aec https://conda.anaconda.org/conda-forge/osx-64/libpng-1.6.44-h4b8f8c9_0.conda#f32ac2c8dd390dbf169f550887ed09d9 -https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.47.0-h2f8c449_1.conda#af445c495253a871c3d809e1199bb12b +https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.47.2-hdb6dae5_0.conda#44d9799fda97eb34f6d88ac1e3eb0ea6 https://conda.anaconda.org/conda-forge/osx-64/libxcb-1.17.0-hf1f96e2_0.conda#bbeca862892e2898bdb45792a61c4afc -https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.4-h12808cf_2.conda#0649b977d9e3d2fd579148643884535e +https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.13.5-he8ee3e7_1.conda#9379f216f9132d0d3cdeeb10af165262 https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.1-h3c5361c_0.conda#a0ebabd021c8191aeb82793fe43cfdcb https://conda.anaconda.org/conda-forge/osx-64/qhull-2020.2-h3c5361c_5.conda#dd1ea9ff27c93db7c01a7b7656bd4ad4 https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e @@ -48,83 +47,82 @@ https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.6-h915ae27_0.conda#4cb2cd https://conda.anaconda.org/conda-forge/osx-64/brotli-bin-1.1.0-h00291cd_2.conda#049933ecbf552479a12c7917f0a4ce59 https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h60636b9_2.conda#25152fce119320c980e5470e64834b50 https://conda.anaconda.org/conda-forge/osx-64/libgfortran-5.0.0-13_2_0_h97931a8_3.conda#0b6e23a012ee7a9a5f6b244f5a92c1d5 -https://conda.anaconda.org/conda-forge/osx-64/libhwloc-2.11.1-default_h456cccd_1000.conda#a14989f6bbea46e6ec4521a403f63ff2 +https://conda.anaconda.org/conda-forge/osx-64/libhwloc-2.11.2-default_h4cdd727_1001.conda#52bbb10ac083c563d00df035c94f9a63 https://conda.anaconda.org/conda-forge/osx-64/libllvm17-17.0.6-hbedff68_1.conda#fcd38f0553a99fa279fb66a5bfc2fb28 -https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.0-h583c2ba_1.conda#4b78bcdcc8780cede8b3d090deba874d +https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.7.0-hb77a491_3.conda#6f2f9df7b093d6b33bc0c334acc7d2d9 https://conda.anaconda.org/conda-forge/osx-64/mpfr-4.2.1-haed47dc_3.conda#d511e58aaaabfc23136880d9956fa7a6 -https://conda.anaconda.org/conda-forge/osx-64/python-3.13.0-h0608dab_100_cp313.conda#9603103619775a3f99fe4b58d278775e +https://conda.anaconda.org/conda-forge/osx-64/python-3.13.1-h2334245_102_cp313.conda#bacdbf2fd86557ad1fb862cb2d30d821 https://conda.anaconda.org/conda-forge/osx-64/brotli-1.1.0-h00291cd_2.conda#2db0c38a7f2321c5bdaf32b181e832c7 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/osx-64/cython-3.0.11-py313h496bac6_3.conda#e2ff2f9b266fe869268ed4c4c97e8f34 -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.7-py313h0c4e38b_0.conda#c37fceab459e104e77bb5456e219fc37 https://conda.anaconda.org/conda-forge/osx-64/lcms2-2.16-ha2f27b4_0.conda#1442db8f03517834843666c422238c9b -https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-951.9-h38c89e5_1.conda#423183fc4729ed4b8e167a980aad83ce +https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-951.9-h5ffbe8e_2.conda#8cd0234328c8e9dcc2db757ff8a2ad22 https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp17-17.0.6-default_hb173f14_7.conda#9fb4dfe8b2c3ba1b68b79fcd9a71cb76 https://conda.anaconda.org/conda-forge/osx-64/libhiredis-1.0.2-h2beb688_0.tar.bz2#524282b2c46c9dedf051b3bc2ae05494 https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-17.0.6-hbedff68_1.conda#4260f86b3dd201ad7ea758d783cd5613 https://conda.anaconda.org/conda-forge/osx-64/mpc-1.3.1-h9d8efa1_1.conda#0520855aaae268ea413d6bc913f1384c https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/osx-64/openjpeg-2.5.2-h7310d3a_0.conda#05a14cc9d725dd74995927968d6547e3 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh145f28c_0.conda#ca3afe2d7b893a8c8cdf489d30a2b1a3 -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/osx-64/openjpeg-2.5.3-h7fd6d84_0.conda#025c711177fc3309228ca1a32374458d +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh145f28c_2.conda#76601b0ccfe1fe13a21a5f8813cb38de +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_1.conda#c0def296b2f6d2dd7b030c2a7f66bb1f https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 -https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.13.0-h37c8870_0.conda#89742f5ac7aeb5c44ec2b4c3c6692c3c +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 +https://conda.anaconda.org/conda-forge/osx-64/tbb-2021.13.0-hb890de9_1.conda#284892942cdddfded53d090050b639a5 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/osx-64/tornado-6.4.1-py313ha37c0e0_1.conda#97e88d20d94ad24b7bf0d7b67b14fa90 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/osx-64/tornado-6.4.2-py313h63b0ddb_0.conda#74a3a14f82dc65fa19f4fd4e2eb8da93 https://conda.anaconda.org/conda-forge/osx-64/ccache-4.10.1-hee5fd93_0.conda#09898bb80e196695cea9e07402cff215 -https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1010.6-h98e843e_1.conda#ed757b98aaa22a9e38c5a76191fb477c +https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1010.6-hea4301f_2.conda#70260b63386f080de1aa175dea5d57ac https://conda.anaconda.org/conda-forge/osx-64/clang-17-17.0.6-default_hb173f14_7.conda#809e36447b1bfb87ed1b7fb46339561a -https://conda.anaconda.org/conda-forge/osx-64/coverage-7.6.4-py313h25ec13a_0.conda#3b51dc2570f11e20bb75fa3bd7d88c46 -https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.54.1-py313h25ec13a_1.conda#86e0b9a91e6d6f97f8dbe7591ad22c76 +https://conda.anaconda.org/conda-forge/osx-64/coverage-7.6.10-py313h717bdf5_0.conda#3025d254bcdd0cbff2c7aa302bb96b38 +https://conda.anaconda.org/conda-forge/osx-64/fonttools-4.55.3-py313h717bdf5_1.conda#f69669f8ead50bb3e13f125defbe6ffe https://conda.anaconda.org/conda-forge/osx-64/gfortran_impl_osx-64-13.2.0-h2bc304d_3.conda#57aa4cb95277a27aa0a1834ed97be45b -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/osx-64/ld64-951.9-h0a3eb4e_1.conda#8b8e1a4bd8384bf4b884c9e41636038f -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/osx-64/ld64-951.9-h0a3eb4e_2.conda#c198062cf84f2e797996ac156daffa9e +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 https://conda.anaconda.org/conda-forge/osx-64/mkl-2023.2.0-h54c2260_50500.conda#0a342ccdc79e4fcd359245ac51941e7b -https://conda.anaconda.org/conda-forge/osx-64/pillow-11.0.0-py313h4d44d4f_0.conda#d5a3e556600840a77c61394c48ee52d9 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/osx-64/cctools-1010.6-h5b2de21_1.conda#5a08ae55869b0b1eb7fbee910aa30d19 +https://conda.anaconda.org/conda-forge/osx-64/pillow-11.1.0-py313h0c4f865_0.conda#11b4dd7a814202f2a0b655420f1c1c3a +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e +https://conda.anaconda.org/conda-forge/osx-64/cctools-1010.6-h5b2de21_2.conda#97f24eeeb3509883a6988894fd7c9bbf https://conda.anaconda.org/conda-forge/osx-64/clang-17.0.6-default_he371ed4_7.conda#fd6888f26c44ddb10c9954a2df5765c7 https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-20_osx64_mkl.conda#160fdc97a51d66d51dc782fb67d35205 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 https://conda.anaconda.org/conda-forge/osx-64/mkl-devel-2023.2.0-h694c41f_50500.conda#1b4d0235ef253a1e19459351badf4f9f -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda#cb8a11b6d209e3d85e5094bdbd9ebd9c -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda#79963c319d1be62c8fd3e34555816e01 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/osx-64/clangxx-17.0.6-default_he371ed4_7.conda#4f110486af1272f0d4dee6adc5041fbf https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-20_osx64_mkl.conda#51089a4865eb4aec2bc5c7468bd07f9f https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-20_osx64_mkl.conda#58f08e12ad487fac4a08f90ff0b87aec https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-17.0.6-hf2b8a54_2.conda#98e6d83e484e42f6beebba4276e38145 https://conda.anaconda.org/conda-forge/osx-64/liblapacke-3.9.0-20_osx64_mkl.conda#124ae8e384268a8da66f1d64114a1eda -https://conda.anaconda.org/conda-forge/osx-64/numpy-2.1.3-py313h7ca3f3b_0.conda#b827b0af2098c63435b27b7f4e4d50dd +https://conda.anaconda.org/conda-forge/osx-64/numpy-2.2.1-py313h6ae94ac_0.conda#b2e20a8de4f49e1d55ec3e10b73840c1 https://conda.anaconda.org/conda-forge/osx-64/blas-devel-3.9.0-20_osx64_mkl.conda#cc3260179093918b801e373c6e888e02 https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-17.0.6-h1020d70_2.conda#be4cb4531d4cee9df94bf752455d68de -https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.0-py313hc99daa9_2.conda#572ff94936f32a90610cb9943f8f9d4f +https://conda.anaconda.org/conda-forge/osx-64/contourpy-1.3.1-py313ha0b1807_0.conda#5ae850f4b044294bd7d655228fc236f9 https://conda.anaconda.org/conda-forge/osx-64/pandas-2.2.3-py313h38cdd20_1.conda#ab61fb255c951a0514616e92dd2e18b2 -https://conda.anaconda.org/conda-forge/osx-64/scipy-1.14.1-py313hbd2dc07_1.conda#63098e1999a8f08b82ae921440e6ed0a +https://conda.anaconda.org/conda-forge/osx-64/scipy-1.15.0-py313hd604262_0.conda#ad0e3fcb5d4328802185894d7c37c182 https://conda.anaconda.org/conda-forge/osx-64/blas-2.120-mkl.conda#b041a7677a412f3d925d8208936cb1e2 -https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-17.0.6-h1af8efd_21.conda#6ef491cbc462aae64eaa0213e7ae6222 -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.9.2-py313h04f2f9a_1.conda#e0355aa34089010cce072986cfb9c989 +https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-17.0.6-h1af8efd_23.conda#90132dd643d402883e4fbd8f0527e152 +https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.10.0-py313he981572_0.conda#765ffe9ff0204c094692b08c08b2c0f4 https://conda.anaconda.org/conda-forge/osx-64/pyamg-5.2.1-py313h0322a6a_1.conda#4bda5182eeaef3d2017a2ec625802e1a -https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-17.0.6-hb91bd55_21.conda#d94a0f2c03e7a50203d2b78d7dd9fa25 -https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.9.2-py313habf4b1d_1.conda#5323d57b4ec77c8cdd7475cbdd85072b +https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-17.0.6-h7e5c614_23.conda#615b86de1eb0162b7fa77bb8cbf57f1d +https://conda.anaconda.org/conda-forge/osx-64/matplotlib-3.10.0-py313habf4b1d_0.conda#a1081de6446fbd9049e1bce7d965a3ac https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.8.0-hfc4bf79_1.conda#d6e3cf55128335736c8d4bb86e73c191 -https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-17.0.6-hc3430b7_21.conda#9dbdec57445cac0f0c39aefe3d3900bc +https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-17.0.6-hc3430b7_23.conda#b724718bfe53f93e782fe944ec58029e https://conda.anaconda.org/conda-forge/osx-64/gfortran_osx-64-13.2.0-h18f7dce_1.conda#71d59c1ae3fea7a97154ff0e20b38df3 -https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-17.0.6-hb91bd55_21.conda#cfcbb6790123280b5be7992d392e8194 +https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-17.0.6-h7e5c614_23.conda#78039b25bfcffb920407522839555289 https://conda.anaconda.org/conda-forge/osx-64/gfortran-13.2.0-h2c809b3_1.conda#b5ad3b799b9ae996fcc8aab3a60fb48e https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.8.0-h385f146_1.conda#b72f72f89de328cc907bcdf88b85447d https://conda.anaconda.org/conda-forge/osx-64/fortran-compiler-1.8.0-h33d1f46_1.conda#f3f15da7cbc7be80ea112ecd5dd73b22 diff --git a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock index e4ac139fba46c..ef954cc247339 100644 --- a/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock +++ b/build_tools/azure/pylatest_conda_mkl_no_openmp_osx-64_conda.lock @@ -4,11 +4,11 @@ @EXPLICIT https://repo.anaconda.com/pkgs/main/osx-64/blas-1.0-mkl.conda#cb2c87e85ac8e0ceae776d26d4214c8a https://repo.anaconda.com/pkgs/main/osx-64/bzip2-1.0.8-h6c40b1e_6.conda#96224786021d0765ce05818fa3c59bdb -https://repo.anaconda.com/pkgs/main/osx-64/ca-certificates-2024.9.24-hecd8cb5_0.conda#12955a02cf8b8955d60a42140c507c87 +https://repo.anaconda.com/pkgs/main/osx-64/ca-certificates-2024.11.26-hecd8cb5_0.conda#c1b6397899ce957abf8d1e3428cd3bba https://repo.anaconda.com/pkgs/main/osx-64/jpeg-9e-h46256e1_3.conda#b1d9769eac428e11f5f922531a1da2e0 https://repo.anaconda.com/pkgs/main/osx-64/libbrotlicommon-1.0.9-h6c40b1e_8.conda#8e86dfa34b08bc664b19e1499e5465b8 https://repo.anaconda.com/pkgs/main/osx-64/libcxx-14.0.6-h9765a3e_0.conda#387757bb354ae9042370452cd0fb5627 -https://repo.anaconda.com/pkgs/main/osx-64/libdeflate-1.17-hb664fd8_1.conda#b6116b8db33ea6a5b5287dae70d4a913 +https://repo.anaconda.com/pkgs/main/osx-64/libdeflate-1.22-h46256e1_0.conda#7612fb79e5e76fcd16655c7d026f4a66 https://repo.anaconda.com/pkgs/main/osx-64/libffi-3.4.4-hecd8cb5_1.conda#eb7f09ada4d95f1a26f483f1009d9286 https://repo.anaconda.com/pkgs/main/osx-64/libwebp-base-1.3.2-h46256e1_1.conda#399c11b50e6e7a6969aca9a84ea416b7 https://repo.anaconda.com/pkgs/main/osx-64/llvm-openmp-14.0.6-h0dcd299_0.conda#b5804d32b87dc61ca94561ade33d5f2d @@ -17,15 +17,15 @@ https://repo.anaconda.com/pkgs/main/noarch/tzdata-2024b-h04d1e81_0.conda#9be6947 https://repo.anaconda.com/pkgs/main/osx-64/xz-5.4.6-h6c40b1e_1.conda#b40d69768d28133d8be1843def4f82f5 https://repo.anaconda.com/pkgs/main/osx-64/zlib-1.2.13-h4b97444_1.conda#38e35f7c817fac0973034bfce6706ec2 https://repo.anaconda.com/pkgs/main/osx-64/ccache-3.7.9-hf120daa_0.conda#a01515a32e721c51d631283f991bc8ea -https://repo.anaconda.com/pkgs/main/osx-64/expat-2.6.3-h6d0c2b6_0.conda#7cfb1a4651369640118e6ee80198e682 +https://repo.anaconda.com/pkgs/main/osx-64/expat-2.6.4-h6d0c2b6_0.conda#337f85e792486001ba7aed0fa2f93e64 https://repo.anaconda.com/pkgs/main/osx-64/intel-openmp-2023.1.0-ha357a0b_43548.conda#ba8a89ffe593eb88e4c01334753c40c3 -https://repo.anaconda.com/pkgs/main/osx-64/lerc-3.0-he9d5cce_0.conda#aec2c3dbef836849c9260f05be04f3db +https://repo.anaconda.com/pkgs/main/osx-64/lerc-4.0.0-h6d0c2b6_0.conda#824f87854c58df1525557c8639ce7f93 https://repo.anaconda.com/pkgs/main/osx-64/libbrotlidec-1.0.9-h6c40b1e_8.conda#6338cd7779e614fc16d835990e627e04 https://repo.anaconda.com/pkgs/main/osx-64/libbrotlienc-1.0.9-h6c40b1e_8.conda#2af01a7b3fdbed47ebe5c452c34e5c5d https://repo.anaconda.com/pkgs/main/osx-64/libgfortran5-11.3.0-h9dfd629_28.conda#1fa1a27ee100b1918c3021dbfa3895a3 https://repo.anaconda.com/pkgs/main/osx-64/libpng-1.6.39-h6c40b1e_0.conda#a3c824835f53ad27aeb86d2b55e47804 https://repo.anaconda.com/pkgs/main/osx-64/lz4-c-1.9.4-hcec6c5f_1.conda#aee0efbb45220e1985533dbff48551f8 -https://repo.anaconda.com/pkgs/main/osx-64/ninja-base-1.10.2-haf03e11_5.conda#c857c13129710a61395270656905c4a2 +https://repo.anaconda.com/pkgs/main/osx-64/ninja-base-1.12.1-h1962661_0.conda#9c0a94a811e88f182519d9309cf5f634 https://repo.anaconda.com/pkgs/main/osx-64/openssl-3.0.15-h46256e1_0.conda#3286ae31653124afad386b813a5d17da https://repo.anaconda.com/pkgs/main/osx-64/readline-8.2-hca72f7f_0.conda#971667436260e523f6f7355fdfa238bf https://repo.anaconda.com/pkgs/main/osx-64/tbb-2021.8.0-ha357a0b_0.conda#fb48530a3eea681c11dafb95b3387c0f @@ -37,50 +37,50 @@ https://repo.anaconda.com/pkgs/main/osx-64/mkl-2023.1.0-h8e150cf_43560.conda#85d https://repo.anaconda.com/pkgs/main/osx-64/sqlite-3.45.3-h6c40b1e_0.conda#2edf909b937b3aad48322c9cb2e8f1a0 https://repo.anaconda.com/pkgs/main/osx-64/zstd-1.5.6-h138b38a_0.conda#f4d15d7d0054d39e6a24fe8d7d1e37c5 https://repo.anaconda.com/pkgs/main/osx-64/brotli-1.0.9-h6c40b1e_8.conda#10f89677a3898d0113dc354adf643df3 -https://repo.anaconda.com/pkgs/main/osx-64/libtiff-4.5.1-hcec6c5f_0.conda#e127a800ffd9d300ed7d5e1b026944ec -https://repo.anaconda.com/pkgs/main/osx-64/python-3.12.7-hcd54a6c_0.conda#6eabc1d6b0c0a5dcbf5adfa79f18b95e -https://repo.anaconda.com/pkgs/main/osx-64/coverage-7.6.1-py312h46256e1_0.conda#08c49d882d5749d2d34385050584f014 +https://repo.anaconda.com/pkgs/main/osx-64/libtiff-4.5.1-h6fa9cd1_1.conda#3d7e2cea5c733721750160acb997a90b +https://repo.anaconda.com/pkgs/main/osx-64/python-3.12.8-hcd54a6c_0.conda#54c4f4421ae085eb9e9d63643c272cf3 +https://repo.anaconda.com/pkgs/main/osx-64/coverage-7.6.9-py312h46256e1_0.conda#f8c1547bbf522a600ee795901240a7b0 https://repo.anaconda.com/pkgs/main/noarch/cycler-0.11.0-pyhd3eb1b0_0.conda#f5e365d2cdb66d547eb8c3ab93843aab -https://repo.anaconda.com/pkgs/main/noarch/execnet-1.9.0-pyhd3eb1b0_0.conda#f895937671af67cebb8af617494b3513 +https://repo.anaconda.com/pkgs/main/noarch/execnet-2.1.1-pyhd3eb1b0_0.conda#b3cb797432ee4657d5907b91a5dc65ad https://repo.anaconda.com/pkgs/main/noarch/iniconfig-1.1.1-pyhd3eb1b0_0.tar.bz2#e40edff2c5708f342cef43c7f280c507 https://repo.anaconda.com/pkgs/main/osx-64/joblib-1.4.2-py312hecd8cb5_0.conda#8ab03dfa447b4e0bfa0bd3d25930f3b6 https://repo.anaconda.com/pkgs/main/osx-64/kiwisolver-1.4.4-py312hcec6c5f_0.conda#2ba6561ddd1d05936fe74f5d118ce7dd -https://repo.anaconda.com/pkgs/main/osx-64/lcms2-2.12-hf1fd2bf_0.conda#697aba7a3308226df7a93ccfeae16ffa +https://repo.anaconda.com/pkgs/main/osx-64/lcms2-2.16-h4f63f0c_0.conda#2cd61d3449b21735ccca2e09ca2f93ef https://repo.anaconda.com/pkgs/main/osx-64/mkl-service-2.4.0-py312h6c40b1e_1.conda#b1ef860be9043b35c5e8d9388b858514 -https://repo.anaconda.com/pkgs/main/osx-64/ninja-1.10.2-hecd8cb5_5.conda#a0043b325fb08db82477ae433668e684 +https://repo.anaconda.com/pkgs/main/osx-64/ninja-1.12.1-hecd8cb5_0.conda#ee3b660616ef0fbcbd0096a67c11c94b https://repo.anaconda.com/pkgs/main/osx-64/openjpeg-2.5.2-hbf2204d_0.conda#8463f11309271a93d615450382761470 -https://repo.anaconda.com/pkgs/main/osx-64/packaging-24.1-py312hecd8cb5_0.conda#6130dafc4d26d55e93ceab460d2a72b5 -https://repo.anaconda.com/pkgs/main/osx-64/pluggy-1.0.0-py312hecd8cb5_1.conda#647fada22f1697691fdee90b52c99bcb -https://repo.anaconda.com/pkgs/main/osx-64/pyparsing-3.1.2-py312hecd8cb5_0.conda#645e2108165e45a3a385f0e11d1748a1 +https://repo.anaconda.com/pkgs/main/osx-64/packaging-24.2-py312hecd8cb5_0.conda#76512e47c9c37443444ef0624769f620 +https://repo.anaconda.com/pkgs/main/osx-64/pluggy-1.5.0-py312hecd8cb5_0.conda#ca381e438f1dbd7986ac0fa0da70c9d8 +https://repo.anaconda.com/pkgs/main/osx-64/pyparsing-3.2.0-py312hecd8cb5_0.conda#e4086daaaed13f68cc8d5b9da7db73cc https://repo.anaconda.com/pkgs/main/noarch/python-tzdata-2023.3-pyhd3eb1b0_0.conda#479c037de0186d114b9911158427624e https://repo.anaconda.com/pkgs/main/osx-64/pytz-2024.1-py312hecd8cb5_0.conda#2b28ec0e0d07f5c0c701f75200b1e8b6 https://repo.anaconda.com/pkgs/main/osx-64/setuptools-75.1.0-py312hecd8cb5_0.conda#3e59d1f40cba32a613a20b2ebdcf2c07 https://repo.anaconda.com/pkgs/main/noarch/six-1.16.0-pyhd3eb1b0_1.conda#34586824d411d36af2fa40e799c172d0 https://repo.anaconda.com/pkgs/main/noarch/toml-0.10.2-pyhd3eb1b0_0.conda#cda05f5f6d8509529d1a2743288d197a -https://repo.anaconda.com/pkgs/main/osx-64/tornado-6.4.1-py312h46256e1_0.conda#ff2efd781e1b1af38284aeda9d676d42 +https://repo.anaconda.com/pkgs/main/osx-64/tornado-6.4.2-py312h46256e1_0.conda#6b41d7d8a2bf93ae3fc512202b14a9ec https://repo.anaconda.com/pkgs/main/osx-64/unicodedata2-15.1.0-py312h6c40b1e_0.conda#65bd2cb787fc99662d9bb6e6520c5826 https://repo.anaconda.com/pkgs/main/osx-64/wheel-0.44.0-py312hecd8cb5_0.conda#bc98874d00f71c3f6f654d0316174d17 https://repo.anaconda.com/pkgs/main/osx-64/fonttools-4.51.0-py312h6c40b1e_0.conda#8f55fa86b73e8a7f4403503f9b7a9959 https://repo.anaconda.com/pkgs/main/osx-64/numpy-base-1.26.4-py312h6f81483_0.conda#87f73efbf26ab2e2ea7c32481a71bd47 -https://repo.anaconda.com/pkgs/main/osx-64/pillow-10.4.0-py312h46256e1_0.conda#486a21e17faf0611e454c0e7faf0bcbc +https://repo.anaconda.com/pkgs/main/osx-64/pillow-11.0.0-py312h47bf62f_1.conda#812dc507843961e9ff4b400945a954a7 https://repo.anaconda.com/pkgs/main/osx-64/pip-24.2-py312hecd8cb5_0.conda#35119ef238299ccf29b25889fd466139 https://repo.anaconda.com/pkgs/main/osx-64/pytest-7.4.4-py312hecd8cb5_0.conda#d4dda983900b045cd27ae836cad670de https://repo.anaconda.com/pkgs/main/osx-64/python-dateutil-2.9.0post0-py312hecd8cb5_2.conda#1047dde28f78127dd9f6121e882926dd -https://repo.anaconda.com/pkgs/main/osx-64/pytest-cov-4.1.0-py312hecd8cb5_1.conda#a33a24eb20359f464938e75b2f57e23a -https://repo.anaconda.com/pkgs/main/osx-64/pytest-xdist-3.5.0-py312hecd8cb5_0.conda#d1ecfb3691cceecb1f16bcfdf0b67bb5 -https://repo.anaconda.com/pkgs/main/osx-64/bottleneck-1.3.7-py312h32608ca_0.conda#f96a01eba5ea542cf9c7cc8d77447627 -https://repo.anaconda.com/pkgs/main/osx-64/contourpy-1.2.0-py312ha357a0b_0.conda#57d384ad07152375b40a6293f79e3f0c -https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-3.9.2-py312hecd8cb5_0.conda#4a0c6fbe79aefa058fddc09690772afa -https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-base-3.9.2-py312ha7ebc0d_0.conda#a5396c401f535238325577ab702ac32a +https://repo.anaconda.com/pkgs/main/osx-64/pytest-cov-6.0.0-py312hecd8cb5_0.conda#db697e319a4d1145363246a51eef0352 +https://repo.anaconda.com/pkgs/main/osx-64/pytest-xdist-3.6.1-py312hecd8cb5_0.conda#38df9520774ee82bf143218f1271f936 +https://repo.anaconda.com/pkgs/main/osx-64/bottleneck-1.4.2-py312ha2b695f_0.conda#7efb63b6a5b33829a3b2c7a3efcf53ce +https://repo.anaconda.com/pkgs/main/osx-64/contourpy-1.3.1-py312h1962661_0.conda#41499d3a415721b0514f0cccb8288cb1 +https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-3.9.2-py312hecd8cb5_1.conda#7a945072ef95437bc65ca5fb5666c45f +https://repo.anaconda.com/pkgs/main/osx-64/matplotlib-base-3.9.2-py312h919b35b_1.conda#263180911eb374703ebbbae0cf828d77 https://repo.anaconda.com/pkgs/main/osx-64/mkl_fft-1.3.8-py312h6c40b1e_0.conda#d59d01b940493f2b6a84aac922fd0c76 https://repo.anaconda.com/pkgs/main/osx-64/mkl_random-1.2.4-py312ha357a0b_0.conda#c1ea9c8eee79a5af3399f3c31be0e9c6 https://repo.anaconda.com/pkgs/main/osx-64/numpy-1.26.4-py312hac873b0_0.conda#3150bac1e382156f82a153229e1ebd06 https://repo.anaconda.com/pkgs/main/osx-64/numexpr-2.8.7-py312hac873b0_0.conda#6303ba071636ef57fddf69eb6f440ec1 https://repo.anaconda.com/pkgs/main/osx-64/scipy-1.11.4-py312h81688c2_0.conda#7d57b4c21a9261f97fa511e0940c5d93 -https://repo.anaconda.com/pkgs/main/osx-64/pandas-2.2.2-py312h77d3abe_0.conda#463868c40d8ff98bec263f1fd57a8d97 +https://repo.anaconda.com/pkgs/main/osx-64/pandas-2.2.3-py312h6d0c2b6_0.conda#84ce5b8ec4a986d13a5df17811f556a2 https://repo.anaconda.com/pkgs/main/osx-64/pyamg-4.2.3-py312h44cbcf4_0.conda#3bdc7be74087b3a5a83c520a74e1e8eb # pip cython @ https://files.pythonhosted.org/packages/58/50/fbb23239efe2183e4eaf76689270d6f5b3bbcf9be9ad1eb97cc34349e6fc/Cython-3.0.11-cp312-cp312-macosx_10_9_x86_64.whl#sha256=11996c40c32abf843ba652a6d53cb15944c88d91f91fc4e6f0028f5df8a8f8a1 -# pip meson @ https://files.pythonhosted.org/packages/76/73/3dc4edc855c9988ff05ea5590f5c7bda72b6e0d138b2ddc1fab92a1f242f/meson-1.6.0-py3-none-any.whl#sha256=234a45f9206c6ee33b473ec1baaef359d20c0b89a71871d58c65a6db6d98fe74 +# pip meson @ https://files.pythonhosted.org/packages/d2/f3/9d53c24a7113e08879b14117f83e7105251e6ecf7e03bb7c04926888db9c/meson-1.6.1-py3-none-any.whl#sha256=3f41f6b03df56bb76836cc33c94e1a404c3584d48b3259540794a60a21fad1f9 # pip threadpoolctl @ https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl#sha256=56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467 # pip pyproject-metadata @ https://files.pythonhosted.org/packages/e8/61/9dd3e68d2b6aa40a5fc678662919be3c3a7bf22cba5a6b4437619b77e156/pyproject_metadata-0.9.0-py3-none-any.whl#sha256=fc862aab066a2e87734333293b0af5845fe8ac6cb69c451a41551001e923be0b # pip meson-python @ https://files.pythonhosted.org/packages/7d/ec/40c0ddd29ef4daa6689a2b9c5ced47d5b58fa54ae149b19e9a97f4979c8c/meson_python-0.17.1-py3-none-any.whl#sha256=30a75c52578ef14aff8392677b09c39346e0a24d2b2c6204b8ed30583c11269c diff --git a/build_tools/azure/pylatest_free_threaded_environment.yml b/build_tools/azure/pylatest_free_threaded_environment.yml new file mode 100644 index 0000000000000..b947f31beb14a --- /dev/null +++ b/build_tools/azure/pylatest_free_threaded_environment.yml @@ -0,0 +1,16 @@ +# DO NOT EDIT: this file is generated from the specification found in the +# following script to centralize the configuration for CI builds: +# build_tools/update_environments_and_lock_files.py +channels: + - conda-forge +dependencies: + - python-freethreading + - numpy + - joblib + - threadpoolctl + - pytest + - pytest-xdist + - ninja + - meson-python + - ccache + - pip diff --git a/build_tools/azure/pylatest_free_threaded_linux-64_conda.lock b/build_tools/azure/pylatest_free_threaded_linux-64_conda.lock new file mode 100644 index 0000000000000..c499cfd66a6fe --- /dev/null +++ b/build_tools/azure/pylatest_free_threaded_linux-64_conda.lock @@ -0,0 +1,58 @@ +# Generated by conda-lock. +# platform: linux-64 +# input_hash: 8bf0c47c0d22842fa5a5531ad2ad62b4795b6b1cbf713816fa1101103a2e3dcc +@EXPLICIT +https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de +https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.13-5_cp313t.conda#ea4c21b96e8280414d9e243da0ec3201 +https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 +https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 +https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 +https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d +https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c +https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b +https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 +https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 +https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 +https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-h4bc722e_0.conda#aeb98fdeb2e8f25d43ef71fbacbeec80 +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 +https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 +https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b +https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe +https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc +https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_1.conda#62857b389e42b36b686331bec0922050 +https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 +https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 +https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_openblas.conda#ac52800af2e0c0e7dac770b435ce768a +https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a +https://conda.anaconda.org/conda-forge/linux-64/python-3.13.1-h9a34b6e_2_cp313t.conda#f0659443f1e7eae7f7606583fde56397 +https://conda.anaconda.org/conda-forge/linux-64/ccache-4.10.1-h065aff2_0.conda#d6b48c138e0c8170a6fe9c136e063540 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.1-py313hd8ed1ab_2.conda#0808acf1f700deba701a0e86833a5f4d +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_openblas.conda#ebcc5f37a435aa3c19640533c82f8d76 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-26_linux64_openblas.conda#3792604c43695d6a273bc5faaac47d48 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh145f28c_2.conda#76601b0ccfe1fe13a21a5f8813cb38de +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.1-py313h151ba9f_0.conda#7dff61c6e719aa5c1ac9a00595c8e9b2 +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-freethreading-3.13.1-h92d6c8b_2.conda#8618c8e664359e801165606d1c5cf10e +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml b/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml index 2d9ca394a6ac9..177d28555f712 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml +++ b/build_tools/azure/pylatest_pip_openblas_pandas_environment.yml @@ -4,7 +4,7 @@ channels: - defaults dependencies: - - python=3.11 + - python - ccache - pip - pip: diff --git a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock index d3a9418c90019..7d47d2f07bd03 100644 --- a/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_openblas_pandas_linux-64_conda.lock @@ -1,17 +1,20 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 893e5f90e655d6606d6b7e308c1099125012b25c3444b5a4240d44b184531e00 +# input_hash: 38d3951742eb4e3d26c6768f2c329b12d5418fed96f94c97da19b776b04ee767 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 -https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2024.9.24-h06a4308_0.conda#e4369d7b4b0707ee0765794d14710e2e +https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2024.11.26-h06a4308_0.conda#cebd61e6520159a1315d679321620f6c https://repo.anaconda.com/pkgs/main/linux-64/ld_impl_linux-64-2.40-h12ee557_0.conda#ee672b5f635340734f58d618b7bca024 +https://repo.anaconda.com/pkgs/main/linux-64/python_abi-3.13-0_cp313.conda#d4009c49dd2b54ffded7f1365b5f6505 https://repo.anaconda.com/pkgs/main/noarch/tzdata-2024b-h04d1e81_0.conda#9be694715c6a65f9631bb1b242125e9d https://repo.anaconda.com/pkgs/main/linux-64/libgomp-11.2.0-h1234567_1.conda#b372c0eea9b60732fdae4b817a63c8cd https://repo.anaconda.com/pkgs/main/linux-64/libstdcxx-ng-11.2.0-h1234567_1.conda#57623d10a70e09e1d048c2b2b6f4e2dd https://repo.anaconda.com/pkgs/main/linux-64/_openmp_mutex-5.1-1_gnu.conda#71d281e9c2192cb3fa425655a8defb85 https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-11.2.0-h1234567_1.conda#a87728dabf3151fb9cfa990bd2eb0464 https://repo.anaconda.com/pkgs/main/linux-64/bzip2-1.0.8-h5eee18b_6.conda#f21a3ff51c1b271977f53ce956a69297 +https://repo.anaconda.com/pkgs/main/linux-64/expat-2.6.4-h6a678d5_0.conda#3ec804f5b85a66e64b262cc2341dd004 https://repo.anaconda.com/pkgs/main/linux-64/libffi-3.4.4-h6a678d5_1.conda#70646cc713f0c43926cfdcfe9b695fe0 +https://repo.anaconda.com/pkgs/main/linux-64/libmpdec-4.0.0-h5eee18b_0.conda#feb10f42b1a7b523acbf85461be41a3e https://repo.anaconda.com/pkgs/main/linux-64/libuuid-1.41.5-h5eee18b_0.conda#4a6a2354414c9080327274aa514e5299 https://repo.anaconda.com/pkgs/main/linux-64/ncurses-6.4-h6a678d5_0.conda#5558eec6e2191741a92f832ea826251c https://repo.anaconda.com/pkgs/main/linux-64/openssl-3.0.15-h5eee18b_0.conda#019e501b69841c6d4aeaef3b8619a678 @@ -21,38 +24,38 @@ https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6f https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.14-h39e8969_0.conda#78dbc5e3c69143ebc037fc5d5b22e597 https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.45.3-h5eee18b_0.conda#acf93d6aceb74d6110e20b44cc45939e -https://repo.anaconda.com/pkgs/main/linux-64/python-3.11.10-he870216_0.conda#ebcea7b39a97d2023bf233d3c46df7cd -https://repo.anaconda.com/pkgs/main/linux-64/setuptools-75.1.0-py311h06a4308_0.conda#7cbefa0320ebd04c6cc060be9c39789a -https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.44.0-py311h06a4308_0.conda#1fb091aa98b4fc5ca036b2086dac1db5 -https://repo.anaconda.com/pkgs/main/linux-64/pip-24.2-py311h06a4308_0.conda#eff3ec695130b6912d64997edbc0db16 +https://repo.anaconda.com/pkgs/main/linux-64/python-3.13.1-hf623796_100_cp313.conda#9159d14122892f226415ae401c2d12bd +https://repo.anaconda.com/pkgs/main/linux-64/setuptools-75.1.0-py313h06a4308_0.conda#93277f023374c43e49b1081438de1798 +https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.44.0-py313h06a4308_0.conda#0d8e57ed81bb23b971817beeb3d49606 +https://repo.anaconda.com/pkgs/main/linux-64/pip-24.2-py313h06a4308_0.conda#59f806485e89cb8721847b5857f6df2b # pip alabaster @ https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl#sha256=fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b -# pip array-api-compat @ https://files.pythonhosted.org/packages/13/1d/2b2d33635de5dbf5e703114c11f1129394e68be16cc4dc5ccc2021a17f7b/array_api_compat-1.9.1-py3-none-any.whl#sha256=41a2703a662832d21619359ddddc5c0449876871f6c01e108c335f2a9432df94 +# pip array-api-compat @ https://files.pythonhosted.org/packages/72/76/633dffbd77631525921ab8d8867e33abd8bdb4ac64bfabd41e88ea910940/array_api_compat-1.10.0-py3-none-any.whl#sha256=d9066981fbc730174861b4394f38e27928827cbf7ed5becd8b1263b507c58864 # pip babel @ https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl#sha256=368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b -# pip certifi @ https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl#sha256=922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 -# pip charset-normalizer @ https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc -# pip coverage @ https://files.pythonhosted.org/packages/cc/57/cb08f0eda0389a9a8aaa4fc1f9fec7ac361c3e2d68efd5890d7042c18aa3/coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e +# pip certifi @ https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl#sha256=1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 +# pip charset-normalizer @ https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 +# pip coverage @ https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c # pip cycler @ https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl#sha256=85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 -# pip cython @ https://files.pythonhosted.org/packages/93/03/e330b241ad8aa12bb9d98b58fb76d4eb7dcbe747479aab5c29fce937b9e7/Cython-3.0.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=3999fb52d3328a6a5e8c63122b0a8bd110dfcdb98dda585a3def1426b991cba7 +# pip cython @ https://files.pythonhosted.org/packages/1c/ae/d520f3cd94a8926bc47275a968e51bbc669a28f27a058cdfc5c3081fbbf7/Cython-3.0.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=9c02361af9bfa10ff1ccf967fc75159e56b1c8093caf565739ed77a559c1f29f # pip docutils @ https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl#sha256=dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # pip execnet @ https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl#sha256=26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc -# pip fonttools @ https://files.pythonhosted.org/packages/96/13/748b7f7239893ff0796de11074b0ad8aa4c3da2d9f4d79a128b0b16147f3/fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07 +# pip fonttools @ https://files.pythonhosted.org/packages/d2/6c/a7066afc19db0705a12efd812e19c32cde2b9514eb714659522f2ebd60b6/fonttools-4.55.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=859c358ebf41db18fb72342d3080bce67c02b39e86b9fbcf1610cca14984841b # pip idna @ https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl#sha256=946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # pip imagesize @ https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl#sha256=0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip joblib @ https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl#sha256=06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6 -# pip kiwisolver @ https://files.pythonhosted.org/packages/a7/4b/2db7af3ed3af7c35f388d5f53c28e155cd402a55432d800c543dc6deb731/kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18 -# pip markupsafe @ https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 -# pip meson @ https://files.pythonhosted.org/packages/76/73/3dc4edc855c9988ff05ea5590f5c7bda72b6e0d138b2ddc1fab92a1f242f/meson-1.6.0-py3-none-any.whl#sha256=234a45f9206c6ee33b473ec1baaef359d20c0b89a71871d58c65a6db6d98fe74 +# pip kiwisolver @ https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246 +# pip markupsafe @ https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 +# pip meson @ https://files.pythonhosted.org/packages/d2/f3/9d53c24a7113e08879b14117f83e7105251e6ecf7e03bb7c04926888db9c/meson-1.6.1-py3-none-any.whl#sha256=3f41f6b03df56bb76836cc33c94e1a404c3584d48b3259540794a60a21fad1f9 # pip networkx @ https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl#sha256=df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f -# pip ninja @ https://files.pythonhosted.org/packages/6d/92/8d7aebd4430ab5ff65df2bfee6d5745f95c004284db2d8ca76dcbfd9de47/ninja-1.11.1.1-py2.py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl#sha256=84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b -# pip numpy @ https://files.pythonhosted.org/packages/7a/f0/80811e836484262b236c684a75dfc4ba0424bc670e765afaa911468d9f39/numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b -# pip packaging @ https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl#sha256=5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 -# pip pillow @ https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl#sha256=45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa +# pip ninja @ https://files.pythonhosted.org/packages/6b/35/a8e38d54768e67324e365e2a41162be298f51ec93e6bd4b18d237d7250d8/ninja-1.11.1.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0 +# pip numpy @ https://files.pythonhosted.org/packages/f1/5a/e572284c86a59dec0871a49cd4e5351e20b9c751399d5f1d79628c0542cb/numpy-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af +# pip packaging @ https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl#sha256=09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 +# pip pillow @ https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl#sha256=3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114 # pip pluggy @ https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl#sha256=44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 -# pip pygments @ https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl#sha256=b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a -# pip pyparsing @ https://files.pythonhosted.org/packages/be/ec/2eb3cd785efd67806c46c13a17339708ddc346cbb684eade7a6e6f79536a/pyparsing-3.2.0-py3-none-any.whl#sha256=93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84 +# pip pygments @ https://files.pythonhosted.org/packages/20/dc/fde3e7ac4d279a331676829af4afafd113b34272393d73f610e8f0329221/pygments-2.19.0-py3-none-any.whl#sha256=4755e6e64d22161d5b61432c0600c923c5927214e7c956e31c23923c89251a9b +# pip pyparsing @ https://files.pythonhosted.org/packages/1c/a7/c8a2d361bf89c0d9577c934ebb7421b25dc84bf3a8e3ac0a40aed9acc547/pyparsing-3.2.1-py3-none-any.whl#sha256=506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 # pip pytz @ https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl#sha256=31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725 -# pip six @ https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl#sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +# pip six @ https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl#sha256=4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 # pip snowballstemmer @ https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl#sha256=c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a # pip sphinxcontrib-applehelp @ https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl#sha256=4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5 # pip sphinxcontrib-devhelp @ https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl#sha256=aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2 @@ -63,25 +66,25 @@ https://repo.anaconda.com/pkgs/main/linux-64/pip-24.2-py311h06a4308_0.conda#eff3 # pip tabulate @ https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl#sha256=024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f # pip threadpoolctl @ https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl#sha256=56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467 # pip tzdata @ https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl#sha256=a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd -# pip urllib3 @ https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl#sha256=ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac -# pip array-api-strict @ https://files.pythonhosted.org/packages/2d/bc/e7f5e40d85744e59cb7692f8098f828e63610d3b850957bba5bbf569a90a/array_api_strict-2.1-py3-none-any.whl#sha256=322740ba4422e7ca758290d00edfe75491f1783ad1ab44325007c44162aa938a -# pip contourpy @ https://files.pythonhosted.org/packages/03/33/003065374f38894cdf1040cef474ad0546368eea7e3a51d48b8a423961f8/contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d -# pip imageio @ https://files.pythonhosted.org/packages/4e/e7/26045404a30c8a200e960fb54fbaf4b73d12e58cd28e03b306b084253f4f/imageio-2.36.0-py3-none-any.whl#sha256=471f1eda55618ee44a3c9960911c35e647d9284c68f077e868df633398f137f0 -# pip jinja2 @ https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl#sha256=bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d +# pip urllib3 @ https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl#sha256=1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df +# pip array-api-strict @ https://files.pythonhosted.org/packages/9a/c2/a202399e3aa2e62aa15669fc95fdd7a5d63240cbf8695962c747f915a083/array_api_strict-2.2-py3-none-any.whl#sha256=577cfce66bf69701cefea85bc14b9e49e418df767b6b178bd93d22f1c1962d59 +# pip contourpy @ https://files.pythonhosted.org/packages/9a/e2/30ca086c692691129849198659bf0556d72a757fe2769eb9620a27169296/contourpy-1.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c +# pip imageio @ https://files.pythonhosted.org/packages/5c/f9/f78e7f5ac8077c481bf6b43b8bc736605363034b3d5eb3ce8eb79f53f5f1/imageio-2.36.1-py3-none-any.whl#sha256=20abd2cae58e55ca1af8a8dcf43293336a59adf0391f1917bf8518633cfc2cdf +# pip jinja2 @ https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl#sha256=aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb # pip lazy-loader @ https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl#sha256=342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc # pip pyproject-metadata @ https://files.pythonhosted.org/packages/e8/61/9dd3e68d2b6aa40a5fc678662919be3c3a7bf22cba5a6b4437619b77e156/pyproject_metadata-0.9.0-py3-none-any.whl#sha256=fc862aab066a2e87734333293b0af5845fe8ac6cb69c451a41551001e923be0b -# pip pytest @ https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl#sha256=a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2 +# pip pytest @ https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl#sha256=50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6 # pip python-dateutil @ https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl#sha256=a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 # pip requests @ https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl#sha256=70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 -# pip scipy @ https://files.pythonhosted.org/packages/93/6b/701776d4bd6bdd9b629c387b5140f006185bd8ddea16788a44434376b98f/scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2 -# pip tifffile @ https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl#sha256=c54dc85bc1065d972cb8a6ffb3181389d597876aa80177933459733e4ed243dd +# pip scipy @ https://files.pythonhosted.org/packages/82/4d/ecef655956ce332edbc411ab64ab843d767dd86e646898ac721dbcc7910e/scipy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=36be480e512d38db67f377add5b759fb117edd987f4791cdf58e59b26962bee4 +# pip tifffile @ https://files.pythonhosted.org/packages/d8/1e/76cbc758f6865a9da18001ac70d1a4154603b71e233f704401fc7d62493e/tifffile-2024.12.12-py3-none-any.whl#sha256=6ff0f196a46a75c8c0661c70995e06ea4d08a81fe343193e69f1673f4807d508 # pip lightgbm @ https://files.pythonhosted.org/packages/4e/19/1b928cad70a4e1a3e2c37d5417ca2182510f2451eaadb6c91cd9ec692cae/lightgbm-4.5.0-py3-none-manylinux_2_28_x86_64.whl#sha256=960a0e7c077de0ca3053f1325d3edfc92ea815acf5176adcacdea0f635aeef9b -# pip matplotlib @ https://files.pythonhosted.org/packages/01/75/6c7ce560e95714a10fcbb3367d1304975a1a3e620f72af28921b796403f3/matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447 +# pip matplotlib @ https://files.pythonhosted.org/packages/ea/3a/bab9deb4fb199c05e9100f94d7f1c702f78d3241e6a71b784d2b88d7bebd/matplotlib-3.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=ad2e15300530c1a94c63cfa546e3b7864bd18ea2901317bae8bbf06a5ade6dcf # pip meson-python @ https://files.pythonhosted.org/packages/7d/ec/40c0ddd29ef4daa6689a2b9c5ced47d5b58fa54ae149b19e9a97f4979c8c/meson_python-0.17.1-py3-none-any.whl#sha256=30a75c52578ef14aff8392677b09c39346e0a24d2b2c6204b8ed30583c11269c -# pip pandas @ https://files.pythonhosted.org/packages/cd/5f/4dba1d39bb9c38d574a9a22548c540177f78ea47b32f99c0ff2ec499fac5/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc -# pip pyamg @ https://files.pythonhosted.org/packages/d3/e8/6898b3b791f369605012e896ed903b6626f3bd1208c6a647d7219c070209/pyamg-5.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=679a5904eac3a4880288c8c0e6a29f110a2627ea15a443a4e9d5997c7dc5fab6 +# pip pandas @ https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24 +# pip pyamg @ https://files.pythonhosted.org/packages/cd/a7/0df731cbfb09e73979a1a032fc7bc5be0eba617d798b998a0f887afe8ade/pyamg-5.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=6999b351ab969c79faacb81faa74c0fa9682feeff3954979212872a3ee40c298 # pip pytest-cov @ https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl#sha256=eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35 # pip pytest-xdist @ https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl#sha256=9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7 -# pip scikit-image @ https://files.pythonhosted.org/packages/ad/96/138484302b8ec9a69cdf65e8d4ab47a640a3b1a8ea3c437e1da3e1a5a6b8/scikit_image-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=fa27b3a0dbad807b966b8db2d78da734cb812ca4787f7fbb143764800ce2fa9c +# pip scikit-image @ https://files.pythonhosted.org/packages/8c/d2/84d658db2abecac5f7225213a69d211d95157e8fa155b4e017903549a922/scikit_image-0.25.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0fe2f05cda852a5f90872054dd3709e9c4e670fc7332aef169867944e1b37431 # pip sphinx @ https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl#sha256=09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 # pip numpydoc @ https://files.pythonhosted.org/packages/6c/45/56d99ba9366476cd8548527667f01869279cedb9e66b28eb4dfb27701679/numpydoc-1.8.0-py3-none-any.whl#sha256=72024c7fd5e17375dec3608a27c03303e8ad00c81292667955c6fea7a3ccf541 diff --git a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock index 2f704dfeadddd..8087b446d3dbe 100644 --- a/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock +++ b/build_tools/azure/pylatest_pip_scipy_dev_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: 8a4a203136d97ff3b2c8657fce2dd2228215bfbf9c1cfbe271e401f934bdf1a7 @EXPLICIT https://repo.anaconda.com/pkgs/main/linux-64/_libgcc_mutex-0.1-main.conda#c3473ff8bdb3d124ed5ff11ec380d6f9 -https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2024.9.24-h06a4308_0.conda#e4369d7b4b0707ee0765794d14710e2e +https://repo.anaconda.com/pkgs/main/linux-64/ca-certificates-2024.11.26-h06a4308_0.conda#cebd61e6520159a1315d679321620f6c https://repo.anaconda.com/pkgs/main/linux-64/ld_impl_linux-64-2.40-h12ee557_0.conda#ee672b5f635340734f58d618b7bca024 https://repo.anaconda.com/pkgs/main/linux-64/python_abi-3.13-0_cp313.conda#d4009c49dd2b54ffded7f1365b5f6505 https://repo.anaconda.com/pkgs/main/noarch/tzdata-2024b-h04d1e81_0.conda#9be694715c6a65f9631bb1b242125e9d @@ -12,7 +12,7 @@ https://repo.anaconda.com/pkgs/main/linux-64/libstdcxx-ng-11.2.0-h1234567_1.cond https://repo.anaconda.com/pkgs/main/linux-64/_openmp_mutex-5.1-1_gnu.conda#71d281e9c2192cb3fa425655a8defb85 https://repo.anaconda.com/pkgs/main/linux-64/libgcc-ng-11.2.0-h1234567_1.conda#a87728dabf3151fb9cfa990bd2eb0464 https://repo.anaconda.com/pkgs/main/linux-64/bzip2-1.0.8-h5eee18b_6.conda#f21a3ff51c1b271977f53ce956a69297 -https://repo.anaconda.com/pkgs/main/linux-64/expat-2.6.3-h6a678d5_0.conda#5e184279ccb8b85331093305cb548f5c +https://repo.anaconda.com/pkgs/main/linux-64/expat-2.6.4-h6a678d5_0.conda#3ec804f5b85a66e64b262cc2341dd004 https://repo.anaconda.com/pkgs/main/linux-64/libffi-3.4.4-h6a678d5_1.conda#70646cc713f0c43926cfdcfe9b695fe0 https://repo.anaconda.com/pkgs/main/linux-64/libmpdec-4.0.0-h5eee18b_0.conda#feb10f42b1a7b523acbf85461be41a3e https://repo.anaconda.com/pkgs/main/linux-64/libuuid-1.41.5-h5eee18b_0.conda#4a6a2354414c9080327274aa514e5299 @@ -24,28 +24,28 @@ https://repo.anaconda.com/pkgs/main/linux-64/ccache-3.7.9-hfe4627d_0.conda#bef6f https://repo.anaconda.com/pkgs/main/linux-64/readline-8.2-h5eee18b_0.conda#be42180685cce6e6b0329201d9f48efb https://repo.anaconda.com/pkgs/main/linux-64/tk-8.6.14-h39e8969_0.conda#78dbc5e3c69143ebc037fc5d5b22e597 https://repo.anaconda.com/pkgs/main/linux-64/sqlite-3.45.3-h5eee18b_0.conda#acf93d6aceb74d6110e20b44cc45939e -https://repo.anaconda.com/pkgs/main/linux-64/python-3.13.0-hf623796_100_cp313.conda#39dace58d617c330efddfd8c27b6da04 +https://repo.anaconda.com/pkgs/main/linux-64/python-3.13.1-hf623796_100_cp313.conda#9159d14122892f226415ae401c2d12bd https://repo.anaconda.com/pkgs/main/linux-64/setuptools-75.1.0-py313h06a4308_0.conda#93277f023374c43e49b1081438de1798 https://repo.anaconda.com/pkgs/main/linux-64/wheel-0.44.0-py313h06a4308_0.conda#0d8e57ed81bb23b971817beeb3d49606 https://repo.anaconda.com/pkgs/main/linux-64/pip-24.2-py313h06a4308_0.conda#59f806485e89cb8721847b5857f6df2b # pip alabaster @ https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl#sha256=fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b # pip babel @ https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl#sha256=368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b -# pip certifi @ https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl#sha256=922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 -# pip charset-normalizer @ https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc -# pip coverage @ https://files.pythonhosted.org/packages/7f/f8/4436a643631a2fbab4b44d54f515028f6099bfb1cd95b13cfbf701e7f2f2/coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f +# pip certifi @ https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl#sha256=1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 +# pip charset-normalizer @ https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 +# pip coverage @ https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c # pip docutils @ https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl#sha256=dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 # pip execnet @ https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl#sha256=26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc # pip idna @ https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl#sha256=946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 # pip imagesize @ https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl#sha256=0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b # pip iniconfig @ https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # pip markupsafe @ https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 -# pip meson @ https://files.pythonhosted.org/packages/76/73/3dc4edc855c9988ff05ea5590f5c7bda72b6e0d138b2ddc1fab92a1f242f/meson-1.6.0-py3-none-any.whl#sha256=234a45f9206c6ee33b473ec1baaef359d20c0b89a71871d58c65a6db6d98fe74 -# pip ninja @ https://files.pythonhosted.org/packages/6d/92/8d7aebd4430ab5ff65df2bfee6d5745f95c004284db2d8ca76dcbfd9de47/ninja-1.11.1.1-py2.py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl#sha256=84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b -# pip packaging @ https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl#sha256=5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 +# pip meson @ https://files.pythonhosted.org/packages/d2/f3/9d53c24a7113e08879b14117f83e7105251e6ecf7e03bb7c04926888db9c/meson-1.6.1-py3-none-any.whl#sha256=3f41f6b03df56bb76836cc33c94e1a404c3584d48b3259540794a60a21fad1f9 +# pip ninja @ https://files.pythonhosted.org/packages/6b/35/a8e38d54768e67324e365e2a41162be298f51ec93e6bd4b18d237d7250d8/ninja-1.11.1.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0 +# pip packaging @ https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl#sha256=09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 # pip platformdirs @ https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl#sha256=73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb # pip pluggy @ https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl#sha256=44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 -# pip pygments @ https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl#sha256=b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a -# pip six @ https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl#sha256=8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +# pip pygments @ https://files.pythonhosted.org/packages/20/dc/fde3e7ac4d279a331676829af4afafd113b34272393d73f610e8f0329221/pygments-2.19.0-py3-none-any.whl#sha256=4755e6e64d22161d5b61432c0600c923c5927214e7c956e31c23923c89251a9b +# pip six @ https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl#sha256=4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 # pip snowballstemmer @ https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl#sha256=c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a # pip sphinxcontrib-applehelp @ https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl#sha256=4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5 # pip sphinxcontrib-devhelp @ https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl#sha256=aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2 @@ -55,10 +55,10 @@ https://repo.anaconda.com/pkgs/main/linux-64/pip-24.2-py313h06a4308_0.conda#59f8 # pip sphinxcontrib-serializinghtml @ https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl#sha256=6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331 # pip tabulate @ https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl#sha256=024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f # pip threadpoolctl @ https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl#sha256=56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467 -# pip urllib3 @ https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl#sha256=ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac -# pip jinja2 @ https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl#sha256=bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d +# pip urllib3 @ https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl#sha256=1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df +# pip jinja2 @ https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl#sha256=aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb # pip pyproject-metadata @ https://files.pythonhosted.org/packages/e8/61/9dd3e68d2b6aa40a5fc678662919be3c3a7bf22cba5a6b4437619b77e156/pyproject_metadata-0.9.0-py3-none-any.whl#sha256=fc862aab066a2e87734333293b0af5845fe8ac6cb69c451a41551001e923be0b -# pip pytest @ https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl#sha256=a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2 +# pip pytest @ https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl#sha256=50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6 # pip python-dateutil @ https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl#sha256=a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 # pip requests @ https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl#sha256=70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 # pip meson-python @ https://files.pythonhosted.org/packages/7d/ec/40c0ddd29ef4daa6689a2b9c5ced47d5b58fa54ae149b19e9a97f4979c8c/meson_python-0.17.1-py3-none-any.whl#sha256=30a75c52578ef14aff8392677b09c39346e0a24d2b2c6204b8ed30583c11269c diff --git a/build_tools/azure/pymin_conda_forge_mkl_win-64_conda.lock b/build_tools/azure/pymin_conda_forge_mkl_win-64_conda.lock index 147126a809ec6..aa94ff9d6cbaf 100644 --- a/build_tools/azure/pymin_conda_forge_mkl_win-64_conda.lock +++ b/build_tools/azure/pymin_conda_forge_mkl_win-64_conda.lock @@ -2,23 +2,23 @@ # platform: win-64 # input_hash: ea607aaeb7b1d1f8a1f821a9f505b3601083a218ec4763e2d72d3d3d800e718c @EXPLICIT -https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.8.30-h56e8100_0.conda#4c4fd67c18619be5aa65dc5b6c72e490 +https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.12.14-h56e8100_0.conda#cb2eaeb88549ddb27af533eccf9a45c1 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda#2d89243bfb53652c182a7c73182cce4f -https://conda.anaconda.org/conda-forge/win-64/mkl-include-2024.2.2-h66d3029_14.conda#19e51a50ba5fc6f7421f12fba6d0b775 +https://conda.anaconda.org/conda-forge/win-64/mkl-include-2024.2.2-h66d3029_15.conda#e2f516189b44b6e042199d13e7015361 https://conda.anaconda.org/conda-forge/win-64/python_abi-3.9-5_cp39.conda#86ba1bbcf9b259d1592201f3c345c810 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda#6797b005cd0f439c4c5c9ac565783700 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_8.conda#03cccbba200ee0523bde1f3dad60b1f3 -https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.40.33810-hcc2c482_22.conda#ce23a4b980ee0556a118ed96550ff3f3 +https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.42.34433-he29a5d6_23.conda#32b37d0cfa80da34548501cdc913a832 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab https://conda.anaconda.org/conda-forge/win-64/libgomp-14.2.0-h1383e82_1.conda#9e2d4d1214df6f21cba12f6eff4972f9 -https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h8a93ad2_22.conda#a47cd756e88d8a80dfae678842d4acc9 -https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.40.33810-h3bf8584_22.conda#8c6b061d44cafdfc8e8c6eb5f100caf0 +https://conda.anaconda.org/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda#7c10ec3158d1eb4ddff7007c9101adb0 +https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.42.34433-hdffcdeb_23.conda#5c176975ca2b8366abad3c97b3cd1e83 https://conda.anaconda.org/conda-forge/win-64/_openmp_mutex-4.5-2_gnu.conda#37e16618af5c4851a3f3d66dd0e11141 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda#276e7ffe9ffe39688abc665ef0f45596 https://conda.anaconda.org/conda-forge/win-64/double-conversion-3.3.0-h63175ca_0.conda#1a8bc18b24014167b2184c5afbe6037e @@ -26,97 +26,95 @@ https://conda.anaconda.org/conda-forge/win-64/graphite2-1.3.13-h63175ca_1003.con https://conda.anaconda.org/conda-forge/win-64/icu-75.1-he0c23c2_0.conda#8579b6bb8d18be7c0b27fb08adeeeb40 https://conda.anaconda.org/conda-forge/win-64/lerc-4.0.0-h63175ca_0.tar.bz2#1900cb3cab5055833cfddb0ba233b074 https://conda.anaconda.org/conda-forge/win-64/libbrotlicommon-1.1.0-h2466b09_2.conda#f7dc9a8f21d74eab46456df301da2972 -https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.22-h2466b09_0.conda#a3439ce12d4e3cd887270d9436f9a4c8 -https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.3-he0c23c2_0.conda#21415fbf4d0de6767a621160b43e5dea +https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.23-h9062f6e_0.conda#a9624935147a25b06013099d3038e467 +https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.4-he0c23c2_0.conda#eb383771c680aa792feb529eaf9df82f https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-hcfcfb64_2.conda#e1eb10b1cca179f2baa3601e4efc8712 https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.0.0-hcfcfb64_1.conda#3f1b948619c45b1ca714d60c7389092c -https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.47.0-h2466b09_1.conda#5b1f36012cc3d09c4eb9f24ad0e2c379 -https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.4.0-hcfcfb64_0.conda#abd61d0ab127ec5cd68f62c2969e6f34 +https://conda.anaconda.org/conda-forge/win-64/liblzma-5.6.3-h2466b09_1.conda#015b9c0bd1eef60729ab577a38aaf0b5 +https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.47.2-h67fdade_0.conda#ff00095330e0d35a16bd3bdbd1a2d3e7 +https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.5.0-h3b0e114_0.conda#33f7313967072c6e6d8f865f5493c7ae https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda#41fbfac52c601159df6c01f875de31b9 https://conda.anaconda.org/conda-forge/win-64/ninja-1.12.1-hc790b64_0.conda#a557dde55343e03c68cd7e29e7f87279 -https://conda.anaconda.org/conda-forge/win-64/openssl-3.3.2-h2466b09_0.conda#1dc86753693df5e3326bb8a85b74c589 -https://conda.anaconda.org/conda-forge/win-64/pixman-0.43.4-h63175ca_0.conda#b98135614135d5f458b75ab9ebb9558c +https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.0-ha4e3fda_1.conda#fb45308ba8bfe1abf1f4a27bad24a743 +https://conda.anaconda.org/conda-forge/win-64/pixman-0.44.2-had0cd8c_0.conda#c720ac9a3bd825bf8b4dc7523ea49be4 https://conda.anaconda.org/conda-forge/win-64/qhull-2020.2-hc790b64_5.conda#854fbdff64b572b5c0b470f334d34c11 -https://conda.anaconda.org/conda-forge/win-64/tbb-2021.7.0-h91493d7_0.tar.bz2#f57be598137919e4f7e7d159960d66a1 https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda#fc048363eb8f03cd1737600a5d08aafe -https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2#515d77642eaa3639413c6b1bc3f94219 https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda#31aec030344e962fbd7dbbbbd68e60a9 https://conda.anaconda.org/conda-forge/win-64/libbrotlidec-1.1.0-h2466b09_2.conda#9bae75ce723fa34e98e239d21d752a7e https://conda.anaconda.org/conda-forge/win-64/libbrotlienc-1.1.0-h2466b09_2.conda#85741a24d97954a991e55e34bc55990b https://conda.anaconda.org/conda-forge/win-64/libgcc-14.2.0-h1383e82_1.conda#75fdd34824997a0f9950a703b15d8ac5 https://conda.anaconda.org/conda-forge/win-64/libintl-0.22.5-h5728263_3.conda#2cf0cf76cc15d360dfa2f17fd6cf9772 https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.44-h3ca93ac_0.conda#639ac6b55a40aa5de7b8c1b4d78f9e81 -https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.4-h442d1da_2.conda#46c233e5c137a2de2d1d95ca35ad8d6a -https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h66d3029_14.conda#f011e7cc21918dc9d1efe0209e27fa16 +https://conda.anaconda.org/conda-forge/win-64/libxml2-2.13.5-he286e8c_1.conda#77eaa84f90fc90643c5a0be0aa9bdd1b https://conda.anaconda.org/conda-forge/win-64/pcre2-10.44-h3d7b363_2.conda#a3a3baddcfb8c80db84bec3cb7746fb8 -https://conda.anaconda.org/conda-forge/win-64/python-3.9.20-hfaddaf0_1_cpython.conda#445389d1d311435a90def248c814ddd6 -https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.1-h2466b09_2.conda#be60c4e8efa55fddc17b4131aa47acbd +https://conda.anaconda.org/conda-forge/win-64/python-3.9.21-h37870fc_1_cpython.conda#436316266ec1b6c23065b398e43d3a44 https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.6-h0ea2cb4_0.conda#9a17230f95733c04dc40a2b1e5491d74 https://conda.anaconda.org/conda-forge/win-64/brotli-bin-1.1.0-h2466b09_2.conda#d22534a9be5771fc58eb7564947f669d -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/win-64/cython-3.0.11-py39h4279646_3.conda#c89d5275e2d6545ba01d6e1ce064496e -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 https://conda.anaconda.org/conda-forge/win-64/freetype-2.12.1-hdaf720e_2.conda#3761b23693f768dc75a8fd0a73ca053f -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.4.7-py39h2b77a98_0.conda#c116c25e2e36f770f065559ad2a1da73 -https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-25_win64_mkl.conda#499208e81242efb6e5abc7366c91c816 -https://conda.anaconda.org/conda-forge/win-64/libclang13-19.1.3-default_ha5278ca_0.conda#fe6aa50eeb307558f8974f115305388f -https://conda.anaconda.org/conda-forge/win-64/libgfortran5-14.2.0-hf020157_1.conda#294a5033b744648a2ba816b34ffd810a +https://conda.anaconda.org/conda-forge/win-64/libclang13-19.1.6-default_ha5278ca_0.conda#1cfe412982fe3a83577aa80d1e39cfb3 https://conda.anaconda.org/conda-forge/win-64/libglib-2.82.2-h7025463_0.conda#3e379c1b908a7101ecbc503def24613f -https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.0-hfc51747_1.conda#eac317ed1cc6b9c0af0c27297e364665 +https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.11.2-default_ha69328c_1001.conda#b87a0ac5ab6495d8225db5dc72dd21cd +https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.0-h797046b_3.conda#defed79ff7a9164ad40320e3f116a138 https://conda.anaconda.org/conda-forge/win-64/libxslt-1.1.39-h3df6e99_0.conda#279ee338c9b34871d578cb3c7aa68f70 -https://conda.anaconda.org/conda-forge/win-64/mkl-devel-2024.2.2-h57928b3_14.conda#ecc2c244eff5cb6289b6db5e0401c0aa https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 https://conda.anaconda.org/conda-forge/win-64/pthread-stubs-0.4-h0e40799_1002.conda#3c8f2573569bb816483e5cf57efbbe29 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/win-64/tornado-6.4.1-py39ha55e580_1.conda#4a93d22ed5b2cede80fbee7f7f775a9d +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/win-64/tornado-6.4.2-py39ha55e580_0.conda#96e4fc4c6aaaa23d99bf1ed008e7b1e1 https://conda.anaconda.org/conda-forge/win-64/unicodedata2-15.1.0-py39ha55e580_1.conda#7b7e5732092b9a635440ec939e45651d -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 -https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.11-h0e40799_1.conda#ca66d6f8fe86dd53664e8de5087ef6b1 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 +https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.12-h0e40799_0.conda#2ffbfae4548098297c033228256eb96e https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.5-h0e40799_0.conda#8393c0f7e7870b4eb45553326f81f0ff -https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 https://conda.anaconda.org/conda-forge/win-64/brotli-1.1.0-h2466b09_2.conda#378f1c9421775dfe644731cb121c8979 -https://conda.anaconda.org/conda-forge/win-64/coverage-7.6.4-py39hf73967f_0.conda#7f2ad67ee529ce63fbb4e69949ee56a0 +https://conda.anaconda.org/conda-forge/win-64/coverage-7.6.10-py39hf73967f_0.conda#7b587c8f98fdfb579147df8c23386531 https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.15.0-h765892d_1.conda#9bb0026a2131b09404c59c4290c697cd -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_1.conda#15798fa69312d433af690c8c42b3fb36 +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 https://conda.anaconda.org/conda-forge/win-64/lcms2-2.16-h67d730c_0.conda#d3592435917b62a8becff3a60db674f6 -https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-25_win64_mkl.conda#3ed189ba03a9888a8013aaee0d67c49d -https://conda.anaconda.org/conda-forge/win-64/libgfortran-14.2.0-h719f0c7_1.conda#bd709ec903eeb030208c78e4c35691d6 -https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-25_win64_mkl.conda#f716ef84564c574e8e74ae725f5d5f93 https://conda.anaconda.org/conda-forge/win-64/libxcb-1.17.0-h0e4246c_0.conda#a69bbf778a462da324489976c84cfc8c -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.2-h3d672ee_0.conda#7e7099ad94ac3b599808950cec30ad4e -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/win-64/cairo-1.18.0-h32b962e_3.conda#8f43723a4925c51e55c2d81725a97db4 -https://conda.anaconda.org/conda-forge/win-64/fonttools-4.54.1-py39hf73967f_1.conda#c0fcffbde1793dfd8067cf29fb22bc5f -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_0.conda#67f4772681cf86652f3e2261794cf045 -https://conda.anaconda.org/conda-forge/win-64/liblapacke-3.9.0-25_win64_mkl.conda#d59fc46f1e1c2f3cf38a08a0a76ffee5 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/win-64/numpy-2.0.2-py39h60232e0_0.conda#13c59f25f5d4ad7d1c677667555f6547 -https://conda.anaconda.org/conda-forge/win-64/pillow-11.0.0-py39h5ee314c_0.conda#0c57206c5215a7e56414ce0332805226 -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda#cb8a11b6d209e3d85e5094bdbd9ebd9c -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 -https://conda.anaconda.org/conda-forge/win-64/blas-devel-3.9.0-25_win64_mkl.conda#b3c40599e865dac087085b596fbbf4ad +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.3-h4d64b90_0.conda#fc050366dd0b8313eb797ed1ffef3a29 +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e +https://conda.anaconda.org/conda-forge/win-64/tbb-2021.13.0-h62715c5_1.conda#9190dd0a23d925f7602f9628b3aed511 +https://conda.anaconda.org/conda-forge/win-64/cairo-1.18.2-h5782bbf_1.conda#63ff2bf400dde4fad0bed56debee5c16 +https://conda.anaconda.org/conda-forge/win-64/fonttools-4.55.3-py39hf73967f_1.conda#8401c0a5f5a3faf092ac6ebb00de608a +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_1.conda#59561d9b70f9df3b884c29910eba6593 +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h66d3029_15.conda#302dff2807f2927b3e9e0d19d60121de +https://conda.anaconda.org/conda-forge/win-64/pillow-11.1.0-py39h73ef694_0.conda#281e124453ea6dc02e9638a4d6c0a8b6 +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda#79963c319d1be62c8fd3e34555816e01 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd +https://conda.anaconda.org/conda-forge/win-64/harfbuzz-10.1.0-ha6ce084_0.conda#ad1da267c13505dbcc7fb9f0d21f24ae +https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-26_win64_mkl.conda#ecfe732dbad1be001826fdb7e5e891b5 +https://conda.anaconda.org/conda-forge/win-64/mkl-devel-2024.2.2-h57928b3_15.conda#a85f53093da069c7c657f090e388f3ef +https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-26_win64_mkl.conda#652f3adcb9d329050a325416edb14246 +https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-26_win64_mkl.conda#0a717f5fda7279b77bcce671b324408a +https://conda.anaconda.org/conda-forge/win-64/qt6-main-6.8.1-h1259614_2.conda#070e8c90ab39a63d9ee0d2155bc668b4 +https://conda.anaconda.org/conda-forge/win-64/liblapacke-3.9.0-26_win64_mkl.conda#759830e09248cc0fd7fe2cbb79c83b03 +https://conda.anaconda.org/conda-forge/win-64/numpy-2.0.2-py39h60232e0_1.conda#d8801e13476c0ae89e410307fbc5a612 +https://conda.anaconda.org/conda-forge/win-64/pyside6-6.8.1-py39h0285922_0.conda#a8d806c618d9ae1836b56e0771ee6abe +https://conda.anaconda.org/conda-forge/win-64/blas-devel-3.9.0-26_win64_mkl.conda#4cbc362151f0933b3bd77ef36cd7d646 https://conda.anaconda.org/conda-forge/win-64/contourpy-1.3.0-py39h2b77a98_2.conda#37f8619ee96710220ead6bb386b9b24b -https://conda.anaconda.org/conda-forge/win-64/harfbuzz-9.0.0-h2bedf89_1.conda#254f119aaed2c0be271c1114ae18d09b https://conda.anaconda.org/conda-forge/win-64/scipy-1.13.1-py39h1a10956_0.conda#9f8e571406af04d2f5fdcbecec704505 -https://conda.anaconda.org/conda-forge/win-64/blas-2.125-mkl.conda#186eeb4e8ba0a5944775e04f241fc02a -https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.9.2-py39h5376392_1.conda#6538e11505db6f3e1ee15a8207839f34 -https://conda.anaconda.org/conda-forge/win-64/qt6-main-6.8.0-hfb098fa_0.conda#053046ca73b71bbcc81c6dc114264d24 -https://conda.anaconda.org/conda-forge/win-64/pyside6-6.8.0.2-py39h0285922_0.conda#07b75557409b6bdbaf723b1bc020afb5 -https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.9.2-py39hcbf5309_1.conda#d14badfe4135e9bb2bec118bd3cff611 +https://conda.anaconda.org/conda-forge/win-64/blas-2.126-mkl.conda#807534bc7c3dac2c87524a5579905c93 +https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.9.4-py39h5376392_0.conda#5424884b703d67e412584ed241f0a9b1 +https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.9.4-py39hcbf5309_0.conda#61326dfe02e88b609166814c47316063 diff --git a/build_tools/azure/pymin_conda_forge_openblas_min_dependencies_linux-64_conda.lock b/build_tools/azure/pymin_conda_forge_openblas_min_dependencies_linux-64_conda.lock index 16de8b3604fe8..0e063b91fed4d 100644 --- a/build_tools/azure/pymin_conda_forge_openblas_min_dependencies_linux-64_conda.lock +++ b/build_tools/azure/pymin_conda_forge_openblas_min_dependencies_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: da804213459d72ef5fa344326a71a64386dfb5085c8e0b582527e8337cecca32 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb @@ -12,29 +12,30 @@ https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-5_cp39.conda#4036 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.3-h024ca30_0.conda#d36687dc90337917a84a96a45111ad59 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.6-h024ca30_0.conda#96e42ccbd3c067c1713ff5f2d2169247 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-hb9d3cd8_1004.conda#24831329718daa6cbe35fcd071b778d4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-he02047a_3.conda#fcd2016d1d299f654f81021e27496818 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2#a8832b479f93521a9e7b5b743803be51 @@ -42,6 +43,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-he02047a_3.conda#efab66b82ec976930b96d62a976de8e7 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 +https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.51-hbd13f7d_1.conda#168cc19c031482f83b23c4eebbb94e26 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 @@ -49,132 +51,130 @@ https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.5-h4ab18f5_0.conda#60 https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2#15345e56d527b330e1cacbdf58676e8f https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda#c7f302fd11eeb0987a6a5e1f3aed6a21 -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe https://conda.anaconda.org/conda-forge/linux-64/nspr-4.36-h5888daf_0.conda#de9cd5bca9e4918527b9b72b6e2e1409 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-he8f35ee_3.conda#4fab9799da9571266d05ca5503330655 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.69-h0f662aa_0.conda#25cb5999faa414e5ccb2c1388f62d3d5 -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.71-h39aace5_0.conda#dd19e4e3043f6948bd7454b946ee0983 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 +https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-lib-1.11.0-hb9d3cd8_2.conda#e55712ff40a054134d51b89afca57dbc https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-he02047a_3.conda#9aba7960731e6b4547b3a52f812ed801 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.106-hdf54f9c_0.conda#efe735c7dc47dddbb14b3433d11c6feb +https://conda.anaconda.org/conda-forge/linux-64/nss-3.107-hdf54f9c_0.conda#294b7009fe9010b35c25bb683f663bc3 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-he8f35ee_3.conda#1091193789bb830127ed067a9e01ac57 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.25-pthreads_h413a1c8_0.conda#d172b34a443b95f86089e8229ddc9a17 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.20-h13acc7a_1_cpython.conda#951cff166a5f170e27908811917165f8 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-256.9-h0b6a36f_2.conda#135bbeb376345b6847c065115be4221a +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda#b4807744af026fdbe8c05131758fb4be https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d https://conda.anaconda.org/conda-forge/linux-64/ccache-4.10.1-h065aff2_0.conda#d6b48c138e0c8170a6fe9c136e063540 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 +https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py39h3d6467e_0.conda#76b5d215fb735a6dc43010ffbe78040e https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-he02047a_3.conda#c7f243bbaea97cd6ea1edd693270100e https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.82.2-h4833e2c_0.conda#12859f91830f58b1803e32846651c6f6 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py39h74842e3_0.conda#1bf77976372ff6de02af7b75cf034ce5 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-20_linux64_openblas.conda#2b7bb4f7562c8cf334fc2e20c2d28abc https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 -https://conda.anaconda.org/conda-forge/linux-64/libpq-16.4-h2d7952a_3.conda#50e2dddb3417a419cbc2388d0b1c06f7 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.25-pthreads_h7a3da1a_0.conda#87661673941b5e702275fdf0fc095ad0 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_2.conda#18c6deb6f9602e32446398203c8f0e91 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda#260009d03c9d5c0f111904d851f053dc +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda#fd5062942bfa1b0bd5e0d2a4397b099e +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda#f26ec986456c30f6dff154b670ae140f https://conda.anaconda.org/conda-forge/linux-64/setuptools-59.8.0-py39hf3d152e_1.tar.bz2#4252d0c211566a9f65149ba7f6e87aa4 -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.1.0-pyh8a188c0_0.tar.bz2#a2995ee828f65687ac5b1e71a2ab1e0c -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py39h8cd3c5a_1.conda#48d269953fcddbbcde078429d4b27afe -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py39h8cd3c5a_0.conda#ebfd05ae1501660e995a8b6bbe02a391 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda#d17f13df8b65464ca316cbc000a3cb64 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py39h9399b63_0.conda#997fc2d288ec458e692dfd784c173704 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.10-py39h9399b63_0.conda#cf3d6b6d3e8aba0a9ea3dec4d05c9380 https://conda.anaconda.org/conda-forge/linux-64/glib-2.82.2-h44428e9_0.conda#f19f985ab043e8843045410f3b99de8a -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 https://conda.anaconda.org/conda-forge/noarch/joblib-1.2.0-pyhd8ed1ab_0.tar.bz2#7583652522d71ad78ba536bba06940eb https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-20_linux64_openblas.conda#36d486d72ab64ffea932329a1d3729a3 -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda#ee48bf17cc83a00f59ca1494d5646869 -https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.50-h4f305b6_0.conda#0d7ff1a8e69565ca3add6925e18e708f https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-20_linux64_openblas.conda#6fabc51f5e647d09cc010c40061557e0 -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py39h538c539_0.conda#a2bafdf8ae51c9eb6e5be684cfcedd60 -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py39h15c0740_0.conda#d6e7eee1f21bce11ae03f40a77c699fe +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.12-py39h3d6467e_0.conda#e667a3ab0df62c54e60e1843d2e6defb https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.24.7-hf3bb09a_0.conda#c78bc4ef0afb3cd2365d9973c71fc876 -https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.11.0-h4ab18f5_1.conda#14858a47d4cc995892e79f2b340682d7 https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-20_linux64_openblas.conda#05c5862c7dc25e65ba6c471d96429dae +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda#ef1910918dd895516a769ed36b5b3a4e https://conda.anaconda.org/conda-forge/noarch/meson-python-0.16.0-pyh0c530f3_0.conda#e16f0dbf502da873be9f9adb0dc52547 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.19.5-py39hd249d9e_3.tar.bz2#0cf333996ebdeeba8d1c8c1c0ee9eff9 https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.12.2-py39h3d6467e_5.conda#93aff412f3e49fdb43361c0215cbd72d -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda#cb8a11b6d209e3d85e5094bdbd9ebd9c -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda#79963c319d1be62c8fd3e34555816e01 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-20_linux64_openblas.conda#9932a1d4e9ecf2d35fb19475446e361e https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.24.7-h0a52356_0.conda#d368425fbd031a2f8e801a40c3415c72 -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-256.7-h2774228_1.conda#ad328c530a12a8798776e5f03942090f https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.3.4-py39h2fa2bec_0.tar.bz2#9ec0b2186fab9121c54f4844f93ee5b7 https://conda.anaconda.org/conda-forge/linux-64/pandas-1.1.5-py39hde0f152_0.tar.bz2#79fc4b5b3a865b90dd3701cecf1ad33c https://conda.anaconda.org/conda-forge/linux-64/polars-0.20.30-py39ha963410_0.conda#322084e8890afc27fcca6df7a528df25 +https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-17.0-hb77b528_0.conda#07f45f1be1c25345faddb8db0de8039b https://conda.anaconda.org/conda-forge/linux-64/scipy-1.6.0-py39hee8e79c_0.tar.bz2#3afcb78281836e61351a2924f3230060 https://conda.anaconda.org/conda-forge/linux-64/blas-2.120-openblas.conda#c8f6916a81a340650078171b1d852574 -https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-17.0-hb77b528_0.conda#07f45f1be1c25345faddb8db0de8039b https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39hac2352c_1.tar.bz2#6fb0628d6195d8b6caa2422d09296399 -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h374914d_0.conda#26e8b00e73c114c9b787d36edcbf4424 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-hc3cb62f_2.conda#eadc22e45a87c8d5c71670d9ec956aba https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.9-py39h52134e7_5.conda#e1f148e57d071b09187719df86f513c1 https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.3.4-py39hf3d152e_0.tar.bz2#cbaec993375a908bbe506dc7328d747c diff --git a/build_tools/azure/pymin_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock b/build_tools/azure/pymin_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock index 2924533aadbde..35efc02036955 100644 --- a/build_tools/azure/pymin_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock +++ b/build_tools/azure/pymin_conda_forge_openblas_ubuntu_2204_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: 3974f9847d888a2fd37ba5fcfb76cb09bba4c9b84b6200932500fc94e3b0c4ae @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb @@ -12,29 +12,31 @@ https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-5_cp39.conda#4036 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.3-h024ca30_0.conda#d36687dc90337917a84a96a45111ad59 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.6-h024ca30_0.conda#96e42ccbd3c067c1713ff5f2d2169247 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 -https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_1.conda#e12057a66af8f2a38a839754ca4481e9 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 +https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda#7df50d44d4a14d6c31a2c54f2cd92157 https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de @@ -43,32 +45,29 @@ https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.co https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda#f87c7b7c2cb45f323ffbce941c78ab7c https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_1.conda#62857b389e42b36b686331bec0922050 https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 @@ -76,126 +75,125 @@ https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda# https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_openblas.conda#ac52800af2e0c0e7dac770b435ce768a https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a -https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_0.conda#9ebc9aedafaa2515ab247ff6bb509458 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.20-h13acc7a_1_cpython.conda#951cff166a5f170e27908811917165f8 +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 +https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.28-pthreads_h6ec200e_1.conda#8fe5d50db07e92519cc639cb0aef9b1b +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda#b4807744af026fdbe8c05131758fb4be https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py39hf88036b_2.conda#8ea5af6ac902f1a4429190970d9099ce -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d https://conda.anaconda.org/conda-forge/linux-64/ccache-4.10.1-h065aff2_0.conda#d6b48c138e0c8170a6fe9c136e063540 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda#e83a31202d1c0a000fce3e9cf3825875 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py39hde8bd2b_3.conda#52637110266d72a26d01d3d81038664e https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 -https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 +https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda#24c1ca34138ee57de72a943237cde4cc +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyhd8ed1ab_1.conda#2aa5ff7fa34a81b9196532c84c10d865 +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_1.conda#566e75c90c1d0c8c459eb0ad9833dc7a +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda#39a4f67be3286c86d696df570b1201b7 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py39h74842e3_0.conda#1bf77976372ff6de02af7b75cf034ce5 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_openblas.conda#8ea26d42ca88ec5258802715fe1ee10b +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_openblas.conda#ebcc5f37a435aa3c19640533c82f8d76 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-26_linux64_openblas.conda#3792604c43695d6a273bc5faaac47d48 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda#e71f31f8cfb0a91439f2086fc8aa0461 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_0.conda#d38773fed557834d3211e019b7cf7c2f +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_1.conda#7821f0938aa629b9f17efd98c300a487 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.28-pthreads_hbcdf1e8_0.conda#edb742fa7cd3fc5fbcbfc24135dcadd8 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda#12c566707c80111f9799308d9e265aef +https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_1.conda#b38dc0206e2a530e5c2cf11dc086b31a +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_1.conda#c0def296b2f6d2dd7b030c2a7f66bb1f https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 -https://conda.anaconda.org/conda-forge/noarch/tabulate-0.9.0-pyhd8ed1ab_1.tar.bz2#4759805cce2d914c38472f70bf4d8bcb +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda#fa839b5ff59e192f411ccc7dae6588bb +https://conda.anaconda.org/conda-forge/noarch/tabulate-0.9.0-pyhd8ed1ab_2.conda#959484a66b4b76befcddc4fa97c95567 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py39h8cd3c5a_1.conda#48d269953fcddbbcde078429d4b27afe +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py39h8cd3c5a_0.conda#ebfd05ae1501660e995a8b6bbe02a391 https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py39h8cd3c5a_1.conda#6346898044e4387631c614290789a434 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda#2ccd714aa2242315acaf0a67faea780b https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 -https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda#9669586875baeced8fc30c0826c3270e +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 +https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_1.conda#3e23f7db93ec14c80525257d8affac28 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py39h15c3d72_0.conda#7e61b8777f42e00b08ff059f9e8ebc44 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py39h9399b63_1.conda#1a4772f78ffa4675c84a4219db3934fd -https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_openblas.conda#5dbd1b0fc0d01ec5e0e1fbe667281a11 -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_openblas.conda#4dc03a53fc69371a6158d0ed37214cd3 -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py39h538c539_0.conda#a2bafdf8ae51c9eb6e5be684cfcedd60 -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.55.3-py39h9399b63_1.conda#5cd3b942589049b43ef3a65d1f63c488 +https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_1.conda#825927dc7b0f287ef8d4d0011bb113b1 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_1.conda#315607a3030ad5d5227e76e0733798ff +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_1.conda#15798fa69312d433af690c8c42b3fb36 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.5-pyhd8ed1ab_0.conda#2752a6ed44105bfb18c9bef1177d9dcd +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-26_linux64_openblas.conda#7b8b7732fb4786c00cf9b67d1d69445c +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_1.conda#be95cf76ebd05d08be67e50e88d3cd49 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py39h15c0740_0.conda#d6e7eee1f21bce11ae03f40a77c699fe +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_0.conda#67f4772681cf86652f3e2261794cf045 -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-25_linux64_openblas.conda#8f5ead31b3a168aedd488b8a87736c41 -https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_0.conda#ed28982e8b085c5d47361fc4af0902ac -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 -https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py39h08a7858_1.conda#cd9fa334e11886738f17254f52210bc3 -https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-25_linux64_openblas.conda#02c516384c77f5a7b4d03ed6c0412c57 +https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-26_linux64_openblas.conda#da61c3ef2fbe100b0613cbc2b01b502d https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py39h74842e3_2.conda#5645190ef7f6d3aebee71e298dc9677b +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_1.conda#59561d9b70f9df3b884c29910eba6593 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py39h3b40f6f_1.conda#d07f482720066758dad87cf90b3de111 -https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.0-h6e8976b_0.conda#6d1c5d2d904d24c17cbb538a95855a4e +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/linux-64/scipy-1.13.1-py39haf93ffa_0.conda#492a2cd65862d16a4aaf535ae9ccb761 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.125-openblas.conda#0c46b8a31a587738befc587dd8e52558 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py39h16632d1_1.conda#83d48ae12dfd01615013e2e8ace6ff86 +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py39h08a7858_1.conda#cd9fa334e11886738f17254f52210bc3 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.126-openblas.conda#057a3d8aebeae33d971bc66ee08cbf61 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py39h16632d1_0.conda#f149592d52f9c1ab1bfe3dc055458e13 https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py39hf59e57a_1.conda#720dbce3188cecd95fc26525394d1e65 -https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.0.2-py39h0383914_0.conda#b93573a620eb5396f0196e6267490738 -https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.2-py39hf3d152e_1.conda#18df8fd10aeee04b1721c2efbf95c8cd -https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.8.0-pyhd8ed1ab_0.conda#0a5522bdd3983c52102e75d1307ad8c4 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.1-h588cce1_2.conda#5d2f1f29c025a110a43f9946527623ab +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda#32674f8dbfb7b26410ed580dd3c10a29 +https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.1-py39h0383914_0.conda#45e71bee7ab5236b01ec50343d70b15e +https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda#a9b9368f3701a417eac9edbcae7cb737 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py39hf3d152e_0.conda#922f2edd2f9ff0a95c83eb781bacad5e +https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.8.0-pyhd8ed1ab_1.conda#5af206d64d18d6c8dfb3122b4d9e643b +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_1.conda#16e3f039c0aa6446513e94ab18a8784b +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_1.conda#910f28a05c178feba832f842155cbfff +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda#e9fb3fe8a5b758b4aff187d434f94f03 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda#00534ebcc0375929b45c3039b5ba7636 https://conda.anaconda.org/conda-forge/noarch/sphinx-7.4.7-pyhd8ed1ab_0.conda#c568e260463da2528ecfd7c5a0b41bbd -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda#3bc61f7161d28137797e038263c04c54 diff --git a/build_tools/azure/test_script.sh b/build_tools/azure/test_script.sh index 48e5d1041da56..48d018d40c7e1 100755 --- a/build_tools/azure/test_script.sh +++ b/build_tools/azure/test_script.sh @@ -48,6 +48,12 @@ if [[ "$COVERAGE" == "true" ]]; then # report that otherwise hides the test failures and forces long scrolls in # the CI logs. export COVERAGE_PROCESS_START="$BUILD_SOURCESDIRECTORY/.coveragerc" + + # Use sys.monitoring to make coverage faster for Python >= 3.12 + HAS_SYSMON=$(python -c 'import sys; print(sys.version_info >= (3, 12))') + if [[ "$HAS_SYSMON" == "True" ]]; then + export COVERAGE_CORE=sysmon + fi TEST_CMD="$TEST_CMD --cov-config='$COVERAGE_PROCESS_START' --cov sklearn --cov-report=" fi diff --git a/build_tools/azure/ubuntu_atlas_lock.txt b/build_tools/azure/ubuntu_atlas_lock.txt index 6a79490ba6c66..d12067653231c 100644 --- a/build_tools/azure/ubuntu_atlas_lock.txt +++ b/build_tools/azure/ubuntu_atlas_lock.txt @@ -14,13 +14,13 @@ iniconfig==2.0.0 # via pytest joblib==1.2.0 # via -r build_tools/azure/ubuntu_atlas_requirements.txt -meson==1.6.0 +meson==1.6.1 # via meson-python meson-python==0.17.1 # via -r build_tools/azure/ubuntu_atlas_requirements.txt -ninja==1.11.1.1 +ninja==1.11.1.3 # via -r build_tools/azure/ubuntu_atlas_requirements.txt -packaging==24.1 +packaging==24.2 # via # meson-python # pyproject-metadata @@ -29,7 +29,7 @@ pluggy==1.5.0 # via pytest pyproject-metadata==0.9.0 # via meson-python -pytest==8.3.3 +pytest==8.3.4 # via # -r build_tools/azure/ubuntu_atlas_requirements.txt # pytest-xdist @@ -37,7 +37,7 @@ pytest-xdist==3.6.1 # via -r build_tools/azure/ubuntu_atlas_requirements.txt threadpoolctl==3.1.0 # via -r build_tools/azure/ubuntu_atlas_requirements.txt -tomli==2.0.2 +tomli==2.2.1 # via # meson-python # pytest diff --git a/build_tools/circle/build_doc.sh b/build_tools/circle/build_doc.sh index 058061641d2b9..1b161beecd507 100755 --- a/build_tools/circle/build_doc.sh +++ b/build_tools/circle/build_doc.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -e +set -x # Decide what kind of documentation build to run, and run it. # @@ -30,11 +31,18 @@ then then CIRCLE_BRANCH=$GITHUB_HEAD_REF CI_PULL_REQUEST=true + CI_TARGET_BRANCH=$GITHUB_BASE_REF else CIRCLE_BRANCH=$GITHUB_REF_NAME fi fi +if [[ -n "$CI_PULL_REQUEST" && -z "$CI_TARGET_BRANCH" ]] +then + # Get the target branch name when using CircleCI + CI_TARGET_BRANCH=$(curl -s "https://api.github.com/repos/scikit-learn/scikit-learn/pulls/$CIRCLE_PR_NUMBER" | jq -r .base.ref) +fi + get_build_type() { if [ -z "$CIRCLE_SHA1" ] then @@ -167,23 +175,34 @@ bash ./miniconda.sh -b -p $MINIFORGE_PATH source $MINIFORGE_PATH/etc/profile.d/conda.sh conda activate -export PATH="/usr/lib/ccache:$PATH" -ccache -M 512M -export CCACHE_COMPRESS=1 create_conda_environment_from_lock_file $CONDA_ENV_NAME $LOCK_FILE conda activate $CONDA_ENV_NAME +# Sets up ccache when using system compiler +export PATH="/usr/lib/ccache:$PATH" +# Sets up ccache when using conda-forge compilers (needs to be after conda +# activate which sets CC and CXX) +export CC="ccache $CC" +export CXX="ccache $CXX" +ccache -M 512M +export CCACHE_COMPRESS=1 +# Zeroing statistics so that ccache statistics are shown only for this build +ccache -z + show_installed_libraries -pip install -e . --no-build-isolation +# Specify explictly ninja -j argument because ninja does not handle cgroups v2 and +# use the same default rule as ninja (-j3 since we have 2 cores on CircleCI), see +# https://github.com/scikit-learn/scikit-learn/pull/30333 +pip install -e . --no-build-isolation --config-settings=compile-args="-j 3" echo "ccache build summary:" ccache -s export OMP_NUM_THREADS=1 -if [[ "$CIRCLE_BRANCH" =~ ^main$ || -n "$CI_PULL_REQUEST" ]] +if [[ "$CIRCLE_BRANCH" == "main" || "$CI_TARGET_BRANCH" == "main" ]] then towncrier build --yes fi @@ -202,9 +221,16 @@ cd - set +o pipefail affected_doc_paths() { + scikit_learn_version=$(python -c 'import re; import sklearn; print(re.sub(r"(\d+\.\d+).+", r"\1", sklearn.__version__))') files=$(git diff --name-only origin/main...$CIRCLE_SHA1) # use sed to replace files ending by .rst or .rst.template by .html - echo "$files" | grep ^doc/.*\.rst | sed 's/^doc\/\(.*\)\.rst$/\1.html/; s/^doc\/\(.*\)\.rst\.template$/\1.html/' + echo "$files" | grep -vP 'upcoming_changes/.*/\d+.*\.rst' | grep ^doc/.*\.rst | \ + sed 's/^doc\/\(.*\)\.rst$/\1.html/; s/^doc\/\(.*\)\.rst\.template$/\1.html/' + # replace towncrier fragment files by link to changelog. uniq is used + # because in some edge cases multiple fragments can be added and we want a + # single link to the changelog. + echo "$files" | grep -P 'upcoming_changes/.*/\d+.*\.rst' | sed "s@.*@whats_new/v${scikit_learn_version}.html@" | uniq + echo "$files" | grep ^examples/.*.py | sed 's/^\(.*\)\.py$/auto_\1.html/' sklearn_files=$(echo "$files" | grep '^sklearn/') if [ -n "$sklearn_files" ] diff --git a/build_tools/circle/doc_linux-64_conda.lock b/build_tools/circle/doc_linux-64_conda.lock index c6bda359eacdb..d41fd4072dccd 100644 --- a/build_tools/circle/doc_linux-64_conda.lock +++ b/build_tools/circle/doc_linux-64_conda.lock @@ -3,7 +3,7 @@ # input_hash: b96afbd150db7ab25e05a34ca1f5ca90f8b1e2fcd993f870601b7376eb9f39d2 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb @@ -14,36 +14,38 @@ https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-13.3.0-h84ea5a7_101.conda#0ce69d40c142915ac9734bc6134e514a -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.3.0-h84ea5a7_101.conda#29b5a4ed4613fa81a07c21045e3f5bf6 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.3-h024ca30_0.conda#d36687dc90337917a84a96a45111ad59 -https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h4a8ded7_18.conda#0ea96f90a10838f58412aa84fdd9df09 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.6-h024ca30_0.conda#96e42ccbd3c067c1713ff5f2d2169247 +https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h0157908_18.conda#460eba7851277ec1fd80a1a24080787a https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.43-h4bf12b8_2.conda#cf0c5521ac2a20dfa6c662a4009eeef6 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 -https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_1.conda#e12057a66af8f2a38a839754ca4481e9 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 +https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda#7df50d44d4a14d6c31a2c54f2cd92157 https://conda.anaconda.org/conda-forge/linux-64/binutils-2.43-h4852527_2.conda#348619f90eee04901f4a70615efff35b https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.43-h4852527_2.conda#18aba879ddf1f8f28145ca6fcb873d8c https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda#5aeabe88534ea4169d4c49998f293d6c https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 @@ -54,25 +56,24 @@ https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.co https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.3.0-heb74ff8_1.conda#c4cb22f270f501f5c59a122dc2adf20a -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 https://conda.anaconda.org/conda-forge/linux-64/rav1e-0.6.6-he8a937b_2.conda#77d9955b4abddb811cb8ab1aa7d743e4 +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda#3b3e64af585eadfb52bb90b553db5edf https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.3.0-h5888daf_0.conda#355898d24394b2af353eb96358db9fdd https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h5888daf_2.conda#e0409515c467b87176b070bff5d9442e -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 -https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.2.2-h5888daf_0.conda#135fd3c66bccad3d2254f50f9809e86a +https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.2.3-h7955e40_0.conda#01cf93c645fa03d44ffe603f51f3d27f https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/charls-2.4.2-h59595ed_0.conda#4336bd67920dd504cd8c6761d6a99645 @@ -83,226 +84,224 @@ https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.c https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.1.0-h00ab1b0_0.conda#88928158ccfe797eac29ef5e03f7d23d https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_1.conda#62857b389e42b36b686331bec0922050 https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 -https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-hef167b5_0.conda#54fe76ab3d0189acaef95156874db7f9 +https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda#2c2fae981fd2afd00812c92ac47d023d https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f -https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.15.1-hc57e6cf_0.conda#5f84961d86d0ef78851cb34f9d5e31fe +https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.15.2-h3122c55_1.conda#2bc8d76acd818d7e79229f5157d5c156 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/gcc-13.3.0-h9576a4e_1.conda#606924335b5bcdf90e9aed9a2f5d22ed -https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-13.3.0-hc28eda2_5.conda#ffbadbbc3345d9a315ba31c8a9188d4c +https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-13.3.0-hc28eda2_7.conda#ac23afbf5805389eb771e2ad3b476f75 https://conda.anaconda.org/conda-forge/linux-64/gfortran_impl_linux-64-13.3.0-h10434e7_1.conda#6709e113709b6ba67cc0f4b0de58ef7f https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hdbfa832_1.conda#806367e23a0a6ad21e51875b34c57d7e https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 https://conda.anaconda.org/conda-forge/linux-64/libavif16-1.1.1-h1909e37_2.conda#21e468ed3786ebcb2124b123aa2484b7 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_openblas.conda#8ea26d42ca88ec5258802715fe1ee10b +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_openblas.conda#ac52800af2e0c0e7dac770b435ce768a https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 -https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.0-hdb8da77_2.conda#9c4554fafc94db681543804037e65de2 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c +https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.1-hdb8da77_0.conda#32b23f3487beae7e81495fbc1099ae9e +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.28-pthreads_h6ec200e_1.conda#8fe5d50db07e92519cc639cb0aef9b1b -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.20-h13acc7a_1_cpython.conda#951cff166a5f170e27908811917165f8 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda#b4807744af026fdbe8c05131758fb4be https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py39hf88036b_2.conda#8ea5af6ac902f1a4429190970d9099ce https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.8.0-h2b85faf_1.conda#fa7b3bf2965b9d74a81a0702d9bb49ee -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 -https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda#e83a31202d1c0a000fce3e9cf3825875 +https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda#f22f4d4970e09d68a10b922cbb0408d3 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py39hde8bd2b_3.conda#52637110266d72a26d01d3d81038664e https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 +https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda#24c1ca34138ee57de72a943237cde4cc +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 https://conda.anaconda.org/conda-forge/linux-64/gfortran-13.3.0-h9576a4e_1.conda#5e5e3b592d5174eb49607a973c77825b -https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-13.3.0-hb919d3a_5.conda#67dbd742855cc95233eb04c43004a29a +https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-13.3.0-hb919d3a_7.conda#0b8e7413559c4c892a37c35de4559969 https://conda.anaconda.org/conda-forge/linux-64/gxx-13.3.0-h9576a4e_1.conda#209182ca6b20aeff62f442e843961d81 -https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_5.conda#81ddb2db98fbe3031aa7ebbbf8bb3ffd -https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 -https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 +https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_7.conda#7c82ca9bda609b6f72f670e4219d3787 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyhd8ed1ab_1.conda#2aa5ff7fa34a81b9196532c84c10d865 +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_1.conda#566e75c90c1d0c8c459eb0ad9833dc7a +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda#39a4f67be3286c86d696df570b1201b7 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py39h74842e3_0.conda#1bf77976372ff6de02af7b75cf034ce5 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_openblas.conda#5dbd1b0fc0d01ec5e0e1fbe667281a11 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_openblas.conda#ebcc5f37a435aa3c19640533c82f8d76 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_openblas.conda#4dc03a53fc69371a6158d0ed37214cd3 -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-26_linux64_openblas.conda#3792604c43695d6a273bc5faaac47d48 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda#e71f31f8cfb0a91439f2086fc8aa0461 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_0.conda#d38773fed557834d3211e019b7cf7c2f +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_1.conda#7821f0938aa629b9f17efd98c300a487 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 https://conda.anaconda.org/conda-forge/noarch/networkx-3.2.1-pyhd8ed1ab_0.conda#425fce3b531bed6ec3c74fab3e5f0a1c -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_0.conda#fd8f2b18b65bbf62e8f653100690c8d2 -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.0-py39h8cd3c5a_0.conda#ef257b7ce1e1cb152639ced6bc653475 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.6-pyhd8ed1ab_1.conda#577852c7e53901ddccc7e6a9959ddebe +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.1-py39h8cd3c5a_0.conda#287b29f8df0363b2a53a5a6e6ce4fa5c +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda#12c566707c80111f9799308d9e265aef +https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_1.conda#b38dc0206e2a530e5c2cf11dc086b31a +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_1.conda#c0def296b2f6d2dd7b030c2a7f66bb1f https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 -https://conda.anaconda.org/conda-forge/noarch/tabulate-0.9.0-pyhd8ed1ab_1.tar.bz2#4759805cce2d914c38472f70bf4d8bcb -https://conda.anaconda.org/conda-forge/noarch/tenacity-9.0.0-pyhd8ed1ab_0.conda#42af51ad3b654ece73572628ad2882ae +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda#fa839b5ff59e192f411ccc7dae6588bb +https://conda.anaconda.org/conda-forge/noarch/tabulate-0.9.0-pyhd8ed1ab_2.conda#959484a66b4b76befcddc4fa97c95567 +https://conda.anaconda.org/conda-forge/noarch/tenacity-9.0.0-pyhd8ed1ab_1.conda#a09f66fe95a54a92172e56a4a97ba271 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py39h8cd3c5a_1.conda#48d269953fcddbbcde078429d4b27afe -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py39h8cd3c5a_0.conda#ebfd05ae1501660e995a8b6bbe02a391 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda#d17f13df8b65464ca316cbc000a3cb64 https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py39h8cd3c5a_1.conda#6346898044e4387631c614290789a434 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda#2ccd714aa2242315acaf0a67faea780b https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 -https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a -https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_0.conda#6d4e9ecca8d88977147e109fc7053184 -https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 +https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_1.conda#74ac5069774cdbc53910ec4d631a3999 +https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_1.conda#3e23f7db93ec14c80525257d8affac28 +https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_1.conda#d48f7e9fdec44baf6d1da416fe402b04 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py39h15c3d72_0.conda#7e61b8777f42e00b08ff059f9e8ebc44 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.8.0-h1a2810e_1.conda#3bb4907086d7187bf01c8bec397ffa5e -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py39h9399b63_1.conda#1a4772f78ffa4675c84a4219db3934fd +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.55.3-py39h9399b63_1.conda#5cd3b942589049b43ef3a65d1f63c488 https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.8.0-h36df796_1.conda#6b57750841d53ade8d3b47eafe53dd9f -https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-25_linux64_openblas.conda#8f5ead31b3a168aedd488b8a87736c41 -https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_0.tar.bz2#8b45f9f2b2f7a98b0ec179c8991a4a9b -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_0.conda#ed28982e8b085c5d47361fc4af0902ac -https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py39h538c539_0.conda#a2bafdf8ae51c9eb6e5be684cfcedd60 -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/plotly-5.24.1-pyhd8ed1ab_0.conda#81bb643d6c3ab4cbeaf724e9d68d0a6a -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c +https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_1.conda#825927dc7b0f287ef8d4d0011bb113b1 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_1.conda#315607a3030ad5d5227e76e0733798ff +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_1.conda#15798fa69312d433af690c8c42b3fb36 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.5-pyhd8ed1ab_0.conda#2752a6ed44105bfb18c9bef1177d9dcd +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-26_linux64_openblas.conda#7b8b7732fb4786c00cf9b67d1d69445c +https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_1.conda#71abbefb6f3b95e1668cd5e0af3affb9 +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_1.conda#be95cf76ebd05d08be67e50e88d3cd49 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py39h15c0740_0.conda#d6e7eee1f21bce11ae03f40a77c699fe +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/plotly-5.24.1-pyhd8ed1ab_1.conda#71ac632876630091c81c50a05ec5e030 +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f -https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-25_linux64_openblas.conda#02c516384c77f5a7b4d03ed6c0412c57 +https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-26_linux64_openblas.conda#da61c3ef2fbe100b0613cbc2b01b502d https://conda.anaconda.org/conda-forge/linux-64/compilers-1.8.0-ha770c72_1.conda#061e111d02f33a99548f0de07169d9fb https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py39h74842e3_2.conda#5645190ef7f6d3aebee71e298dc9677b -https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2024.9.22-py39h1aa77c4_0.conda#6001ae3f85403137d61e3ef7e96dd940 -https://conda.anaconda.org/conda-forge/noarch/imageio-2.36.0-pyh12aca89_1.conda#36349844ff73fcd0140ee7f30745f0bf -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_0.conda#67f4772681cf86652f3e2261794cf045 -https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_1.conda#4809b9f4c6ce106d443c3f90b8e10db2 -https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 +https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2024.9.22-py39hac51188_2.conda#87d7ce1f90bf94f40584db14777f8765 +https://conda.anaconda.org/conda-forge/noarch/imageio-2.36.1-pyh12aca89_1.conda#84d5a2f075c861a8f98afd2842f7eb6e +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_1.conda#59561d9b70f9df3b884c29910eba6593 +https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.4-pyhd8ed1ab_2.conda#d10d9393680734a8febc4b362a4c94f2 +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py39h3b40f6f_1.conda#d07f482720066758dad87cf90b3de111 -https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.6-pyhd8ed1ab_0.conda#a5b55d1cb110cdcedc748b5c3e16e687 -https://conda.anaconda.org/conda-forge/linux-64/polars-1.12.0-py39h74f158a_0.conda#698f8f845bcb227d52695b4ab6f7c381 -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda#ee23fabfd0a8c6b8d6f3729b47b2859d +https://conda.anaconda.org/conda-forge/linux-64/polars-1.17.1-py39h0cd0d40_0.conda#61d726e861b268c5d128465645b565f6 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py39hd92a3bb_0.conda#32e26e16f60c568b17a82e3033a4d309 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.13.1-py39haf93ffa_0.conda#492a2cd65862d16a4aaf535ae9ccb761 https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py39h08a7858_1.conda#cd9fa334e11886738f17254f52210bc3 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.125-openblas.conda#0c46b8a31a587738befc587dd8e52558 -https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_1.conda#ec6f70b8a5242936567d4f886726a372 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py39h16632d1_1.conda#83d48ae12dfd01615013e2e8ace6ff86 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.126-openblas.conda#057a3d8aebeae33d971bc66ee08cbf61 +https://conda.anaconda.org/conda-forge/noarch/lazy_loader-0.4-pyhd8ed1ab_2.conda#bb0230917e2473c77d615104dbe8a49d +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.4-py39h16632d1_0.conda#f149592d52f9c1ab1bfe3dc055458e13 https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py39hf59e57a_1.conda#720dbce3188cecd95fc26525394d1e65 -https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.0-h6e8976b_0.conda#6d1c5d2d904d24c17cbb538a95855a4e +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.1-h588cce1_2.conda#5d2f1f29c025a110a43f9946527623ab https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.4-py39hf3d9206_0.conda#f633ed7c19e120b9e6c0efb79f20a53f https://conda.anaconda.org/conda-forge/noarch/tifffile-2024.6.18-pyhd8ed1ab_0.conda#7c3077529bfe3b86f9425d526d73bd24 -https://conda.anaconda.org/conda-forge/noarch/towncrier-24.8.0-pyhd8ed1ab_0.conda#02190423152df62fda1cde3d9527b882 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 -https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.0.2-py39h0383914_0.conda#b93573a620eb5396f0196e6267490738 -https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 +https://conda.anaconda.org/conda-forge/noarch/towncrier-24.8.0-pyhd8ed1ab_1.conda#820b6a1ddf590fba253f8204f7200d82 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda#32674f8dbfb7b26410ed580dd3c10a29 +https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.1-py39h0383914_0.conda#45e71bee7ab5236b01ec50343d70b15e +https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda#a9b9368f3701a417eac9edbcae7cb737 https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.24.0-py39h3b40f6f_3.conda#63666cfacc4dc32c8b2ff49705988f92 -https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_2.conda#b713b116feaf98acdba93ad4d7f90ca1 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.2-py39hf3d152e_1.conda#18df8fd10aeee04b1721c2efbf95c8cd -https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_0.conda#8dab97d8a9616e07d779782995710aed -https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_2.conda#a79d8797f62715255308d92d3a91ef2e -https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.8.0-pyhd8ed1ab_0.conda#0a5522bdd3983c52102e75d1307ad8c4 -https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.16.0-pyhd8ed1ab_0.conda#344261b0e77f5d2faaffb4eac225eeb7 -https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda#ac832cc43adc79118cf6e23f1f9b8995 -https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.1-pyhd8ed1ab_1.conda#db0f1eb28b6df3a11e89437597309009 -https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.18.0-pyhd8ed1ab_0.conda#dc78276cbf5ec23e4b959d1bbd9caadb +https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_3.conda#fd96da444e81f9e6fcaac38590f3dd42 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.4-py39hf3d152e_0.conda#922f2edd2f9ff0a95c83eb781bacad5e +https://conda.anaconda.org/conda-forge/noarch/pooch-1.8.2-pyhd8ed1ab_1.conda#b3e783e8e8ed7577cf0b6dee37d1fbac +https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_3.conda#62afb877ca2c2b4b6f9ecb37320085b6 +https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.8.0-pyhd8ed1ab_1.conda#5af206d64d18d6c8dfb3122b4d9e643b +https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.16.1-pyhd8ed1ab_0.conda#837aaf71ddf3b27acae0e7e9015eebc6 +https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_1.conda#bf22cb9c439572760316ce0748af3713 +https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.1-pyhd8ed1ab_2.conda#3e6c15d914b03f83fc96344f917e0838 +https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.18.0-pyhd8ed1ab_1.conda#aa09c826cf825f905ade2586978263ca https://conda.anaconda.org/conda-forge/noarch/sphinx-prompt-1.4.0-pyhd8ed1ab_0.tar.bz2#88ee91e8679603f2a5bd036d52919cc2 https://conda.anaconda.org/conda-forge/noarch/sphinx-remove-toctrees-1.0.0.post1-pyhd8ed1ab_0.conda#6dee8412218288a17f99f2cfffab334d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_1.conda#16e3f039c0aa6446513e94ab18a8784b +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_1.conda#910f28a05c178feba832f842155cbfff +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda#e9fb3fe8a5b758b4aff187d434f94f03 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda#00534ebcc0375929b45c3039b5ba7636 https://conda.anaconda.org/conda-forge/noarch/sphinx-7.4.7-pyhd8ed1ab_0.conda#c568e260463da2528ecfd7c5a0b41bbd -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e -https://conda.anaconda.org/conda-forge/noarch/sphinxext-opengraph-0.9.1-pyhd8ed1ab_0.conda#286283e05a1eff606f55e7cd70f6d7f7 -# pip attrs @ https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl#sha256=81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda#3bc61f7161d28137797e038263c04c54 +https://conda.anaconda.org/conda-forge/noarch/sphinxext-opengraph-0.9.1-pyhd8ed1ab_1.conda#79f5d05ad914baf152fb7f75073fe36d +# pip attrs @ https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl#sha256=ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308 # pip cloudpickle @ https://files.pythonhosted.org/packages/48/41/e1d85ca3cab0b674e277c8c4f678cf66a91cd2cecf93df94353a606fe0db/cloudpickle-3.1.0-py3-none-any.whl#sha256=fe11acda67f61aaaec473e3afe030feb131d78a43461b718185363384f1ba12e # pip defusedxml @ https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl#sha256=a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 -# pip fastjsonschema @ https://files.pythonhosted.org/packages/6d/ca/086311cdfc017ec964b2436fe0c98c1f4efcb7e4c328956a22456e497655/fastjsonschema-2.20.0-py3-none-any.whl#sha256=5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a +# pip fastjsonschema @ https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl#sha256=c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667 # pip fqdn @ https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl#sha256=3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014 -# pip json5 @ https://files.pythonhosted.org/packages/8a/3c/4f8791ee53ab9eeb0b022205aa79387119a74cc9429582ce04098e6fc540/json5-0.9.25-py3-none-any.whl#sha256=34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f +# pip json5 @ https://files.pythonhosted.org/packages/aa/42/797895b952b682c3dafe23b1834507ee7f02f4d6299b65aaa61425763278/json5-0.10.0-py3-none-any.whl#sha256=19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa # pip jsonpointer @ https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl#sha256=13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942 # pip jupyterlab-pygments @ https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl#sha256=841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780 # pip libsass @ https://files.pythonhosted.org/packages/fd/5a/eb5b62641df0459a3291fc206cf5bd669c0feed7814dded8edef4ade8512/libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl#sha256=4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306 -# pip mistune @ https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl#sha256=71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205 +# pip mdurl @ https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl#sha256=84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 # pip overrides @ https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl#sha256=c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49 # pip pandocfilters @ https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl#sha256=93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc -# pip pkginfo @ https://files.pythonhosted.org/packages/17/b7/71f9fbebc37ecf55233407f348b9acc974482e6ee37d057a1e8e3baba081/pkginfo-1.11.2-py3-none-any.whl#sha256=9ec518eefccd159de7ed45386a6bb4c6ca5fa2cb3bd9b71154fae44f6f1b36a3 -# pip prometheus-client @ https://files.pythonhosted.org/packages/84/2d/46ed6436849c2c88228c3111865f44311cff784b4aabcdef4ea2545dbc3d/prometheus_client-0.21.0-py3-none-any.whl#sha256=4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166 +# pip pkginfo @ https://files.pythonhosted.org/packages/21/11/4af184fbd8ae13daa13953212b27a212f4e63772ca8a0dd84d08b60ed206/pkginfo-1.12.0-py3-none-any.whl#sha256=dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088 +# pip prometheus-client @ https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl#sha256=594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301 # pip ptyprocess @ https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl#sha256=4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 -# pip python-json-logger @ https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl#sha256=f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd # pip pyyaml @ https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 # pip rfc3986-validator @ https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl#sha256=2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9 -# pip rpds-py @ https://files.pythonhosted.org/packages/44/ab/6fd9144e3b182b7c6ee09fd3f1718541d86c74a595f2afe0bd8bf8fb5db0/rpds_py-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592 +# pip rpds-py @ https://files.pythonhosted.org/packages/93/f5/c1c772364570d35b98ba64f36ec90c3c6d0b932bc4d8b9b4efef6dc64b07/rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543 # pip send2trash @ https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl#sha256=0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9 # pip sniffio @ https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl#sha256=2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 # pip traitlets @ https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl#sha256=b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f -# pip types-python-dateutil @ https://files.pythonhosted.org/packages/35/d6/ba5f61958f358028f2e2ba1b8e225b8e263053bd57d3a79e2d2db64c807b/types_python_dateutil-2.9.0.20241003-py3-none-any.whl#sha256=250e1d8e80e7bbc3a6c99b907762711d1a1cdd00e978ad39cb5940f6f0a87f3d +# pip types-python-dateutil @ https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl#sha256=e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53 # pip uri-template @ https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl#sha256=a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363 -# pip webcolors @ https://files.pythonhosted.org/packages/f0/33/12020ba99beaff91682b28dc0bbf0345bbc3244a4afbae7644e4fa348f23/webcolors-24.8.0-py3-none-any.whl#sha256=fc4c3b59358ada164552084a8ebee637c221e4059267d0f8325b3b560f6c7f0a +# pip webcolors @ https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl#sha256=515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9 # pip webencodings @ https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl#sha256=a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 # pip websocket-client @ https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl#sha256=17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526 -# pip anyio @ https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl#sha256=6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d +# pip anyio @ https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl#sha256=b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a # pip argon2-cffi-bindings @ https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae # pip arrow @ https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl#sha256=c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80 -# pip bleach @ https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl#sha256=117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e # pip doit @ https://files.pythonhosted.org/packages/44/83/a2960d2c975836daa629a73995134fd86520c101412578c57da3d2aa71ee/doit-0.36.0-py3-none-any.whl#sha256=ebc285f6666871b5300091c26eafdff3de968a6bd60ea35dd1e3fc6f2e32479a # pip jupyter-core @ https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl#sha256=4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409 +# pip markdown-it-py @ https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl#sha256=355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 +# pip mistune @ https://files.pythonhosted.org/packages/b4/b3/743ffc3f59da380da504d84ccd1faf9a857a1445991ff19bf2ec754163c2/mistune-3.1.0-py3-none-any.whl#sha256=b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1 +# pip python-json-logger @ https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl#sha256=cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090 # pip pyzmq @ https://files.pythonhosted.org/packages/6e/bd/3ff3e1172f12f55769793a3a334e956ec2886805ebfb2f64756b6b5c6a1a/pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl#sha256=05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9 # pip referencing @ https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl#sha256=eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de # pip rfc3339-validator @ https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl#sha256=24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa @@ -310,17 +309,20 @@ https://conda.anaconda.org/conda-forge/noarch/sphinxext-opengraph-0.9.1-pyhd8ed1 # pip terminado @ https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl#sha256=a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0 # pip tinycss2 @ https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl#sha256=3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289 # pip argon2-cffi @ https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl#sha256=c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea +# pip bleach @ https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl#sha256=117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e # pip isoduration @ https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl#sha256=b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042 # pip jsonschema-specifications @ https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl#sha256=a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf # pip jupyter-client @ https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl#sha256=e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f # pip jupyter-server-terminals @ https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl#sha256=41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa -# pip jupyterlite-core @ https://files.pythonhosted.org/packages/3a/d9/ca90f3136565863ae3ddc445a38c965124655010b0102c409cbd31151161/jupyterlite_core-0.4.3-py3-none-any.whl#sha256=1922530b04196c985b69cfdf94654c64ca55598cd69b4214442579fef51c9877 +# pip jupyterlite-core @ https://files.pythonhosted.org/packages/ff/51/0812a39260335c708c6f150e66e5d0ff2adcc40885f0a8b7244639286960/jupyterlite_core-0.4.5-py3-none-any.whl#sha256=2c30b815b0699d50160bfec35ff612295f8518ac66cf52acd7bfe41aa42ce0be +# pip mdit-py-plugins @ https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl#sha256=0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636 # pip jsonschema @ https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl#sha256=fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566 -# pip jupyterlite-pyodide-kernel @ https://files.pythonhosted.org/packages/ea/f1/bd65f1fe3b9535f5aa00d89ed2b2bf3cf4cff39273a3e7dac97e890141cd/jupyterlite_pyodide_kernel-0.4.3-py3-none-any.whl#sha256=88ddfddb2c17d71db0180c1a5b335213bd2fd1d8a964b84c3b69dda1f949dfad -# pip jupyter-events @ https://files.pythonhosted.org/packages/a5/94/059180ea70a9a326e1815176b2370da56376da347a796f8c4f0b830208ef/jupyter_events-0.10.0-py3-none-any.whl#sha256=4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960 +# pip jupyterlite-pyodide-kernel @ https://files.pythonhosted.org/packages/3f/9e/ab31828d7d0c12bf4bb3f46c44d20cbff961ea2bdebd254354e066dc81c0/jupyterlite_pyodide_kernel-0.4.7-py3-none-any.whl#sha256=3e597f213921cad0439c04c554f57e4e626356ab337bd259a396fb1a9a88324b +# pip jupyter-events @ https://files.pythonhosted.org/packages/3f/8c/9b65cb2cd4ea32d885993d5542244641590530836802a2e8c7449a4c61c9/jupyter_events-0.11.0-py3-none-any.whl#sha256=36399b41ce1ca45fe8b8271067d6a140ffa54cec4028e95491c93b78a855cacf # pip nbformat @ https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl#sha256=3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b -# pip nbclient @ https://files.pythonhosted.org/packages/66/e8/00517a23d3eeaed0513e718fbc94aab26eaa1758f5690fc8578839791c79/nbclient-0.10.0-py3-none-any.whl#sha256=f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f -# pip nbconvert @ https://files.pythonhosted.org/packages/b8/bb/bb5b6a515d1584aa2fd89965b11db6632e4bdc69495a52374bcc36e56cfa/nbconvert-7.16.4-py3-none-any.whl#sha256=05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3 -# pip jupyter-server @ https://files.pythonhosted.org/packages/57/e1/085edea6187a127ca8ea053eb01f4e1792d778b4d192c74d32eb6730fed6/jupyter_server-2.14.2-py3-none-any.whl#sha256=47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd +# pip jupytext @ https://files.pythonhosted.org/packages/f4/02/27191f18564d4f2c0e543643aa94b54567de58f359cd6a3bed33adb723ac/jupytext-1.16.6-py3-none-any.whl#sha256=900132031f73fee15a1c9ebd862e05eb5f51e1ad6ab3a2c6fdd97ce2f9c913b4 +# pip nbclient @ https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl#sha256=4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d +# pip nbconvert @ https://files.pythonhosted.org/packages/8f/9e/2dcc9fe00cf55d95a8deae69384e9cea61816126e345754f6c75494d32ec/nbconvert-7.16.5-py3-none-any.whl#sha256=e12eac052d6fd03040af4166c563d76e7aeead2e9aadf5356db552a1784bd547 +# pip jupyter-server @ https://files.pythonhosted.org/packages/e2/a2/89eeaf0bb954a123a909859fa507fa86f96eb61b62dc30667b60dbd5fdaf/jupyter_server-2.15.0-py3-none-any.whl#sha256=872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3 # pip jupyterlab-server @ https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl#sha256=e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4 -# pip jupyterlite-sphinx @ https://files.pythonhosted.org/packages/f6/71/d7fa0b7d802f359539019dfe2ec9e4b0b11b14ce815748b5adc8d28bb283/jupyterlite_sphinx-0.16.5-py3-none-any.whl#sha256=9429bfd0310d18c3cd4273e342a7e67e5a07b6baf21b150c26a54fae1b2a0077 +# pip jupyterlite-sphinx @ https://files.pythonhosted.org/packages/ea/cd/b47668fdb492702e2373429c41eb7fa5b8379fb068901b3ff7328e3c4841/jupyterlite_sphinx-0.17.1-py3-none-any.whl#sha256=1e36fe2300175fe3afa9d4c46514764c98078000f96b2c726bf20b755c4061f2 diff --git a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock index ec206ad2138b2..e8c27ccd85378 100644 --- a/build_tools/circle/doc_min_dependencies_linux-64_conda.lock +++ b/build_tools/circle/doc_min_dependencies_linux-64_conda.lock @@ -3,49 +3,49 @@ # input_hash: 4fd19c6cc3ab292f8b0a9bd29e5d6cd82a9527f9584eb9ad03dec32454ef1840 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-3.10.0-he073ed8_18.conda#ad8527bf134a90e1c9ed35fa0b64318c -https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2024.2.2-ha957f24_16.conda#42b0d14354b5910a9f41e29289914f6b https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-5_cp39.conda#40363a30db350596b5f225d0d5a33328 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-13.3.0-h84ea5a7_101.conda#0ce69d40c142915ac9734bc6134e514a -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda#cc3573974587f12dda90d96e3e55a702 https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-13.3.0-h84ea5a7_101.conda#29b5a4ed4613fa81a07c21045e3f5bf6 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.3-h024ca30_0.conda#d36687dc90337917a84a96a45111ad59 -https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h4a8ded7_18.conda#0ea96f90a10838f58412aa84fdd9df09 -https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 +https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h0157908_18.conda#460eba7851277ec1fd80a1a24080787a +https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.43-h4bf12b8_2.conda#cf0c5521ac2a20dfa6c662a4009eeef6 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 https://conda.anaconda.org/conda-forge/linux-64/binutils-2.43-h4852527_2.conda#348619f90eee04901f4a70615efff35b https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.43-h4852527_2.conda#18aba879ddf1f8f28145ca6fcb873d8c https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-hb9d3cd8_1004.conda#24831329718daa6cbe35fcd071b778d4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2#d9c69a24ad678ffce24c6543a0176b00 +https://conda.anaconda.org/conda-forge/linux-64/blis-0.9.0-h4ab18f5_2.conda#6f77ba1352b69c4a6f8a6d20def30e4e https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda#418c6ca5929a611cbd69204907a83995 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-he02047a_3.conda#fcd2016d1d299f654f81021e27496818 https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6 https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda#5aeabe88534ea4169d4c49998f293d6c @@ -57,6 +57,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3 https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-he02047a_3.conda#efab66b82ec976930b96d62a976de8e7 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.conda#f1fd30127802683586f768875127a987 +https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.51-hbd13f7d_1.conda#168cc19c031482f83b23c4eebbb94e26 https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 @@ -65,24 +66,24 @@ https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2 https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-13.3.0-heb74ff8_1.conda#c4cb22f270f501f5c59a122dc2adf20a -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda#c7f302fd11eeb0987a6a5e1f3aed6a21 -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe https://conda.anaconda.org/conda-forge/linux-64/nspr-4.36-h5888daf_0.conda#de9cd5bca9e4918527b9b72b6e2e1409 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 https://conda.anaconda.org/conda-forge/linux-64/rav1e-0.6.6-he8a937b_2.conda#77d9955b4abddb811cb8ab1aa7d743e4 +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda#3b3e64af585eadfb52bb90b553db5edf https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.3.0-h5888daf_0.conda#355898d24394b2af353eb96358db9fdd https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h5888daf_2.conda#e0409515c467b87176b070bff5d9442e -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 -https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.2.2-h5888daf_0.conda#135fd3c66bccad3d2254f50f9809e86a +https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.2.3-h7955e40_0.conda#01cf93c645fa03d44ffe603f51f3d27f https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda#346722a0be40f6edc53f12640d301338 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 https://conda.anaconda.org/conda-forge/linux-64/charls-2.4.2-h59595ed_0.conda#4336bd67920dd504cd8c6761d6a99645 @@ -93,204 +94,198 @@ https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b1893 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda#5e97e271911b8b2001a8b71860c32faa https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-he8f35ee_3.conda#4fab9799da9571266d05ca5503330655 -https://conda.anaconda.org/conda-forge/linux-64/libcap-2.69-h0f662aa_0.conda#25cb5999faa414e5ccb2c1388f62d3d5 -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_blis.conda#6c34f4ac0b024d8346d13204dce0281d +https://conda.anaconda.org/conda-forge/linux-64/libcap-2.71-h39aace5_0.conda#dd19e4e3043f6948bd7454b946ee0983 +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 +https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-lib-1.11.0-hb9d3cd8_2.conda#e55712ff40a054134d51b89afca57dbc https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-he02047a_3.conda#9aba7960731e6b4547b3a52f812ed801 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.1.0-h00ab1b0_0.conda#88928158ccfe797eac29ef5e03f7d23d https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2#309dec04b70a3cc0f1e84a4013683bc0 https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2#c66fe2d123249af7651ebde8984c51c2 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 -https://conda.anaconda.org/conda-forge/linux-64/nss-3.106-hdf54f9c_0.conda#efe735c7dc47dddbb14b3433d11c6feb +https://conda.anaconda.org/conda-forge/linux-64/nss-3.107-hdf54f9c_0.conda#294b7009fe9010b35c25bb683f663bc3 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 -https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-hef167b5_0.conda#54fe76ab3d0189acaef95156874db7f9 +https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda#2c2fae981fd2afd00812c92ac47d023d https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f -https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.15.1-hc57e6cf_0.conda#5f84961d86d0ef78851cb34f9d5e31fe +https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.15.2-h3122c55_1.conda#2bc8d76acd818d7e79229f5157d5c156 https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/gcc-13.3.0-h9576a4e_1.conda#606924335b5bcdf90e9aed9a2f5d22ed -https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-13.3.0-hc28eda2_5.conda#ffbadbbc3345d9a315ba31c8a9188d4c +https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-13.3.0-hc28eda2_7.conda#ac23afbf5805389eb771e2ad3b476f75 https://conda.anaconda.org/conda-forge/linux-64/gfortran_impl_linux-64-13.3.0-h10434e7_1.conda#6709e113709b6ba67cc0f4b0de58ef7f https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hdbfa832_1.conda#806367e23a0a6ad21e51875b34c57d7e https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-he8f35ee_3.conda#1091193789bb830127ed067a9e01ac57 https://conda.anaconda.org/conda-forge/linux-64/libavif16-1.1.1-h1909e37_2.conda#21e468ed3786ebcb2124b123aa2484b7 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_blis.conda#a602fa2ca743dedd49a1fad3382eb244 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 -https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.0-hdb8da77_2.conda#9c4554fafc94db681543804037e65de2 -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 -https://conda.anaconda.org/conda-forge/linux-64/python-3.9.20-h13acc7a_1_cpython.conda#951cff166a5f170e27908811917165f8 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c +https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.1-hdb8da77_0.conda#32b23f3487beae7e81495fbc1099ae9e +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-8_h3b12eaf_netlib.conda#09c4b501eaefc9041f73b680a7a2e673 +https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-256.9-h0b6a36f_2.conda#135bbeb376345b6847c065115be4221a +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 +https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda#b4807744af026fdbe8c05131758fb4be https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda#def531a3ac77b7fb8c21d17bb5d0badb -https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b +https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda#f4e90937bbfc3a4a92539545a37bb448 https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py39hf88036b_2.conda#8ea5af6ac902f1a4429190970d9099ce https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-h9c3ff4c_0.tar.bz2#c1ac6229d0bfd14f8354ff9ad2a26cad https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.8.0-h2b85faf_1.conda#fa7b3bf2965b9d74a81a0702d9bb49ee -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.0-pyhd8ed1ab_0.conda#a374efa97290b8799046df7c5ca17164 -https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda#f3ad426304898027fc619827ff428eca -https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.0-pyhd8ed1ab_1.conda#c88ca2bb7099167912e3b26463fff079 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda#e83a31202d1c0a000fce3e9cf3825875 +https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda#f22f4d4970e09d68a10b922cbb0408d3 +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.0-pyhd8ed1ab_2.conda#1f76b7e2b3ab88def5aa2f158322c7e6 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 +https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.10-py39h3d6467e_0.conda#76b5d215fb735a6dc43010ffbe78040e https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda#e8cd5d629f65bdf0f3bb312cde14659e -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.10.0-pyhff2d567_0.conda#816dbc4679a64e4417cd1385d661bb31 +https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda#24c1ca34138ee57de72a943237cde4cc +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.12.0-pyhd8ed1ab_0.conda#e041ad4c43ab5e10c74587f95378ebc7 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-he02047a_3.conda#c7f243bbaea97cd6ea1edd693270100e https://conda.anaconda.org/conda-forge/linux-64/gfortran-13.3.0-h9576a4e_1.conda#5e5e3b592d5174eb49607a973c77825b -https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-13.3.0-hb919d3a_5.conda#67dbd742855cc95233eb04c43004a29a +https://conda.anaconda.org/conda-forge/linux-64/gfortran_linux-64-13.3.0-hb919d3a_7.conda#0b8e7413559c4c892a37c35de4559969 https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.82.2-h4833e2c_0.conda#12859f91830f58b1803e32846651c6f6 https://conda.anaconda.org/conda-forge/linux-64/gxx-13.3.0-h9576a4e_1.conda#209182ca6b20aeff62f442e843961d81 -https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_5.conda#81ddb2db98fbe3031aa7ebbbf8bb3ffd -https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2#914d6646c4dbb1fd3ff539830a12fd71 -https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2#9f765cbfab6870c8435b9eefecd7a1f4 -https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_0.conda#7ba2ede0e7c795ff95088daf0dc59753 +https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_7.conda#7c82ca9bda609b6f72f670e4219d3787 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyhd8ed1ab_1.conda#2aa5ff7fa34a81b9196532c84c10d865 +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_1.conda#566e75c90c1d0c8c459eb0ad9833dc7a +https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda#39a4f67be3286c86d696df570b1201b7 https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2#7de5386c8fea29e76b303f37dde4c352 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py39h74842e3_0.conda#1bf77976372ff6de02af7b75cf034ce5 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 -https://conda.anaconda.org/conda-forge/linux-64/libpq-16.4-h2d7952a_3.conda#50e2dddb3417a419cbc2388d0b1c06f7 +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-8_h3b12eaf_netlib.conda#4785c8d7af13c1d601b1a427e5f18ea9 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_0.conda#d38773fed557834d3211e019b7cf7c2f +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py39h9399b63_1.conda#7821f0938aa629b9f17efd98c300a487 https://conda.anaconda.org/conda-forge/noarch/networkx-3.2-pyhd8ed1ab_0.conda#cec8cc498664cc00a070676aa89e69a7 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_2.conda#18c6deb6f9602e32446398203c8f0e91 -https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.0-py39h8cd3c5a_0.conda#ef257b7ce1e1cb152639ced6bc653475 -https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda#844d9eb3b43095b031874477f7d70088 -https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda#b7f5c092b8f9800150d998a71b76d5a1 -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025 -https://conda.anaconda.org/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_0.conda#260009d03c9d5c0f111904d851f053dc +https://conda.anaconda.org/conda-forge/linux-64/numpy-1.19.5-py39hd249d9e_3.tar.bz2#0cf333996ebdeeba8d1c8c1c0ee9eff9 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda#fd5062942bfa1b0bd5e0d2a4397b099e +https://conda.anaconda.org/conda-forge/linux-64/psutil-6.1.1-py39h8cd3c5a_0.conda#287b29f8df0363b2a53a5a6e6ce4fa5c +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda#12c566707c80111f9799308d9e265aef +https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_1.conda#b38dc0206e2a530e5c2cf11dc086b31a +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac +https://conda.anaconda.org/conda-forge/noarch/pytz-2024.2-pyhd8ed1ab_1.conda#f26ec986456c30f6dff154b670ae140f https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py39h8cd3c5a_1.conda#76e82e62b7bda86a7fceb1f32585abad https://conda.anaconda.org/conda-forge/linux-64/setuptools-59.8.0-py39hf3d152e_1.tar.bz2#4252d0c211566a9f65149ba7f6e87aa4 -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2#4d22a9315e78c6827f806065957d566e https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda#3f144b2c34f8cb5a9abd9ed23a39c561 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda#da1d979339e2714c30a8e806a33ec087 -https://conda.anaconda.org/conda-forge/noarch/tenacity-9.0.0-pyhd8ed1ab_0.conda#42af51ad3b654ece73572628ad2882ae +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_1.conda#fa839b5ff59e192f411ccc7dae6588bb +https://conda.anaconda.org/conda-forge/noarch/tenacity-9.0.0-pyhd8ed1ab_1.conda#a09f66fe95a54a92172e56a4a97ba271 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_0.conda#34feccdd4177f2d3d53c73fc44fd9a37 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py39h8cd3c5a_1.conda#48d269953fcddbbcde078429d4b27afe -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_1.conda#40d0ed782a8aaa16ef248e68c06c168d +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py39h8cd3c5a_0.conda#ebfd05ae1501660e995a8b6bbe02a391 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda#d17f13df8b65464ca316cbc000a3cb64 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 -https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_0.conda#1bb1ef9806a9a20872434f58b3e7fc1a -https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_0.conda#6d4e9ecca8d88977147e109fc7053184 -https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda#332493000404d8411859539a5a630865 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 +https://conda.anaconda.org/conda-forge/noarch/accessible-pygments-0.0.5-pyhd8ed1ab_1.conda#74ac5069774cdbc53910ec4d631a3999 +https://conda.anaconda.org/conda-forge/noarch/babel-2.16.0-pyhd8ed1ab_1.conda#3e23f7db93ec14c80525257d8affac28 +https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_1.conda#d48f7e9fdec44baf6d1da416fe402b04 +https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-26_linux64_blis.conda#0498c83a4942dcb342d5416c2ff1048c https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py39h15c3d72_0.conda#7e61b8777f42e00b08ff059f9e8ebc44 https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.8.0-h1a2810e_1.conda#3bb4907086d7187bf01c8bec397ffa5e -https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.0-py39h8cd3c5a_1.conda#7a98e8be85fb0ce5531cac253ca95497 +https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.1-py39h8cd3c5a_0.conda#6a86bebd04e7ecd773208e774aa3a58d https://conda.anaconda.org/conda-forge/linux-64/fortran-compiler-1.8.0-h36df796_1.conda#6b57750841d53ade8d3b47eafe53dd9f https://conda.anaconda.org/conda-forge/linux-64/glib-2.82.2-h44428e9_0.conda#f19f985ab043e8843045410f3b99de8a -https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2#b748fbf7060927a6e82df7cb5ee8f097 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 -https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda#54198435fce4d64d8a89af22573012a8 -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 +https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_1.conda#825927dc7b0f287ef8d4d0011bb113b1 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 +https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2024.9.22-py39hac51188_2.conda#87d7ce1f90bf94f40584db14777f8765 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_1.conda#315607a3030ad5d5227e76e0733798ff +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_1.conda#15798fa69312d433af690c8c42b3fb36 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.5-pyhd8ed1ab_0.conda#2752a6ed44105bfb18c9bef1177d9dcd +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda#ee48bf17cc83a00f59ca1494d5646869 -https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.50-h4f305b6_0.conda#0d7ff1a8e69565ca3add6925e18e708f -https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_0.tar.bz2#8b45f9f2b2f7a98b0ec179c8991a4a9b -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa +https://conda.anaconda.org/conda-forge/noarch/memory_profiler-0.61.0-pyhd8ed1ab_1.conda#71abbefb6f3b95e1668cd5e0af3affb9 +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py39h538c539_0.conda#a2bafdf8ae51c9eb6e5be684cfcedd60 -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 +https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda#ee23fabfd0a8c6b8d6f3729b47b2859d +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py39h15c0740_0.conda#d6e7eee1f21bce11ae03f40a77c699fe +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f https://conda.anaconda.org/conda-forge/noarch/plotly-5.14.0-pyhd8ed1ab_0.conda#6a7bcc42ef58dd6cf3da9333ea102433 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c +https://conda.anaconda.org/conda-forge/linux-64/polars-0.20.30-py39ha963410_0.conda#322084e8890afc27fcca6df7a528df25 +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e +https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py39hd92a3bb_0.conda#32e26e16f60c568b17a82e3033a4d309 +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.6.0-py39hee8e79c_0.tar.bz2#3afcb78281836e61351a2924f3230060 https://conda.anaconda.org/conda-forge/linux-64/sip-6.7.12-py39h3d6467e_0.conda#e667a3ab0df62c54e60e1843d2e6defb -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.126-blis.conda#166a502cf42652611beef4b9dc50fe27 https://conda.anaconda.org/conda-forge/linux-64/compilers-1.8.0-ha770c72_1.conda#061e111d02f33a99548f0de07169d9fb https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.24.7-hf3bb09a_0.conda#c78bc4ef0afb3cd2365d9973c71fc876 -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_0.conda#67f4772681cf86652f3e2261794cf045 -https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda#2a92e152208121afadf85a5e1f3a5f4d -https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.11.0-h4ab18f5_1.conda#14858a47d4cc995892e79f2b340682d7 +https://conda.anaconda.org/conda-forge/noarch/imageio-2.36.1-pyh12aca89_1.conda#84d5a2f075c861a8f98afd2842f7eb6e +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_1.conda#59561d9b70f9df3b884c29910eba6593 +https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_1.conda#c70dd0718dbccdcc6d5828de3e71399d +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda#ef1910918dd895516a769ed36b5b3a4e -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/linux-64/mkl-2024.2.2-ha957f24_16.conda#1459379c79dda834673426504d52b319 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.3.4-py39h2fa2bec_0.tar.bz2#9ec0b2186fab9121c54f4844f93ee5b7 +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/linux-64/pandas-1.1.5-py39hde0f152_0.tar.bz2#79fc4b5b3a865b90dd3701cecf1ad33c +https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39hac2352c_1.tar.bz2#6fb0628d6195d8b6caa2422d09296399 https://conda.anaconda.org/conda-forge/linux-64/pyqt5-sip-12.12.2-py39h3d6467e_5.conda#93aff412f3e49fdb43361c0215cbd72d -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd +https://conda.anaconda.org/conda-forge/noarch/tifffile-2024.6.18-pyhd8ed1ab_0.conda#7c3077529bfe3b86f9425d526d73bd24 https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py39h08a7858_1.conda#cd9fa334e11886738f17254f52210bc3 https://conda.anaconda.org/conda-forge/noarch/dask-core-2024.8.0-pyhd8ed1ab_0.conda#bf68bf9ff9a18f1b17aa8c817225aee0 https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.24.7-h0a52356_0.conda#d368425fbd031a2f8e801a40c3415c72 -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-25_linux64_mkl.conda#b77ebfb548eae4d91639e2ca003662c8 -https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-256.7-h2774228_1.conda#ad328c530a12a8798776e5f03942090f -https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2024.2.2-ha770c72_16.conda#140891ea14285fc634353b31e9e40a95 -https://conda.anaconda.org/conda-forge/noarch/towncrier-24.8.0-pyhd8ed1ab_0.conda#02190423152df62fda1cde3d9527b882 -https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.3-pyhd8ed1ab_0.conda#6b55867f385dd762ed99ea687af32a69 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-25_linux64_mkl.conda#e48aeb4ab1a293f621fe995959f1d32f -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-25_linux64_mkl.conda#d5afbe3777c594434e4de6481254e99c https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-17.0-hb77b528_0.conda#07f45f1be1c25345faddb8db0de8039b -https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_0.conda#5ede4753180c7a550a443c430dc8ab52 -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-25_linux64_mkl.conda#cbddb4169d3d24b13b308403b45f401e -https://conda.anaconda.org/conda-forge/linux-64/numpy-1.19.5-py39hd249d9e_3.tar.bz2#0cf333996ebdeeba8d1c8c1c0ee9eff9 -https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 -https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-h374914d_0.conda#26e8b00e73c114c9b787d36edcbf4424 -https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-25_linux64_mkl.conda#cb60caae3cb30988431d7107691bd587 -https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2024.9.22-py39h1aa77c4_0.conda#6001ae3f85403137d61e3ef7e96dd940 -https://conda.anaconda.org/conda-forge/noarch/imageio-2.36.0-pyh12aca89_1.conda#36349844ff73fcd0140ee7f30745f0bf -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.3.4-py39h2fa2bec_0.tar.bz2#9ec0b2186fab9121c54f4844f93ee5b7 -https://conda.anaconda.org/conda-forge/linux-64/pandas-1.1.5-py39hde0f152_0.tar.bz2#79fc4b5b3a865b90dd3701cecf1ad33c -https://conda.anaconda.org/conda-forge/noarch/patsy-0.5.6-pyhd8ed1ab_0.conda#a5b55d1cb110cdcedc748b5c3e16e687 -https://conda.anaconda.org/conda-forge/linux-64/polars-0.20.30-py39ha963410_0.conda#322084e8890afc27fcca6df7a528df25 -https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.9-py39h52134e7_5.conda#e1f148e57d071b09187719df86f513c1 -https://conda.anaconda.org/conda-forge/linux-64/pywavelets-1.6.0-py39hd92a3bb_0.conda#32e26e16f60c568b17a82e3033a4d309 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.6.0-py39hee8e79c_0.tar.bz2#3afcb78281836e61351a2924f3230060 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.125-mkl.conda#8a0ffaaae2bccf691cffdde83cb0f1a5 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.3.4-py39hf3d152e_0.tar.bz2#cbaec993375a908bbe506dc7328d747c -https://conda.anaconda.org/conda-forge/linux-64/pyamg-4.2.3-py39hac2352c_1.tar.bz2#6fb0628d6195d8b6caa2422d09296399 https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.12.2-pyhd8ed1ab_0.conda#cf88f3a1c11536bc3c10c14ad00ccc42 https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.13.2-py39hd257fcd_0.tar.bz2#bd7cdadf70e34a19333c3aacc40206e8 -https://conda.anaconda.org/conda-forge/noarch/tifffile-2024.6.18-pyhd8ed1ab_0.conda#7c3077529bfe3b86f9425d526d73bd24 +https://conda.anaconda.org/conda-forge/noarch/towncrier-24.8.0-pyhd8ed1ab_1.conda#820b6a1ddf590fba253f8204f7200d82 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda#32674f8dbfb7b26410ed580dd3c10a29 +https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.15-hc3cb62f_2.conda#eadc22e45a87c8d5c71670d9ec956aba +https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda#a9b9368f3701a417eac9edbcae7cb737 https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.17.2-py39hde0f152_4.tar.bz2#2a58a7e382317b03f023b2fddf40f8a1 https://conda.anaconda.org/conda-forge/noarch/seaborn-0.12.2-hd8ed1ab_0.conda#50847a47c07812f88581081c620f5160 +https://conda.anaconda.org/conda-forge/noarch/pooch-1.6.0-pyhd8ed1ab_0.tar.bz2#6429e1d1091c51f626b5dcfdd38bf429 +https://conda.anaconda.org/conda-forge/linux-64/pyqt-5.15.9-py39h52134e7_5.conda#e1f148e57d071b09187719df86f513c1 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.3.4-py39hf3d152e_0.tar.bz2#cbaec993375a908bbe506dc7328d747c https://conda.anaconda.org/conda-forge/noarch/numpydoc-1.2-pyhd8ed1ab_0.tar.bz2#025ad7ca2c7f65007ab6b6f5d93a56eb https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.15.3-pyhd8ed1ab_0.conda#55e445f4fcb07f2471fb0e1102d36488 -https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda#ac832cc43adc79118cf6e23f1f9b8995 +https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_1.conda#bf22cb9c439572760316ce0748af3713 https://conda.anaconda.org/conda-forge/noarch/sphinx-design-0.6.0-pyhd8ed1ab_0.conda#b04f3c04e4f7939c6207dc0c0355f468 https://conda.anaconda.org/conda-forge/noarch/sphinx-gallery-0.17.1-pyhd8ed1ab_0.conda#0adfccc6e7269a29a63c1c8ee3c6d8ba https://conda.anaconda.org/conda-forge/noarch/sphinx-prompt-1.4.0-pyhd8ed1ab_0.tar.bz2#88ee91e8679603f2a5bd036d52919cc2 https://conda.anaconda.org/conda-forge/noarch/sphinx-remove-toctrees-1.0.0.post1-pyhd8ed1ab_0.conda#6dee8412218288a17f99f2cfffab334d -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_0.conda#9075bd8c033f0257122300db914e49c9 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_0.conda#b3bcc38c471ebb738854f52a36059b48 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_0.conda#e25640d692c02e8acfff0372f547e940 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_0.conda#d6e5ea5fe00164ac6c2dcc5d76a42192 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-2.0.0-pyhd8ed1ab_1.conda#16e3f039c0aa6446513e94ab18a8784b +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-2.0.0-pyhd8ed1ab_1.conda#910f28a05c178feba832f842155cbfff +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.1.0-pyhd8ed1ab_1.conda#e9fb3fe8a5b758b4aff187d434f94f03 +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-2.0.0-pyhd8ed1ab_1.conda#00534ebcc0375929b45c3039b5ba7636 https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda#7b1465205e28d75d2c0e1a868ee00a67 -https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda#e507335cb4ca9cff4c3d0fa9cdab255e +https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_1.conda#3bc61f7161d28137797e038263c04c54 # pip libsass @ https://files.pythonhosted.org/packages/fd/5a/eb5b62641df0459a3291fc206cf5bd669c0feed7814dded8edef4ade8512/libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl#sha256=4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306 # pip sphinxcontrib-sass @ https://files.pythonhosted.org/packages/2e/87/7c2eb08e3ca1d6baae32c0a5e005330fe1cec93a36aa085e714c3b3a3c7d/sphinxcontrib_sass-0.3.4-py2.py3-none-any.whl#sha256=a0c79a44ae8b8935c02dc340ebe40c9e002c839331201c899dc93708970c355a # pip sphinxext-opengraph @ https://files.pythonhosted.org/packages/92/0a/970b80b4fa1feeb6deb6f2e22d4cb14e388b27b315a1afdb9db930ff91a4/sphinxext_opengraph-0.9.1-py3-none-any.whl#sha256=b3b230cc6a5b5189139df937f0d9c7b23c7c204493b22646273687969dcb760e diff --git a/build_tools/cirrus/pymin_conda_forge_linux-aarch64_conda.lock b/build_tools/cirrus/pymin_conda_forge_linux-aarch64_conda.lock index 9b2b12078f0a5..0997b149849e3 100644 --- a/build_tools/cirrus/pymin_conda_forge_linux-aarch64_conda.lock +++ b/build_tools/cirrus/pymin_conda_forge_linux-aarch64_conda.lock @@ -2,38 +2,39 @@ # platform: linux-aarch64 # input_hash: 2d8c526ab7c0c2f0ca509bfec3f035e5bd33b8096f194f0747f167c8aff66383 @EXPLICIT -https://conda.anaconda.org/conda-forge/linux-aarch64/ca-certificates-2024.8.30-hcefe29a_0.conda#70e57e8f59d2c98f86b49c69e5074be5 +https://conda.anaconda.org/conda-forge/linux-aarch64/ca-certificates-2024.12.14-hcefe29a_0.conda#83b4ad1e6dc14df5891f3fcfdeb44351 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.43-h80caac9_2.conda#fcbde5ea19d55468953bf588770c0501 -https://conda.anaconda.org/conda-forge/linux-aarch64/libglvnd-1.7.0-hd24410f_1.conda#32763e24bc6e5ed4de4a4a1598448d5b -https://conda.anaconda.org/conda-forge/linux-aarch64/llvm-openmp-19.1.3-h013ceaa_0.conda#41689b81ad3f991ac539fd00b37af432 +https://conda.anaconda.org/conda-forge/linux-aarch64/libglvnd-1.7.0-hd24410f_2.conda#9e115653741810778c9a915a2f8439e7 +https://conda.anaconda.org/conda-forge/linux-aarch64/llvm-openmp-19.1.6-h013ceaa_0.conda#8d79254b1ef223cc37202f09508078d8 https://conda.anaconda.org/conda-forge/linux-aarch64/python_abi-3.9-5_cp39.conda#2d2843f11ec622f556137d72d9c72d89 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#98a1185182fec3c434069fa74e6473d6 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 -https://conda.anaconda.org/conda-forge/linux-aarch64/libegl-1.7.0-hd24410f_1.conda#f82d2736a04324c05bdce1c39a57fee6 -https://conda.anaconda.org/conda-forge/linux-aarch64/libopengl-1.7.0-hd24410f_1.conda#9e50e575daf28ab2f1a6d8f6da3027d3 +https://conda.anaconda.org/conda-forge/linux-aarch64/libegl-1.7.0-hd24410f_2.conda#cf105bce884e4ef8c8ccdca9fe6695e7 +https://conda.anaconda.org/conda-forge/linux-aarch64/libopengl-1.7.0-hd24410f_2.conda#cf9d12bfab305e48d095a4c79002c922 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-14.2.0-he277a41_1.conda#511b511c5445e324066c3377481bcab8 +https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.13-h86ecc28_0.conda#f643bb02c4bbcfe7de161a8ca5df530b https://conda.anaconda.org/conda-forge/linux-aarch64/libbrotlicommon-1.1.0-h86ecc28_2.conda#3ee026955c688f551a9999840cff4c67 -https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.22-h86ecc28_0.conda#ff6a44e8b1707d02be2fe9a36ea88d4a -https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.6.3-h5ad3122_0.conda#1d2b842bb76e268625e8ee8d0a9fe8c3 +https://conda.anaconda.org/conda-forge/linux-aarch64/libdeflate-1.23-h5e3c512_0.conda#7e7ca2607b11b180120cefc2354fc0cb +https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.6.4-h5ad3122_0.conda#f1b3fab36861b3ce945a13f0dfdfc688 https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-14.2.0-he9431aa_1.conda#0694c249c61469f2c0f7e2990782af21 https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-14.2.0-hb6113d0_1.conda#fc068e11b10e18f184e027782baa12b6 +https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.6.3-h86ecc28_1.conda#eb08b903681f9f2432c320e8ed626723 https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-14.2.0-h3f4de04_1.conda#37f489acd39e22b623d2d1e5ac6d195c +https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.5.0-h0886dbf_0.conda#95ef4a689b8cc1b7e18b53784d88f96b https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda#08aad7cbe9f5a6b460d0976076b6ae64 -https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.3.2-h86ecc28_0.conda#9e1e477b3f8ee3789297883faffa708b +https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.4.0-hd08dc88_1.conda#e21c4767e783a58c373fdb99de6211bf https://conda.anaconda.org/conda-forge/linux-aarch64/pthread-stubs-0.4-h86ecc28_1002.conda#bb5a90c93e3bac3d5690acf76b4a6386 -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libice-1.1.1-h57736b2_1.conda#99a9c8245a1cc6dacd292ffeca39425f -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.11-h86ecc28_1.conda#c5f72a733c461aa7785518d29b997cc8 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libice-1.1.2-h86ecc28_0.conda#c8d8ec3e00cd0fd8a231789b91a7c5b7 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxau-1.0.12-h86ecc28_0.conda#d5397424399a66d33c80b1f2345a36a6 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdmcp-1.1.5-h57736b2_0.conda#25a5a7b797fe6e084e04ffe2db02fc62 -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-xorgproto-2024.1-h86ecc28_1.conda#91cef7867bf2b47f614597b59705ff56 -https://conda.anaconda.org/conda-forge/linux-aarch64/alsa-lib-1.2.12-h68df207_0.conda#65448d015f05afb3c68ea92d0483a466 https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h68df207_7.conda#56398c28220513b9ea13d7b450acfb20 -https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.6.3-h5ad3122_0.conda#901a44b341632b0c233756ed5abcd78b +https://conda.anaconda.org/conda-forge/linux-aarch64/expat-2.6.4-h5ad3122_0.conda#e8f1d587055376ea2419cc78696abd0b https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.1-h4e544f5_0.tar.bz2#1f24853e59c68892452ef94ddd8afd4b https://conda.anaconda.org/conda-forge/linux-aarch64/libbrotlidec-1.1.0-h86ecc28_2.conda#e64d0f3b59c7c4047446b97a8624a72d https://conda.anaconda.org/conda-forge/linux-aarch64/libbrotlienc-1.1.0-h86ecc28_2.conda#0e9bd365480c72b25c71a448257b537d @@ -45,29 +46,27 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h31becfc_0.con https://conda.anaconda.org/conda-forge/linux-aarch64/libntlm-1.4-hf897c2e_1002.tar.bz2#835c7c4137821de5c309f4266a51ba89 https://conda.anaconda.org/conda-forge/linux-aarch64/libpciaccess-0.18-h31becfc_0.conda#6d48179630f00e8c9ad9e30879ce1e54 https://conda.anaconda.org/conda-forge/linux-aarch64/libpng-1.6.44-hc4a20ef_0.conda#5d25802b25fcc7419fa13e21affaeb3a -https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.47.0-hc4a20ef_1.conda#a6b185aac10d08028340858f77231b23 +https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.47.2-h5eb1b54_0.conda#d4bf59f8783a4a66c0aec568f6de3ff4 https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-14.2.0-hf1166c9_1.conda#0e75771b8a03afae5a2c6ce71bc733f5 https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.38.1-hb4cce97_0.conda#000e30b09db0b7c775b21695dff30969 -https://conda.anaconda.org/conda-forge/linux-aarch64/libwebp-base-1.4.0-h31becfc_0.conda#5fd7ab3e5f382c70607fbac6335e6e19 https://conda.anaconda.org/conda-forge/linux-aarch64/libxcb-1.17.0-h262b8f6_0.conda#cd14ee5cca2464a425b1dbfc24d90db2 https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda#b4df5d7d4b63579d081fd3a4cf99740e -https://conda.anaconda.org/conda-forge/linux-aarch64/mysql-common-9.0.1-h3f5c77f_2.conda#cc7bc11893dd1aee492dae85f317769e +https://conda.anaconda.org/conda-forge/linux-aarch64/mysql-common-9.0.1-h3f5c77f_4.conda#252699a6b6e8e86d64d37c360ac8d783 https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-hcccb83c_1.conda#91d49c85cacd92caa40cf375ef72a25d +https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.44.2-h86a87f0_0.conda#95689fc369832398e82d17c56ff5df8a https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-h194ca79_0.conda#f75105e0585851f818e0009dd1dde4dc -https://conda.anaconda.org/conda-forge/linux-aarch64/xz-5.2.6-h9cdd2b7_0.tar.bz2#83baad393a31d59c20b63ba4da6592df -https://conda.anaconda.org/conda-forge/linux-aarch64/zlib-1.3.1-h86ecc28_2.conda#bc230abb5d21b63ff4799b0e75204783 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-bin-1.1.0-h86ecc28_2.conda#7d48b185fe1f722f8cda4539bb931f85 https://conda.anaconda.org/conda-forge/linux-aarch64/double-conversion-3.3.0-h2f0025b_0.conda#3b34b29f68d60abc1ce132b87f5a213c https://conda.anaconda.org/conda-forge/linux-aarch64/freetype-2.12.1-hf0a5ef3_2.conda#a5ab74c5bd158c3d5532b66d8d83d907 https://conda.anaconda.org/conda-forge/linux-aarch64/graphite2-1.3.13-h2f0025b_1003.conda#f33009add6a08358bc12d114ceec1304 https://conda.anaconda.org/conda-forge/linux-aarch64/icu-75.1-hf9b3779_0.conda#268203e8b983fddb6412b36f2024e75c https://conda.anaconda.org/conda-forge/linux-aarch64/lerc-4.0.0-h4de3ea5_0.tar.bz2#1a0ffc65e03ce81559dbcb0695ad1476 -https://conda.anaconda.org/conda-forge/linux-aarch64/libdrm-2.4.123-h86ecc28_0.conda#4e3c67f6999ea7ccac41611f930d19d4 +https://conda.anaconda.org/conda-forge/linux-aarch64/libdrm-2.4.124-h86ecc28_0.conda#a8058bcb6b4fa195aaa20452437c7727 https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#29371161d77933a54fccf1bb66b96529 https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-ng-14.2.0-he9431aa_1.conda#5e90005d310d69708ba0aa7f4fed1de6 +https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.28-pthreads_h9d3fd7e_1.conda#e8dde93dd199da3c1f2c1fcfd0042cd4 https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.12.1-h70be974_0.conda#216635cea46498d8045c7cf0f03eaf72 https://conda.anaconda.org/conda-forge/linux-aarch64/pcre2-10.44-h070dd5b_2.conda#94022de9682cb1a0bb18a99cbc3541b3 -https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.43.4-h2f0025b_0.conda#81b2ddea4b0eca188da9c5a7aa4b0cff https://conda.anaconda.org/conda-forge/linux-aarch64/qhull-2020.2-h70be974_5.conda#bb138086d938e2b64f5f364945793ebf https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.2-h8fc344f_1.conda#105eb1e16bf83bfb2eb380a48032b655 https://conda.anaconda.org/conda-forge/linux-aarch64/wayland-1.23.1-h698ed42_0.conda#2661f9252065051914f1cdf5835e7430 @@ -75,92 +74,91 @@ https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-0.4.1-h5c728e9_2.c https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-keysyms-0.4.1-h5c728e9_0.conda#57ca8564599ddf8b633c4ea6afee6f3a https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-renderutil-0.3.10-h5c728e9_0.conda#7beeda4223c5484ef72d89fb66b7e8c1 https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-wm-0.4.2-h5c728e9_0.conda#f14dcda6894722e421da2b7dcffb0b78 -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libsm-1.2.4-hbac51e1_1.conda#18655ac9fc6624db89b33a89fed51c5f -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libx11-1.8.9-he755bbd_2.conda#7acc45f80415e6ec352b729105dc0375 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libsm-1.2.5-h0808dbd_0.conda#3983c253f53f67a9d8710fc96646950f +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libx11-1.8.10-hca56bd8_1.conda#6e3e980940b26a060e553266ae0181a9 https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.6-h02f22dd_0.conda#be8d5f8cf21aed237b8b182ea86b3dd6 https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-1.1.0-h86ecc28_2.conda#5094acc34eb173f74205c0b55f0dd4a4 https://conda.anaconda.org/conda-forge/linux-aarch64/fontconfig-2.15.0-h8dda3cd_1.conda#112b71b6af28b47c624bcbeefeea685b https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.21.3-h50a48e9_0.conda#29c10432a2ca1472b53f299ffb2ffa37 +https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.9.0-26_linuxaarch64_openblas.conda#8d900b7079a00969d70305e9aad550b7 https://conda.anaconda.org/conda-forge/linux-aarch64/libglib-2.82.2-hc486b8e_0.conda#47f6d85fe47b865e56c539f2ba5f4dad -https://conda.anaconda.org/conda-forge/linux-aarch64/libglx-1.7.0-hd24410f_1.conda#b4e4c7703e944564b512dabbcc1130d0 +https://conda.anaconda.org/conda-forge/linux-aarch64/libglx-1.7.0-hd24410f_2.conda#1d4269e233636148696a67e2d30dad2a https://conda.anaconda.org/conda-forge/linux-aarch64/libhiredis-1.0.2-h05efe27_0.tar.bz2#a87f068744fd20334cd41489eb163bee -https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.28-pthreads_h9d3fd7e_0.conda#554edd2031035f21b042fdbc74429774 -https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.0-hec21d91_1.conda#1f80061f5ba6956fcdc381f34618cd8d -https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.4-hf4efe5d_2.conda#0e28ab30d29c5a566d05bf73dfc5c184 -https://conda.anaconda.org/conda-forge/linux-aarch64/mysql-libs-9.0.1-h11569fd_2.conda#94c70f21e0a1f8558941d901027215a4 -https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.9.20-h4a649e4_1_cpython.conda#c2833e3d5a6d210ffb433cbd4a1cf174 +https://conda.anaconda.org/conda-forge/linux-aarch64/libtiff-4.7.0-h88f7998_3.conda#36a0ea4a173338c8725dc0807e99cf22 +https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.13.5-h2e0c361_1.conda#63410f85031930cde371dfe0ee89109a +https://conda.anaconda.org/conda-forge/linux-aarch64/mysql-libs-9.0.1-h11569fd_4.conda#283642d922c40633996f0f1afb5c9993 +https://conda.anaconda.org/conda-forge/linux-aarch64/openblas-0.3.28-pthreads_h3a8cbd8_1.conda#d36b4f01d28df4f90c7e37adb8e9adb5 +https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.9.21-hb97c71e_1_cpython.conda#49094665d26eac2d8a199169cf0989db https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-image-0.4.0-h5c728e9_2.conda#b82e5c78dbbfa931980e8bfe83bce913 https://conda.anaconda.org/conda-forge/linux-aarch64/xkeyboard-config-2.43-h86ecc28_0.conda#a809b8e3776fbc05696c82f8cf6f5a92 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxext-1.3.6-h57736b2_0.conda#bd1e86dd8aa3afd78a4bfdb4ef918165 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxfixes-6.0.1-h57736b2_0.conda#78f8715c002cc66991d7c11e3cf66039 -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrender-0.9.11-h57736b2_1.conda#19fb476dc5cdd51b67719a6342fab237 -https://conda.anaconda.org/conda-forge/linux-aarch64/cairo-1.18.0-hdb1a16f_3.conda#080659f02bf2202c57f1cda4f9e51f21 +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrender-0.9.12-h86ecc28_0.conda#ae2c2dd0e2d38d249887727db2af960e +https://conda.anaconda.org/conda-forge/linux-aarch64/cairo-1.18.2-h83712da_1.conda#e7b46975d2c9a4666da0e9bb8a087f28 https://conda.anaconda.org/conda-forge/linux-aarch64/ccache-4.10.1-ha3bccff_0.conda#7cd24a038d2727b5e6377975237a6cfa -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/certifi-2024.12.14-pyhd8ed1ab_0.conda#6feb87357ecd66733be3279f16a8c400 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-aarch64/cyrus-sasl-2.1.27-hf6b2984_7.conda#7a85d417c8acd7a5215c082c5b9219e5 https://conda.anaconda.org/conda-forge/linux-aarch64/cython-3.0.11-py39h3e5e1bb_3.conda#9cbb30d5775193a8766a276d8fb52bc7 https://conda.anaconda.org/conda-forge/linux-aarch64/dbus-1.13.6-h12b9eeb_3.tar.bz2#f3d63805602166bac09386741e00935e -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-aarch64/kiwisolver-1.4.7-py39h78c8b8d_0.conda#8dc5516dd121089f14c1a557ecec3224 https://conda.anaconda.org/conda-forge/linux-aarch64/lcms2-2.16-h922389a_0.conda#ffdd8267a04c515e7ce69c727b051414 -https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.9.0-25_linuxaarch64_openblas.conda#f9b8a4a955ed2d0b68b1f453abcc1c9e +https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.9.0-26_linuxaarch64_openblas.conda#d77f943ae4083f3aeddca698f2d28262 https://conda.anaconda.org/conda-forge/linux-aarch64/libcups-2.3.3-h405e4a8_4.conda#d42c670b0c96c1795fd859d5e0275a55 -https://conda.anaconda.org/conda-forge/linux-aarch64/libgl-1.7.0-hd24410f_1.conda#06cf88e73c69957c56318c6a1ccc5306 -https://conda.anaconda.org/conda-forge/linux-aarch64/libllvm19-19.1.3-h2edbd07_0.conda#4f335bb2183b2a9a062518cbc079dc8b +https://conda.anaconda.org/conda-forge/linux-aarch64/libgl-1.7.0-hd24410f_2.conda#0d00176464ebb25af83d40736a2cd3bb +https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.9.0-26_linuxaarch64_openblas.conda#a5d4e18876393633da62fd8492c00156 +https://conda.anaconda.org/conda-forge/linux-aarch64/libllvm19-19.1.6-h2edbd07_0.conda#9e755607ec3a05f5ca9eba87abc76d65 https://conda.anaconda.org/conda-forge/linux-aarch64/libxkbcommon-1.7.0-h46f2afe_1.conda#78a24e611ab9c09c518f519be49c2e46 https://conda.anaconda.org/conda-forge/linux-aarch64/libxslt-1.1.39-h1cc9640_0.conda#13e1d3f9188e85c6d59a98651aced002 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/linux-aarch64/openblas-0.3.28-pthreads_h395f137_0.conda#ee90d0aeb560772351c2bb5628dea2fd -https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.2-h0d9d63b_0.conda#fd2898519e839d5ceb778343f39a3176 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/linux-aarch64/openjpeg-2.5.3-h3f56577_0.conda#04231368e4af50d11184b50e14250993 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-aarch64/tornado-6.4.1-py39h3e3acee_1.conda#a4d4b0a58bf2fadfa1285f4710b72f99 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-aarch64/tornado-6.4.2-py39h3e3acee_0.conda#fdf7a3dc0d7e6ca4cc792f1731d282c4 https://conda.anaconda.org/conda-forge/linux-aarch64/unicodedata2-15.1.0-py39h060674a_1.conda#22a119d3f80e6d91b28fbc49a3cc08b2 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-aarch64/xcb-util-cursor-0.1.5-h86ecc28_0.conda#d6bb2038d26fa118d5cbc2761116f3e5 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxcomposite-0.4.6-h86ecc28_2.conda#86051eee0766c3542be24844a9c3cf36 -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxcursor-1.2.2-h86ecc28_0.conda#d4e9a277c7bdba9464a52712d788226a +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxcursor-1.2.3-h86ecc28_0.conda#f2054759c2203d12d0007005e1f1296d https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxdamage-1.1.6-h86ecc28_0.conda#d5773c4e4d64428d7ddaa01f6f845dc7 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxi-1.8.2-h57736b2_0.conda#eeee3bdb31c6acde2b81ad1b8c287087 https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxrandr-1.5.4-h86ecc28_0.conda#dd3e74283a082381aa3860312e3c721e -https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxxf86vm-1.1.5-h57736b2_4.conda#82fa1f5642ef7ac7172e295327ce20e2 -https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda#4daaed111c05672ae669f7036ee5bba3 -https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.54.1-py39hbebea31_1.conda#48e4d4179d70359d8d1fa6716467ef62 -https://conda.anaconda.org/conda-forge/linux-aarch64/harfbuzz-9.0.0-hbf49d6b_1.conda#ceb458f664cab8550fcd74fff26451db -https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_0.conda#c808991d29b9838fb4d96ce8267ec9ec -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.9.0-25_linuxaarch64_openblas.conda#db6af51123c67814572a8c25542cb368 -https://conda.anaconda.org/conda-forge/linux-aarch64/libclang-cpp19.1-19.1.3-default_he324ac1_0.conda#9ac4956d6676bdb251279d8c27406954 -https://conda.anaconda.org/conda-forge/linux-aarch64/libclang13-19.1.3-default_h4390ef5_0.conda#d23cae404c2763d07fee33a9299f2d63 -https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.9.0-25_linuxaarch64_openblas.conda#0eb74e81de46454960bde9e44e7ee378 -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-aarch64/openldap-2.6.8-h50f9a67_0.conda#6f6627099ae614fe176e162e6eeae240 -https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-11.0.0-py39hb20fde8_0.conda#78cdfe29a452feee8c5bd689c2c871bd -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c +https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxxf86vm-1.1.6-h86ecc28_0.conda#d745faa2d7c15092652e40a22bb261ed +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 +https://conda.anaconda.org/conda-forge/linux-aarch64/fonttools-4.55.3-py39hbebea31_1.conda#8f6cca97167821f34fc339f18f0acea8 +https://conda.anaconda.org/conda-forge/linux-aarch64/harfbuzz-10.1.0-hbdc1db7_0.conda#881e8d9b31e1a7335d4dea4d66851bc0 +https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.5-pyhd8ed1ab_1.conda#15798fa69312d433af690c8c42b3fb36 +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-aarch64/libclang-cpp19.1-19.1.6-default_he324ac1_0.conda#2f399a5612317660f5c98f6cb634829b +https://conda.anaconda.org/conda-forge/linux-aarch64/libclang13-19.1.6-default_h4390ef5_0.conda#b3aa0944c1ae4277c0b2d23dfadc13da +https://conda.anaconda.org/conda-forge/linux-aarch64/liblapacke-3.9.0-26_linuxaarch64_openblas.conda#a5250ad700e86a8764947dc850abe973 +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.0.2-py39h4a34e27_1.conda#fe586ddf9512644add97b0526129ed95 +https://conda.anaconda.org/conda-forge/linux-aarch64/openldap-2.6.9-h30c48ee_0.conda#c07822a5de65ce9797b9afa257faa917 +https://conda.anaconda.org/conda-forge/linux-aarch64/pillow-11.1.0-py39h301a0e3_0.conda#22c413e9649bfe2a9af6cbe8c82077d3 +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e https://conda.anaconda.org/conda-forge/linux-aarch64/xorg-libxtst-1.2.5-h57736b2_3.conda#c05698071b5c8e0da82a282085845860 -https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_0.conda#67f4772681cf86652f3e2261794cf045 -https://conda.anaconda.org/conda-forge/linux-aarch64/liblapacke-3.9.0-25_linuxaarch64_openblas.conda#1e68063075954830f707b41dab6c7fd8 -https://conda.anaconda.org/conda-forge/linux-aarch64/libpq-17.0-h081282e_4.conda#4627c6a062463cf4191aafca4d6c748c -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.0.2-py39h4a34e27_0.conda#4d6edcc002364ced01e4fc947832eee6 -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 -https://conda.anaconda.org/conda-forge/linux-aarch64/blas-devel-3.9.0-25_linuxaarch64_openblas.conda#32539a9b9e09140a83e987edf3c09926 +https://conda.anaconda.org/conda-forge/linux-aarch64/blas-devel-3.9.0-26_linuxaarch64_openblas.conda#d955d2b75f044b9d1bd4ef83f0d840e7 https://conda.anaconda.org/conda-forge/linux-aarch64/contourpy-1.3.0-py39hbd2ca3f_2.conda#57fa6811a7a80c5641e373408389bc5a -https://conda.anaconda.org/conda-forge/linux-aarch64/qt6-main-6.8.0-h666f7c6_0.conda#1c50a44d681075eff85d0332624c927e +https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.4.5-pyhd8ed1ab_1.conda#59561d9b70f9df3b884c29910eba6593 +https://conda.anaconda.org/conda-forge/linux-aarch64/libpq-17.2-hd56632b_1.conda#2113425a121b0aa65dc87728ed5601ac +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/linux-aarch64/scipy-1.13.1-py39hb921187_0.conda#1aac9080de661e03d286f18fb71e5240 -https://conda.anaconda.org/conda-forge/linux-aarch64/blas-2.125-openblas.conda#dfbaf914827bc38dda840c90231c91df -https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-base-3.9.2-py39hd333c8e_1.conda#b1a6b946d3b38515ecaf10f1ee5aa6c6 -https://conda.anaconda.org/conda-forge/linux-aarch64/pyside6-6.8.0.2-py39h51c6ee1_0.conda#c130c84c26696485a720d85bd530e992 -https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-3.9.2-py39ha65689a_1.conda#10358b436f2d5adcaa436a018ffc7d97 +https://conda.anaconda.org/conda-forge/linux-aarch64/blas-2.126-openblas.conda#b98894367755d9a81f6e90ef2bcff0a6 +https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-base-3.9.4-py39hd333c8e_0.conda#d3c00b185510462fe6c3829f06bbfc82 +https://conda.anaconda.org/conda-forge/linux-aarch64/qt6-main-6.8.1-ha0a94ed_2.conda#72dfd400f4b96eab2e36ff57bd887f13 +https://conda.anaconda.org/conda-forge/linux-aarch64/pyside6-6.8.1-py39h51c6ee1_0.conda#ba98ca3cd6725e007a6ca0870e8212dd +https://conda.anaconda.org/conda-forge/linux-aarch64/matplotlib-3.9.4-py39ha65689a_0.conda#3694fc225c2b4ef3943e74c81c43307d diff --git a/build_tools/generate_authors_table.py b/build_tools/generate_authors_table.py index 483dc3739506e..6dcddda40af4d 100644 --- a/build_tools/generate_authors_table.py +++ b/build_tools/generate_authors_table.py @@ -15,9 +15,9 @@ import requests -print("user:", file=sys.stderr) +print("Input user:", file=sys.stderr) user = input() -token = getpass.getpass("access token:\n") +token = getpass.getpass("Input access token:\n") auth = (user, token) LOGO_URL = "https://avatars2.githubusercontent.com/u/365630?v=4" @@ -63,11 +63,13 @@ def get_contributors(): ), (core_devs, contributor_experience_team, comm_team, documentation_team), ): + print(f"Retrieving {team_slug}\n") for page in [1, 2]: # 30 per page reply = get(f"{entry_point}teams/{team_slug}/members?page={page}") lst.extend(reply.json()) # get members of scikit-learn on GitHub + print("Retrieving members\n") members = [] for page in [1, 2, 3]: # 30 per page reply = get(f"{entry_point}members?page={page}") @@ -214,6 +216,7 @@ def generate_list(contributors): documentation_team, ) = get_contributors() + print("Generating rst files") with open( REPO_FOLDER / "doc" / "maintainers.rst", "w+", encoding="utf-8" ) as rst_file: diff --git a/build_tools/github/build_minimal_windows_image.sh b/build_tools/github/build_minimal_windows_image.sh index adac06f02bb9a..cf07538878064 100755 --- a/build_tools/github/build_minimal_windows_image.sh +++ b/build_tools/github/build_minimal_windows_image.sh @@ -5,43 +5,49 @@ set -x PYTHON_VERSION=$1 -TEMP_FOLDER="$HOME/AppData/Local/Temp" -WHEEL_PATH=$(ls -d $TEMP_FOLDER/**/*/repaired_wheel/*) -WHEEL_NAME=$(basename $WHEEL_PATH) - -cp $WHEEL_PATH $WHEEL_NAME - -# Dot the Python version for identifying the base Docker image -PYTHON_DOCKER_IMAGE_PART=$(echo ${PYTHON_VERSION:0:1}.${PYTHON_VERSION:1:2}) - -if [[ "$CIBW_PRERELEASE_PYTHONS" =~ [tT]rue ]]; then - PYTHON_DOCKER_IMAGE_PART="${PYTHON_DOCKER_IMAGE_PART}-rc" +FREE_THREADED_BUILD="$(python -c"import sysconfig; print(bool(sysconfig.get_config_var('Py_GIL_DISABLED')))")" + +if [[ $FREE_THREADED_BUILD == "False" ]]; then + # Prepare a minimal Windows environement without any developer runtime libraries + # installed to check that the scikit-learn wheel does not implicitly rely on + # external DLLs when running the tests. + TEMP_FOLDER="$HOME/AppData/Local/Temp" + WHEEL_PATH=$(ls -d $TEMP_FOLDER/**/*/repaired_wheel/*) + WHEEL_NAME=$(basename $WHEEL_PATH) + + cp $WHEEL_PATH $WHEEL_NAME + + # Dot the Python version for identifying the base Docker image + PYTHON_DOCKER_IMAGE_PART=$(echo ${PYTHON_VERSION:0:1}.${PYTHON_VERSION:1:2}) + + if [[ "$CIBW_PRERELEASE_PYTHONS" =~ [tT]rue ]]; then + PYTHON_DOCKER_IMAGE_PART="${PYTHON_DOCKER_IMAGE_PART}-rc" + fi + + # We could have all of the following logic in a Dockerfile but it's a lot + # easier to do it in bash rather than figure out how to do it in Powershell + # inside the Dockerfile ... + DOCKER_IMAGE="winamd64/python:${PYTHON_DOCKER_IMAGE_PART}-windowsservercore" + MNT_FOLDER="C:/mnt" + CONTAINER_ID=$(docker run -it -v "$(cygpath -w $PWD):$MNT_FOLDER" -d $DOCKER_IMAGE) + + function exec_inside_container() { + docker exec $CONTAINER_ID powershell -Command $1 + } + + exec_inside_container "python -m pip install $MNT_FOLDER/$WHEEL_NAME" + exec_inside_container "python -m pip install $CIBW_TEST_REQUIRES" + + # Save container state to scikit-learn/minimal-windows image. On Windows the + # container needs to be stopped first. + docker stop $CONTAINER_ID + docker commit $CONTAINER_ID scikit-learn/minimal-windows +else + # This is too cumbersome to use a Docker image in the free-threaded case + # TODO Remove the next three lines when scipy and pandas each have a release + # with a Windows free-threaded wheel. + python -m pip install numpy + dev_anaconda_url=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple + python -m pip install --pre --upgrade --timeout=60 --extra-index $dev_anaconda_url scipy pandas --only-binary :all: + python -m pip install $CIBW_TEST_REQUIRES fi - -# We could have all of the following logic in a Dockerfile but it's a lot -# easier to do it in bash rather than figure out how to do it in Powershell -# inside the Dockerfile ... -DOCKER_IMAGE="winamd64/python:${PYTHON_DOCKER_IMAGE_PART}-windowsservercore" -MNT_FOLDER="C:/mnt" -CONTAINER_ID=$(docker run -it -v "$(cygpath -w $PWD):$MNT_FOLDER" -d $DOCKER_IMAGE) - -function exec_inside_container() { - docker exec $CONTAINER_ID powershell -Command $1 -} - -exec_inside_container "python -m pip install $MNT_FOLDER/$WHEEL_NAME" - -if [[ "$PYTHON_VERSION" == "313" ]]; then - # TODO: remove when pandas has a release with python 3.13 wheels - # First install numpy release - exec_inside_container "python -m pip install numpy" - # Then install pandas-dev - exec_inside_container "python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple pandas --only-binary :all:" -fi - -exec_inside_container "python -m pip install $CIBW_TEST_REQUIRES" - -# Save container state to scikit-learn/minimal-windows image. On Windows the -# container needs to be stopped first. -docker stop $CONTAINER_ID -docker commit $CONTAINER_ID scikit-learn/minimal-windows diff --git a/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_conda.lock b/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_conda.lock index 260cf1a598ee0..bb5aa3b1f43b7 100644 --- a/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_conda.lock +++ b/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_conda.lock @@ -1,55 +1,56 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 7044e24fc9243a244c265e4b8c44e1304a8f55cd0cfa2d036ead6f92921d624e +# input_hash: ad3ced8bfb037ba949d6129ec446e3900b4e9a23f87df881b5804d13539972c9 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81 -https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda#c27d1c142233b5bc9ca570c6e2e0c244 -https://conda.anaconda.org/conda-forge/noarch/cuda-version-12.4-h3060b56_3.conda#c9a3fe8b957176e1a8452c6f3431b0d8 +https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.12.14-hbcca054_0.conda#720523eb0d6a9b0f6120c16b2aa4e7de +https://conda.anaconda.org/conda-forge/noarch/cuda-version-11.8-h70ddcb2_3.conda#670f0e1593b8c1d84f57ad5fe5256799 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 -https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2022.1.0-h84fe81f_915.tar.bz2#2dcd1acca05c11410d4494d7fc7dfa2a +https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-3.10.0-he073ed8_18.conda#ad8527bf134a90e1c9ed35fa0b64318c https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda#0424ae29b104430108f5218a66db7260 -https://conda.anaconda.org/pytorch/noarch/pytorch-mutex-1.0-cuda.tar.bz2#a948316e36fb5b11223b3fcfa93f8358 https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda#8ac3367aafb1cc0a068483c580af8015 -https://conda.anaconda.org/conda-forge/noarch/cuda-cccl_linux-64-12.4.127-ha770c72_2.conda#357fbcd43f1296b02d6738a2295abc24 -https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-static_linux-64-12.4.127-h85509e4_2.conda#0b0522d8685968f25370d5c36bb9fba3 -https://conda.anaconda.org/conda-forge/noarch/cuda-cudart_linux-64-12.4.127-h85509e4_2.conda#329163110a96514802e9e64d971edf43 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda#048b02e3962f066da18efe3a21b77672 -https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_1.conda#1ece2ccb1dc8c68639712b05e0fae070 -https://conda.anaconda.org/conda-forge/noarch/cuda-cudart-dev_linux-64-12.4.127-h85509e4_2.conda#12039deb2a3f103f5756831702bf29fc -https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab -https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_1.conda#38a5cd3be5fb620b48069e27285f1a44 -https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_1.conda#e12057a66af8f2a38a839754ca4481e9 +https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-19.1.6-h024ca30_0.conda#96e42ccbd3c067c1713ff5f2d2169247 +https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.17-h0157908_18.conda#460eba7851277ec1fd80a1a24080787a https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2#562b26ba2e19059551a811e72ab7f793 +https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab +https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 +https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda#7df50d44d4a14d6c31a2c54f2cd92157 https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda#3cb76c3f10d3bc7f1105b2fc9db984df -https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.9.31-hb9d3cd8_0.conda#75f7776e1c9af78287f055ca34797517 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.2-heb4867d_0.conda#2b780c0338fc0ffa678ac82c54af51fd +https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.10.6-hb9d3cd8_0.conda#d7d4680337a14001b0e043e96529409b +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda#e2775acf57efd5af15b8e3d1d74d72d3 https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 -https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.22-hb9d3cd8_0.conda#b422943d5d772b7cc858b36ad2a92db5 -https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda#59f4c43bb1b5ef1c71946ff2cbf59524 +https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db +https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda#db833e03127376d461e1e13e76f09b6c https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda#e39480b9ca41323497b05492a63bc35b https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hd5240d6_1.conda#9822b874ea29af082e5d36098d25427d +https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.3-hb9d3cd8_1.conda#2ecf2f1c7e4e21fcfe6423a51a992d84 +https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda#7c7927b404672409d9917d49bff5f2d6 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-hc0a3c3a_1.conda#234a5554c53625688d51062645337328 +https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.9.0-hb9d3cd8_1.conda#1e936bd23d737aac62a18e9a1e7f8b18 +https://conda.anaconda.org/conda-forge/linux-64/libuv-1.49.2-hb9d3cd8_0.conda#070e3c9ddab77e38799d5c30b109c633 +https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda#4d638782050ab6faa27275bed57e9b4e +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-h7b32b05_1.conda#4ce6875f75469b2757a65e10a5d05e31 https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e -https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hb9d3cd8_1.conda#19608a9656912805b2b9a2f6bd257b04 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hb9d3cd8_1.conda#77cbc488235ebbaab2b6e912d3934bae +https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda#8035c64cb77ed555e3f150b7b3972480 -https://conda.anaconda.org/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda#7c21106b851ec72c037b162c216d8f05 -https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.12-h4ab18f5_0.conda#7ed427f0871fd41cb1d9c17727c17589 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.8.0-hd3f4568_0.conda#0902512e7a2de9722697fb011db07a54 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.0-hf20e7d7_0.conda#84412135f9c1dd8985741e9c351f499a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.0-hf20e7d7_0.conda#ff265c3736cdac819c8adb844e0557d8 -https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.0-hf20e7d7_0.conda#e54103489d34bd5a106b9298dc28c848 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.8.1-h1a47875_3.conda#55a8561fdbbbd34f50f57d9be12ed084 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.0-h4e1184b_5.conda#3f4c1197462a6df2be6dc8241828fe93 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.1-h4e1184b_4.conda#a5126a90e74ac739b00564a4c7ddcc36 +https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.2-h4e1184b_4.conda#74e8c3e4df4ceae34aa2959df4b28101 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda#62ee74e96c5ebb0af99386de58cf9553 -https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.3-h5888daf_0.conda#6595440079bed734b113de44ffd3cd0a +https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda#1d6afef758879ef5ee78127eb4cd2c4a https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda#d411fc29e338efb48c5fd4576d71d881 https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2#30186d27e2c9fa62b45fb1476b7200e3 -https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_h5888daf_1.conda#e1f604644fe8d78e22660e2fec6756bc +https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240722.0-cxx17_hbbce691_4.conda#488f260ccda0afaf08acb286db439c2f https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda#9566f0bd264fbd463002e759b8a82401 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda#06f70867945ea6a84d35836af780f1de https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055 @@ -59,33 +60,25 @@ https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_1.co https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda#d66573916ffcf376178462f1b61c941e https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda#ea25936bb4080d843790b586850f82b8 https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda#30fd6e37fe21f86f4bd26d6ee73eeec7 -https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.4-h7f98852_1002.tar.bz2#e728e874159b042d92b90238a3cb0dc2 https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda#48f4330bfcd959c3cfb704d424903c82 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.44-hadc24fc_0.conda#f4cc49d7aa68316213e4b12be35308d1 -https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda#b6f02b52a174e612e89548f4663ce56a -https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda#1f5a58e686b13bcfde88b93f547d23fe +https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.2-hee588c1_0.conda#b58da17db24b6e08bcbf8fed2fb8c915 +https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hf672d98_0.conda#be2de152d8073ef1c01b7728475f2fe7 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_1.conda#8371ac6457591af2cf6159439c1fd051 -https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.8.0-h166bdaf_0.tar.bz2#ede4266dc02e875fe1ea77b25dd43747 https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b -https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda#b26e8aa824079e1be0294e7152ca4559 https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda#5aa797f8787fe7a17d1b0821485b5adc -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda#589c9a3575a050b583241c3d688ad9aa -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_2.conda#85c0dc0bcd110c998b01856975486ee7 +https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_4.conda#9a5a1e3db671a8258c3f2c1969a4c654 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda#70caf8bb6cf39a0b6b7efc885f51c0fe -https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda#c66f837ac65e4d1cdeb80e2a1d5fcc3d -https://conda.anaconda.org/conda-forge/linux-64/s2n-1.5.6-h0e56266_0.conda#54752411d7559a8bbd4c0204a8f1cf35 +https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 +https://conda.anaconda.org/conda-forge/linux-64/s2n-1.5.10-hb5b8611_0.conda#999f3673f2a011f59287f2969e3749e4 +https://conda.anaconda.org/conda-forge/linux-64/sleef-3.7-h1b44611_2.conda#4792f3259c6fdc0b730563a85b211dc0 +https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda#3b3e64af585eadfb52bb90b553db5edf https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc -https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0 -https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae -https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.15.0-h17eb868_2.conda#bb03f4ce96deea2175fc3ec17b2c1c04 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.15.3-h831e299_5.conda#80dd9f0ddf935290d1dc00ec75ff3023 https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda#c63b5e52939e795ba8d26e35d767a843 -https://conda.anaconda.org/conda-forge/linux-64/cuda-cudart-12.4.127-he02047a_2.conda#a748faa52331983fc3adcc3b116fe0e4 -https://conda.anaconda.org/conda-forge/linux-64/cuda-cupti-12.4.127-he02047a_2.conda#46422ef1b1161fb180027e50c598ecd0 -https://conda.anaconda.org/conda-forge/linux-64/cuda-nvrtc-12.4.127-he02047a_2.conda#80baf6262f4a1a0dde42d85aaa393402 -https://conda.anaconda.org/conda-forge/linux-64/cuda-nvtx-12.4.127-he02047a_2.conda#656a004b6e44f50ce71c65cab0d429b4 -https://conda.anaconda.org/conda-forge/linux-64/cuda-opencl-12.4.127-he02047a_1.conda#1e98deda07c14d26c80d124cf0eb011a +https://conda.anaconda.org/conda-forge/linux-64/cudatoolkit-11.8.0-h4ba93d1_13.conda#eb43f5f1f16e2fad2eba22219c3e499b https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.0-h59595ed_0.conda#c2f83a5ddadadcdb08fe05863295ee97 https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda#9ae35c3d96db2c94ce0cef86efdfa2cb https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hbabe93e_0.conda#ff862eebdfeb2fd048ae9dc92510baca @@ -94,175 +87,164 @@ https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.c https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda#8b189310083baabfb622af68fd9d3ae3 https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2#76bbff344f0134279f225174e9064c8f https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2#c965a5aa0d5c1c37ffc62dff36e28400 -https://conda.anaconda.org/conda-forge/linux-64/libcufft-11.2.1.3-he02047a_2.conda#d2641a67c207946ef96f1328c4a8e8ed -https://conda.anaconda.org/conda-forge/linux-64/libcufile-1.9.1.3-he02047a_2.conda#a051267bcb1912467c81d802a7d3465e -https://conda.anaconda.org/conda-forge/linux-64/libcurand-10.3.5.147-he02047a_2.conda#9c4886d513fd477df88d411cd274c202 -https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.123-hb9d3cd8_0.conda#ee605e794bdc14e2b7f84c4faa0d8c2c +https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.124-hb9d3cd8_0.conda#8bc89311041d7fcb510238cf0848ccae https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1 https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.2.0-h69a702a_1.conda#0a7f4cd238267c88e5d69f7826a407eb https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda#19e57602824042dfd0446292ef90488b -https://conda.anaconda.org/conda-forge/linux-64/libnpp-12.2.5.30-he02047a_2.conda#a96a1edd18bee676cf2dcca251d3d6a4 -https://conda.anaconda.org/conda-forge/linux-64/libnvfatbin-12.4.127-he02047a_2.conda#d746b76642b4ac6e40f1219405672beb -https://conda.anaconda.org/conda-forge/linux-64/libnvjitlink-12.4.127-he02047a_2.conda#303845d6c48bf4185dc4138634650468 -https://conda.anaconda.org/conda-forge/linux-64/libnvjpeg-12.3.1.117-he02047a_2.conda#8f3ed0e41a4b505de40b4f96f4bfb0fa +https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.28-pthreads_h94d23a6_1.conda#62857b389e42b36b686331bec0922050 https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.28.2-h5b01275_0.conda#ab0bff36363bec94720275a681af8b83 -https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2024.07.02-hbbce691_1.conda#2124de47357b7a516c0a3efd8f88c143 +https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2024.07.02-hbbce691_2.conda#b2fede24428726dd867611664fb372e8 https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.21.0-h0e7cc3e_0.conda#dcb95c0a98ba9ff737f7ae482aef7833 -https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda#318b08df404f9c9be5712aaa5a6f0bb0 +https://conda.anaconda.org/conda-forge/linux-64/nccl-2.23.4.1-h03a54cd_3.conda#5ea398a88c7271b2e3ec56cd33da424f https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda#71004cbf7924e19c02746ccde9fd7123 https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4 -https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-ha2e4443_0.conda#6b7dcc7349efd123d493d2dbe85a045f https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda#ad748ccca349aec3e91743e08b5e2b50 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda#0e0cbe0564d03a99afd5fd7b362feecd https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda#608e0ef8256b81d04456e8d211eee3e8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-he73a12e_1.conda#05a8ea5f446de33006171a7afe6ae857 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_0.conda#0b666058a179b744a622d0a4a0c56353 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.5-he73a12e_0.conda#4c3e9fab69804ec6077697922d70c6e2 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.10-h4f16b4b_1.conda#125f34a17d7b4bea418a83904ea82ea6 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda#4d056880988120e29d75bfff282e0f45 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.0-h68c3b0c_2.conda#a08831d82df7546a599095b33f3cae2a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.9.0-hfad4ed3_3.conda#01bc29be557b8c7c1963f7ad7185529a +https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.0-h7959bf6_11.conda#9b3fb60fe57925a92f399bc3fc42eccf +https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.9.2-hefd7a92_4.conda#5ce4df662d32d3123ea8da15571b6f51 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f +https://conda.anaconda.org/conda-forge/linux-64/cudnn-9.3.0.75-hf36481c_2.conda#4317195ce030bb551f3853bf928d436f https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda#3f43953b7d3fb3aaa1d0d0723d91e368 -https://conda.anaconda.org/conda-forge/linux-64/libcublas-12.4.5.8-he02047a_2.conda#d446adae085aa1ff37c44b69988a6f06 -https://conda.anaconda.org/conda-forge/linux-64/libcusparse-12.3.1.170-he02047a_2.conda#1c4c7ff54dc5b947f2ab8f5ff8a28dae +https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-26_linux64_openblas.conda#ac52800af2e0c0e7dac770b435ce768a https://conda.anaconda.org/conda-forge/linux-64/libglib-2.82.2-h2ff4ddf_0.conda#13e8e54035ddd2b91875ba399f0f7c04 -https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_1.conda#80a57756c545ad11f9847835aa21e6b2 +https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8013e438185f33b13814c5c488acd5c https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a -https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-he137b08_1.conda#63872517c98aa305da58a757c443698e -https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.4-hb346dea_2.conda#69b90b70c434b916abf5a1d5ee5d55fb +https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de +https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.5-h8d12d68_1.conda#1a21e49e190d1ffe58531a81b6e400e1 https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h90cbb55_3.conda#2eeb50cab6652538eee8fc0bc3340c81 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_2.conda#57a9e7ee3c0840d3c8c9012473978629 -https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.2-he039a57_2.conda#5e7bb9779cc5c200e63475eb2538d382 -https://conda.anaconda.org/conda-forge/linux-64/python-3.12.7-hc5c86c4_0_cpython.conda#0515111a9cdf69f83278f7c197db9807 -https://conda.anaconda.org/conda-forge/linux-64/re2-2024.07.02-h77b4e00_1.conda#01093ff37c1b5e6bf9f17c0116747d11 +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_4.conda#af19508df9d2e9f6894a9076a0857dc7 +https://conda.anaconda.org/conda-forge/linux-64/openblas-0.3.28-pthreads_h6ec200e_1.conda#8fe5d50db07e92519cc639cb0aef9b1b +https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.3-h97ab989_1.conda#2f46eae652623114e112df13fae311cf +https://conda.anaconda.org/conda-forge/linux-64/python-3.12.8-h9e4cc4f_1_cpython.conda#7fd2fd79436d9b473812f14e86746844 +https://conda.anaconda.org/conda-forge/linux-64/re2-2024.07.02-h9925aae_2.conda#e84ddf12bde691e8ec894b00ea829ddf https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hb9d3cd8_1.conda#a7a49a8b85122b49214798321e2e96b4 -https://conda.anaconda.org/conda-forge/noarch/array-api-compat-1.9.1-pyhd8ed1ab_0.conda#f2328337441baa8f669d2a830cfd0097 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.8.0-h56a2c13_4.conda#44a599a9c2c7e5d75e062457ddc6666a -https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.11.0-h407ecb8_2.conda#f9fcf88ac9d34b2bfe70429064d7744c -https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-hebfffa5_3.conda#fceaedf1cdbcb02df9699a0d9b005292 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e +https://conda.anaconda.org/conda-forge/noarch/array-api-compat-1.10.0-pyhd8ed1ab_0.conda#e399bc184553ca13cb068d272a995f48 +https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.8.0-hb921021_15.conda#c79d50f64cffa5ad51ecc1a81057962f +https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.11.0-h11f4f37_12.conda#96c3e0221fa2da97619ee82faa341a73 +https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.2-h3394656_1.conda#b34c2833a1f56db610aeb27f206d800d https://conda.anaconda.org/conda-forge/linux-64/ccache-4.10.1-h065aff2_0.conda#d6b48c138e0c8170a6fe9c136e063540 -https://conda.anaconda.org/conda-forge/noarch/certifi-2024.8.30-pyhd8ed1ab_0.conda#12f7d00853807b0531775e9be891cb11 -https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99 -https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.7-py312hd8ed1ab_0.conda#f0d1309310498284ab13c9fd73db4781 -https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_0.conda#5cd86562580f274031ede6aa6aa24441 +https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 +https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.8-py312hd8ed1ab_1.conda#caa04d37126e82822468d6bdf50f5ebd +https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.11-py312h8fd2918_3.conda#21e433caf1bb1e4c95832f8bb731d64c https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d -https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda#d02ae936e42063ca46af6cdad2dbd1e0 -https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda#15dda3cdbf330abfe9f555d22f66db46 -https://conda.anaconda.org/conda-forge/linux-64/fastrlock-0.8.2-py312h30efb56_2.conda#7065ec5a4909f925e305b77e505b0aec -https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_0.conda#916f8ec5dd4128cd5f207a3c4c07b2c6 -https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda#f800d2da156d08e289b14e87e43c1ae5 +https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_1.conda#a16662747cdeb9abbac74d0057cc976e +https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a71efeae2c160f6789900ba2631a2c90 +https://conda.anaconda.org/conda-forge/linux-64/fastrlock-0.8.3-py312h6edf5ed_1.conda#2e401040f77cf54d8d5e1f0417dcf0b2 +https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.1-pyhd8ed1ab_1.conda#d692e9ba6f92dc51484bf3477e36ce7c +https://conda.anaconda.org/conda-forge/noarch/fsspec-2024.12.0-pyhd8ed1ab_0.conda#e041ad4c43ab5e10c74587f95378ebc7 +https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py312h68727a3_0.conda#444266743652a4f1538145e9362f6d3b https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda#51bb7010fc86f70eee639b4bb7a894f5 +https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-26_linux64_openblas.conda#ebcc5f37a435aa3c19640533c82f8d76 https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 -https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.10.1-hbbe4b11_0.conda#6e801c50a40301f6978c53976917b277 -https://conda.anaconda.org/conda-forge/linux-64/libcusolver-11.6.1.9-he02047a_2.conda#9f6877f8936be962f598db5e9b8efc51 -https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_1.conda#204892bce2e44252b5cf272712f10bdd +https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.11.1-h332b0f4_0.conda#2b3e0081006dc21e8bf53a91c83a055c +https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda#928b8be80851f5d8ffb016f9c81dae7a https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.67.1-hc2c308b_0.conda#4606a4647bfe857e3cfe21ca12ac3afb -https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.1-default_hecaa2ac_1000.conda#f54aeebefb5c5ff84eca4fb05ca8aa3a -https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.3-ha7bfdaf_0.conda#8bd654307c455162668cd66e36494000 +https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.11.2-default_h0d58e46_1001.conda#804ca9e91bcaea0824a341d55b1684f2 +https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-26_linux64_openblas.conda#3792604c43695d6a273bc5faaac47d48 +https://conda.anaconda.org/conda-forge/linux-64/libllvm19-19.1.6-ha7bfdaf_0.conda#ec6abc65eefc96cba8443b2716dcc43b https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h2c5496b_1.conda#e2eaefa4de2b7237af7c907b8bbc760a https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda#e71f31f8cfb0a91439f2086fc8aa0461 -https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py312h178313f_0.conda#a755704ea0e2503f8c227d84829a8e81 +https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py312h178313f_1.conda#eb227c3e0bf58f5bd69c0532b157975b https://conda.anaconda.org/conda-forge/linux-64/mpc-1.3.1-h24ddda3_1.conda#aa14b9a5196a6d8dd364164b7ce56acf -https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_0.conda#dbf6e2d89137da32fa6670f3bffc024e +https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_1.conda#3585aa87c43ab15b167b574cd73b057b https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 -https://conda.anaconda.org/conda-forge/noarch/networkx-3.4.2-pyhd8ed1ab_1.conda#1d4c088869f206413c59acdd309908b7 -https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda#7f2e286780f072ed750df46dc2631138 -https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda#cbe1bb1f21567018ce595d9c2be0f0db -https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda#d3483c8fc2dc2cc3f5cf43e26d60cabf -https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.0-pyhd8ed1ab_1.conda#035c17fbf099f50ff60bf2eb303b0a83 -https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_0.conda#986287f89929b2d629bd6ef6497dc307 +https://conda.anaconda.org/conda-forge/noarch/networkx-3.4.2-pyh267e887_2.conda#fd40bf7f7f4bc4b647dc8512053d9873 +https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 +https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa +https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.1-pyhd8ed1ab_0.conda#285e237b8f351e85e7574a2c7bfa6d46 +https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2024.2-pyhd8ed1ab_1.conda#c0def296b2f6d2dd7b030c2a7f66bb1f https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad -https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h66e93f0_1.conda#549e5930e768548a89c23f595dac5a95 -https://conda.anaconda.org/conda-forge/noarch/setuptools-75.3.0-pyhd8ed1ab_0.conda#2ce9825396daf72baabaade36cee16da -https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2 +https://conda.anaconda.org/conda-forge/noarch/setuptools-75.6.0-pyhff2d567_1.conda#fc80f7995e396cbaeabd23cf46c413dc +https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.5.0-pyhc1e730c_0.conda#df68d78237980a159bd7149f33c0e8fd -https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2#f832c45a477c78bebd107098db465095 -https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.2-pyhd8ed1ab_0.conda#e977934e00b355ff55ed154904044727 -https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h66e93f0_1.conda#af648b62462794649066366af4ecd5b0 -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_0.conda#ebe6952715e1d5eb567eeebf25250fa7 +https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 +https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py312h66e93f0_0.conda#e417822cb989e80a0d2b1b576fdd1657 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.12.2-pyha770c72_1.conda#d17f13df8b65464ca316cbc000a3cb64 https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-15.1.0-py312h66e93f0_1.conda#588486a61153f94c7c13816f7069e440 -https://conda.anaconda.org/conda-forge/noarch/wheel-0.44.0-pyhd8ed1ab_0.conda#d44e3b085abcaef02983c6305b84b584 +https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda#75cb7132eb58d97896e173ef12ac9986 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.2-hb9d3cd8_0.conda#bb2638cd7fbdd980b1cff9a99a6c1fa8 +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda#2ccd714aa2242315acaf0a67faea780b https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda#b5fcc7172d22516e1f965490e65e33a4 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda#17dcc85db3c7886650b8908b183d6876 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda#2de7f99d6581a4a7adbff607b5c278ca -https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.5-hb9d3cd8_4.conda#7da9007c0582712c4bad4131f89c8372 -https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.7.0-hadeddc1_5.conda#429e7497e7f08bc470d2872147d8ef6d +https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda#5efa5fa6243a622445fdfd72aee15efa +https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.7.7-hf454442_0.conda#947c82025693bebd557f782bb5d6b469 https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.14.0-h5cfcd09_0.conda#0a8838771cc2e985cd295e01ae83baf1 -https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.4-py312h178313f_0.conda#a32fbd2322865ac80c7db74c553f5306 -https://conda.anaconda.org/conda-forge/linux-64/cuda-libraries-12.4.1-ha770c72_1.conda#6bb3f998485d4344a7539e0b218b3fc1 -https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.54.1-py312h178313f_1.conda#bbbf5fa5cab622c33907bc8d7eeea9f7 -https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py312h7201bc8_2.conda#af9faf103fb57241246416dc70b466f7 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-9.0.0-hda332d3_1.conda#76b32dcf243444aea9c6b804bcfa40b8 -https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda#7b86ecb7d3557821c649b3c31e3eb9f2 -https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_0.conda#25df261d4523d9f9783bcdb7208d872f -https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.3-default_hb5137d0_0.conda#311e6a1d041db3d6a8a8437750d4234f -https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.3-default_h9c6a7e4_0.conda#b8a8cd77810b20754f358f2327812552 -https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.30.0-h804f50b_1.conda#0a1c61bdbf27a966bbb0c8bf9df37b02 -https://conda.anaconda.org/conda-forge/noarch/meson-1.6.0-pyhd8ed1ab_0.conda#380ba6a3eddd8e7649bfe8e6812611aa -https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.8-hedd0468_0.conda#dcd0ed5147d8876b0848a552b416ce76 -https://conda.anaconda.org/conda-forge/linux-64/pillow-11.0.0-py312h7b63e92_0.conda#385f46a4df6f97892503a841121a9acf -https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_0.conda#5dd546fe99b44fda83963d15f84263b7 -https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyh2cfa8aa_0.conda#10906a130eeb4a68645bf97c28333141 -https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.3-pyhd8ed1ab_0.conda#c03d61f31f38fdb9facf70c29958bf7a -https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda#2cf4264fffb9e6eff6031c5b6884d61c -https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-h84d6215_0.conda#ee6f7fd1e76061ef1fa307d41fa86a96 +https://conda.anaconda.org/conda-forge/linux-64/coverage-7.6.10-py312h178313f_0.conda#df113f58bdfc79c98f5e07b6bd3eb4c2 +https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.55.3-py312h178313f_1.conda#bc18c46eda4c2b29431981998507e723 +https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py312h7201bc8_3.conda#673ef4d6611f5b4ca7b5c1f8c65a38dc +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-10.1.0-h0b3b770_0.conda#ab1d7d56034814f4c3ed9f69f8c68806 +https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.5-pyhd8ed1ab_0.conda#2752a6ed44105bfb18c9bef1177d9dcd +https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 +https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp19.1-19.1.6-default_hb5137d0_0.conda#9caebd39281536bf6bcb32f665dd4fbf +https://conda.anaconda.org/conda-forge/linux-64/libclang13-19.1.6-default_h9c6a7e4_0.conda#e1d2936c320083f1c520c3a17372521c +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.32.0-h804f50b_0.conda#3d96df4d6b1c88455e05b94ce8a14a53 +https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-26_linux64_openblas.conda#7b8b7732fb4786c00cf9b67d1d69445c +https://conda.anaconda.org/conda-forge/linux-64/libmagma-2.8.0-h9ddd185_2.conda#8de40c4f75d36bb00a5870f682457f1d +https://conda.anaconda.org/conda-forge/noarch/meson-1.6.1-pyhd8ed1ab_0.conda#0062fb0a7f5da474705d0ce626de12f4 +https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.1-py312h7e784f5_0.conda#6159cab400b61f38579a7692be5e630a +https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py312h80c1187_0.conda#d3894405f05b2c0f351d5de3ae26fa9c +https://conda.anaconda.org/conda-forge/noarch/pip-24.3.1-pyh8b19718_2.conda#04e691b9fadd93a8a9fad87a81d4fd8f +https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.0-pyhd8ed1ab_1.conda#1239146a53a383a84633800294120f17 +https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda#799ed216dc6af62520f32aa39bc1c2bb +https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e +https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-hceb3a55_1.conda#ba7726b8df7b9d34ea80e82b097a4893 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f -https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.29.0-h73f0fd4_6.conda#19f6d559f3be939046d2ac5c7b2ded7a +https://conda.anaconda.org/conda-forge/noarch/array-api-strict-2.2-pyhd8ed1ab_1.conda#02e7a32986412d3aaf97095d17120757 +https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.29.7-hd92328a_7.conda#02b95564257d5c3db9c06beccf711f95 https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.10.0-h113e628_0.conda#73f73f60854f325a55f1d31459f2ab73 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.8.0-h736e048_1.conda#13de36be8de3ae3f05ba127631599213 -https://conda.anaconda.org/conda-forge/noarch/cuda-runtime-12.4.1-ha804496_0.conda#48829f4ef6005ae8d4867b99168ff2b8 -https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.30.0-h0121fbd_1.conda#afbbf507f8c96faa95a2efa376ad484c -https://conda.anaconda.org/conda-forge/linux-64/libpq-17.0-h04577a9_4.conda#392cae2a58fbcb9db8c2147c6d6d1620 -https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_0.conda#722b649da38842068d83b6e6770f11a1 -https://conda.anaconda.org/conda-forge/linux-64/mkl-2022.1.0-h84fe81f_915.tar.bz2#b9c8f925797a93dbff45e1626b025a6b -https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_0.conda#cb8a11b6d209e3d85e5094bdbd9ebd9c -https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_0.conda#b39568655c127a9c4a44d178ac99b6d0 +https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-26_linux64_openblas.conda#da61c3ef2fbe100b0613cbc2b01b502d +https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.1-py312h68727a3_0.conda#f5fbba0394ee45e9a64a73c2a994126a +https://conda.anaconda.org/conda-forge/linux-64/cupy-core-13.3.0-py312haa09b14_2.conda#565acd25611fce8f002b9ed10bd07165 +https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.32.0-h0121fbd_0.conda#877a5ec0431a5af83bf0cd0522bfe661 +https://conda.anaconda.org/conda-forge/linux-64/libmagma_sparse-2.8.0-h9ddd185_0.conda#f4eb3cfeaf9d91e72d5b2b8706bf059f +https://conda.anaconda.org/conda-forge/linux-64/libpq-17.2-h3b95a9b_1.conda#37724d8bae042345a19ca1a25dde786b +https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 +https://conda.anaconda.org/conda-forge/linux-64/mkl-2024.2.2-ha957f24_16.conda#1459379c79dda834673426504d52b319 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py312hf9745cd_1.conda#8bce4f6caaf8c5448c7ac86d87e26b4b +https://conda.anaconda.org/conda-forge/linux-64/polars-1.17.1-py312hda0fa55_0.conda#7ac74b8f85b43224508108f850617dad +https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.0.0-pyhd8ed1ab_1.conda#79963c319d1be62c8fd3e34555816e01 +https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd +https://conda.anaconda.org/conda-forge/linux-64/scipy-1.15.0-py312h180e4f1_0.conda#66004839e9394a241b483436a9742845 https://conda.anaconda.org/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_104.conda#68085d736d2b2f54498832b65059875d -https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.407-h6a6dca0_6.conda#3c25988c0b0a2085b4df578b7160d963 +https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.458-hc430e4a_4.conda#aeefac461bea1f126653c1285cf5af08 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.13.0-h3cf044e_1.conda#7eb66060455c7a47d9dcdbfa9f46579b -https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_mkl.tar.bz2#85f61af03fd291dae33150ffe89dc09a -https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2022.1.0-ha770c72_916.tar.bz2#69ba49e445f87aea2cba343a71a35ca2 -https://conda.anaconda.org/pytorch/linux-64/pytorch-cuda-12.4-hc786d27_7.tar.bz2#06635b1bbf5e2fef4a8b9b282500cd7b -https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.0-h6e8976b_0.conda#6d1c5d2d904d24c17cbb538a95855a4e -https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.12.0-ha633028_1.conda#7c1980f89dd41b097549782121a73490 -https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-16_linux64_mkl.tar.bz2#361bf757b95488de76c4f123805742d3 -https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_mkl.tar.bz2#a2f166748917d6d6e4707841ca1f519e -https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.0.2-py312h91f0f75_0.conda#ec3da81d5f9d3612b227e09a650f7bf2 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-18.0.0-ha5db6c2_1_cpu.conda#412e50a89595c2ed2d0d49e1c3665be6 -https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-16_linux64_mkl.tar.bz2#44ccc4d4dca6a8d57fa17442bc64b5a1 -https://conda.anaconda.org/conda-forge/linux-64/numpy-2.1.3-py312h58c1407_0.conda#dfdbc12e6d81889ba4c494a23f23eba8 -https://conda.anaconda.org/conda-forge/noarch/array-api-strict-2.1-pyhd8ed1ab_0.conda#15cc819ed82470249cbf1337791bc5ff -https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-16_linux64_mkl.tar.bz2#3f92c1c9e1c0e183462c5071aa02cae1 -https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.0-py312h68727a3_2.conda#ff28f374b31937c048107521c814791e -https://conda.anaconda.org/conda-forge/linux-64/cupy-core-13.3.0-py312h1acd1a8_2.conda#15e9530e87664584a6b409ecdf5c9264 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-18.0.0-h5888daf_1_cpu.conda#5eea7d1aad1772bb0b7629ba0bf9ba38 -https://conda.anaconda.org/conda-forge/linux-64/libparquet-18.0.0-h6bd9018_1_cpu.conda#13ac6045ae32e0fd87e51003570ba372 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py312hf9745cd_1.conda#8bce4f6caaf8c5448c7ac86d87e26b4b -https://conda.anaconda.org/conda-forge/linux-64/polars-1.12.0-py312hfe7c9be_0.conda#47b6df7e8b629d1257a6f971b88c15de -https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-18.0.0-py312h01725c0_0_cpu.conda#9100ae6cdd482666b38fa20e7819b385 -https://conda.anaconda.org/conda-forge/linux-64/scipy-1.14.1-py312h62794b6_1.conda#b43233a9e2f62fb94affe5607ea79473 -https://conda.anaconda.org/conda-forge/linux-64/blas-2.116-mkl.tar.bz2#c196a26abf6b4f132c88828ab7c2231c -https://conda.anaconda.org/conda-forge/linux-64/cupy-13.3.0-py312h7d319b9_2.conda#009ef049020fef7d1541183d52fab5a9 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-18.0.0-h5888daf_1_cpu.conda#ba0a7a916ce6145f484e46c32e89ba97 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.9.2-py312hd3ec401_1.conda#2f4f3854f23be30de29e9e4d39758349 +https://conda.anaconda.org/conda-forge/linux-64/blas-2.126-openblas.conda#057a3d8aebeae33d971bc66ee08cbf61 +https://conda.anaconda.org/conda-forge/linux-64/cupy-13.3.0-py312h8e83189_2.conda#75f6ffc66a1f05ce4f09e83511c9d852 +https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.5.1-cuda118_hb34f2e8_303.conda#da799bf557ff6376a1a58f40bddfb293 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.0-py312hd3ec401_0.conda#c27a17a8c54c0d35cf83bbc0de8f7f77 https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py312hc39e661_1.conda#372efc32220f0dfb603e5b31ffaefa23 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-18.0.0-h5c8f2c3_1_cpu.conda#295696a3696d039787fbf4f733a4f296 -https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.9.2-py312h7900ff3_1.conda#07d5646ea9f22f4b1c46c2947d1b2f58 -https://conda.anaconda.org/conda-forge/linux-64/pyarrow-18.0.0-py312h9cebb41_0.conda#e110b1f861e749bc1dd48ad5467adab8 -https://conda.anaconda.org/pytorch/linux-64/pytorch-2.5.1-py3.12_cuda12.4_cudnn9.1.0_0.tar.bz2#42164c6ce8e563c20a542686a8b9b964 -https://conda.anaconda.org/pytorch/linux-64/torchtriton-3.1.0-py312.tar.bz2#bb4b2d07cb6b9b476e78740c08ba69fe +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.8.1-h588cce1_2.conda#5d2f1f29c025a110a43f9946527623ab +https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.12.0-ha633028_1.conda#7c1980f89dd41b097549782121a73490 +https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.8.1-py312h91f0f75_0.conda#0b7900a6d6f6c441acad5e9ab51001ab +https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.5.1-cuda118_py312h919e71f_303.conda#f2fd2356f07999ac24b84b097bb96749 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-18.1.0-h44a453e_6_cpu.conda#2cf6d608d6e66506f69797d5c6944c35 +https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.0-py312h7900ff3_0.conda#89cde9791e6f6355266e7d4455207a5b +https://conda.anaconda.org/conda-forge/linux-64/pytorch-gpu-2.5.1-cuda126hf7c78f0_303.conda#afaf760e55725108ae78ed41198c49bb +https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-18.1.0-hcb10f89_6_cpu.conda#143f9288b64759a6427563f058c62f2b +https://conda.anaconda.org/conda-forge/linux-64/libparquet-18.1.0-h081d1f1_6_cpu.conda#68788df49ce7480187eb6387f15b2b67 +https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-18.1.0-py312h01725c0_0_cpu.conda#ee80934a6c280ff8635f8db5dec11e04 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-18.1.0-hcb10f89_6_cpu.conda#20ca46a6bc714a6ab189d5b3f46e66d8 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-18.1.0-h3ee7192_6_cpu.conda#aa313b3168caf98d00b3753f5ba27650 +https://conda.anaconda.org/conda-forge/linux-64/pyarrow-18.1.0-py312h7900ff3_0.conda#ac65b70df28687c6af4270923c020bdd diff --git a/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_environment.yml b/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_environment.yml index e2ffb1429aa1d..130627b9b7f7b 100644 --- a/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_environment.yml +++ b/build_tools/github/pylatest_conda_forge_cuda_array-api_linux-64_environment.yml @@ -25,8 +25,7 @@ dependencies: - pytest-cov - coverage - ccache - - pytorch::pytorch - - pytorch-cuda + - pytorch-gpu - polars - pyarrow - cupy diff --git a/build_tools/github/test_windows_wheels.sh b/build_tools/github/test_windows_wheels.sh index 5ee3f50d9506c..c96ec4ad89d3e 100755 --- a/build_tools/github/test_windows_wheels.sh +++ b/build_tools/github/test_windows_wheels.sh @@ -8,11 +8,23 @@ PROJECT_DIR=$2 python $PROJECT_DIR/build_tools/wheels/check_license.py -docker container run \ - --rm scikit-learn/minimal-windows \ - powershell -Command "python -c 'import sklearn; sklearn.show_versions()'" +FREE_THREADED_BUILD="$(python -c"import sysconfig; print(bool(sysconfig.get_config_var('Py_GIL_DISABLED')))")" -docker container run \ - -e SKLEARN_SKIP_NETWORK_TESTS=1 \ - --rm scikit-learn/minimal-windows \ - powershell -Command "pytest --pyargs sklearn" +if [[ $FREE_THREADED_BUILD == "False" ]]; then + # Run the tests for the scikit-learn wheel in a minimal Windows environment + # without any developer runtime libraries installed to ensure that it does not + # implicitly rely on the presence of the DLLs of such runtime libraries. + docker container run \ + --rm scikit-learn/minimal-windows \ + powershell -Command "python -c 'import sklearn; sklearn.show_versions()'" + + docker container run \ + -e SKLEARN_SKIP_NETWORK_TESTS=1 \ + --rm scikit-learn/minimal-windows \ + powershell -Command "pytest --pyargs sklearn" +else + # This is too cumbersome to use a Docker image in the free-threaded case + export PYTHON_GIL=0 + python -c "import sklearn; sklearn.show_versions()" + pytest --pyargs sklearn +fi diff --git a/build_tools/shared.sh b/build_tools/shared.sh index cb5242239d7cf..b4e56556be749 100644 --- a/build_tools/shared.sh +++ b/build_tools/shared.sh @@ -29,7 +29,7 @@ show_installed_libraries(){ activate_environment() { if [[ "$DISTRIB" =~ ^conda.* ]]; then source activate $VIRTUALENV - elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" || "$DISTRIB" == "pip-free-threaded" ]]; then + elif [[ "$DISTRIB" == "ubuntu" || "$DISTRIB" == "debian-32" ]]; then source $VIRTUALENV/bin/activate fi } diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index 03fae3c0f99ae..312a54dba4dad 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -26,6 +26,7 @@ with pip. To run this script you need: +- conda - conda-lock. The version should match the one used in the CI in sklearn/_min_dependencies.py - pip-tools @@ -100,9 +101,7 @@ def remove_from(alist, to_remove): "conda_dependencies": common_dependencies + [ "ccache", - # Make sure pytorch comes from the pytorch channel and not conda-forge - "pytorch::pytorch", - "pytorch-cuda", + "pytorch-gpu", "polars", "pyarrow", "cupy", @@ -225,12 +224,6 @@ def remove_from(alist, to_remove): # Test array API on CPU without PyTorch + ["array-api-compat", "array-api-strict"] ), - "package_constraints": { - # XXX: we would like to use the latest Python version, but for now using - # Python 3.12 makes the CI much slower so we use Python 3.11. See - # https://github.com/scikit-learn/scikit-learn/pull/29444#issuecomment-2219550662. - "python": "3.11", - }, }, { "name": "pylatest_pip_scipy_dev", @@ -266,6 +259,31 @@ def remove_from(alist, to_remove): + ["python-dateutil"] ), }, + { + "name": "pylatest_free_threaded", + "type": "conda", + "tag": "free-threaded", + "folder": "build_tools/azure", + "platform": "linux-64", + "channels": ["conda-forge"], + "conda_dependencies": [ + "python-freethreading", + "numpy", + # TODO add cython and scipy when there are conda-forge packages for + # them and remove dev version install in + # build_tools/azure/install.sh. Note that for now conda-lock does + # not deal with free-threaded wheels correctly, see + # https://github.com/conda/conda-lock/issues/754. + "joblib", + "threadpoolctl", + "pytest", + "pytest-xdist", + "ninja", + "meson-python", + "ccache", + "pip", + ], + }, { "name": "pymin_conda_forge_mkl", "type": "conda", diff --git a/build_tools/wheels/cibw_before_test.sh b/build_tools/wheels/cibw_before_test.sh index 193a3890530b4..29bfcd41a8bb3 100755 --- a/build_tools/wheels/cibw_before_test.sh +++ b/build_tools/wheels/cibw_before_test.sh @@ -6,14 +6,8 @@ set -x FREE_THREADED_BUILD="$(python -c"import sysconfig; print(bool(sysconfig.get_config_var('Py_GIL_DISABLED')))")" PY_VERSION=$(python -c 'import sys; print(f"{sys.version_info.major}{sys.version_info.minor}")') +# TODO: remove when scipy has a release with free-threaded wheels if [[ $FREE_THREADED_BUILD == "True" ]]; then - # TODO: remove when numpy, scipy and pandas have releases with free-threaded wheels - python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy scipy pandas --only-binary :all: - -elif [[ "$PY_VERSION" == "313" ]]; then - # TODO: remove when pandas has a release with python 3.13 wheels - # First install numpy release - python -m pip install numpy --only-binary :all: - # Then install pandas-dev - python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple pandas --only-binary :all: + python -m pip install numpy pandas + python -m pip install --pre --extra-index https://pypi.anaconda.org/scientific-python-nightly-wheels/simple scipy --only-binary :all: fi diff --git a/doc/api_reference.py b/doc/api_reference.py index b3e658bd22120..7c81887f48f36 100644 --- a/doc/api_reference.py +++ b/doc/api_reference.py @@ -123,6 +123,7 @@ def _get_submodule(module_name, submodule_name): "is_classifier", "is_clusterer", "is_regressor", + "is_outlier_detector", ], } ], @@ -386,6 +387,7 @@ def _get_submodule(module_name, submodule_name): "InconsistentVersionWarning", "NotFittedError", "UndefinedMetricWarning", + "EstimatorCheckFailedWarning", ], }, ], @@ -547,7 +549,7 @@ def _get_submodule(module_name, submodule_name): ], }, "sklearn.kernel_approximation": { - "short_summary": "Isotonic regression.", + "short_summary": "Kernel approximation.", "description": _get_guide("kernel_approximation"), "sections": [ { @@ -1296,6 +1298,7 @@ def _get_submodule(module_name, submodule_name): "autosummary": [ "estimator_checks.check_estimator", "estimator_checks.parametrize_with_checks", + "estimator_checks.estimator_checks_generator", ], }, { diff --git a/doc/common_pitfalls.rst b/doc/common_pitfalls.rst index c16385943f9ad..63d2893cec479 100644 --- a/doc/common_pitfalls.rst +++ b/doc/common_pitfalls.rst @@ -160,7 +160,7 @@ much higher than expected accuracy score:: >>> from sklearn.model_selection import train_test_split >>> from sklearn.feature_selection import SelectKBest - >>> from sklearn.ensemble import GradientBoostingClassifier + >>> from sklearn.ensemble import HistGradientBoostingClassifier >>> from sklearn.metrics import accuracy_score >>> # Incorrect preprocessing: the entire data is transformed @@ -168,9 +168,9 @@ much higher than expected accuracy score:: >>> X_train, X_test, y_train, y_test = train_test_split( ... X_selected, y, random_state=42) - >>> gbc = GradientBoostingClassifier(random_state=1) + >>> gbc = HistGradientBoostingClassifier(random_state=1) >>> gbc.fit(X_train, y_train) - GradientBoostingClassifier(random_state=1) + HistGradientBoostingClassifier(random_state=1) >>> y_pred = gbc.predict(X_test) >>> accuracy_score(y_test, y_pred) @@ -189,14 +189,14 @@ data, close to chance:: >>> select = SelectKBest(k=25) >>> X_train_selected = select.fit_transform(X_train, y_train) - >>> gbc = GradientBoostingClassifier(random_state=1) + >>> gbc = HistGradientBoostingClassifier(random_state=1) >>> gbc.fit(X_train_selected, y_train) - GradientBoostingClassifier(random_state=1) + HistGradientBoostingClassifier(random_state=1) >>> X_test_selected = select.transform(X_test) >>> y_pred = gbc.predict(X_test_selected) >>> accuracy_score(y_test, y_pred) - 0.46 + 0.5 Here again, we recommend using a :class:`~sklearn.pipeline.Pipeline` to chain together the feature selection and model estimators. The pipeline ensures @@ -207,15 +207,15 @@ is used only for calculating the accuracy score:: >>> X_train, X_test, y_train, y_test = train_test_split( ... X, y, random_state=42) >>> pipeline = make_pipeline(SelectKBest(k=25), - ... GradientBoostingClassifier(random_state=1)) + ... HistGradientBoostingClassifier(random_state=1)) >>> pipeline.fit(X_train, y_train) Pipeline(steps=[('selectkbest', SelectKBest(k=25)), - ('gradientboostingclassifier', - GradientBoostingClassifier(random_state=1))]) + ('histgradientboostingclassifier', + HistGradientBoostingClassifier(random_state=1))]) >>> y_pred = pipeline.predict(X_test) >>> accuracy_score(y_test, y_pred) - 0.46 + 0.5 The pipeline can also be fed into a cross-validation function such as :func:`~sklearn.model_selection.cross_val_score`. @@ -225,7 +225,7 @@ method is used during fitting and predicting:: >>> from sklearn.model_selection import cross_val_score >>> scores = cross_val_score(pipeline, X, y) >>> print(f"Mean accuracy: {scores.mean():.2f}+/-{scores.std():.2f}") - Mean accuracy: 0.46+/-0.07 + Mean accuracy: 0.43+/-0.05 .. _randomness: diff --git a/doc/conf.py b/doc/conf.py index 98e36f4fe36de..e2f1c837a65dd 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -207,6 +207,11 @@ # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = "pydata_sphinx_theme" +# This config option is used to generate the canonical links in the header +# of every page. The canonical link is needed to prevent search engines from +# returning results pointing to old scikit-learn versions. +html_baseurl = "https://scikit-learn.org/stable/" + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -346,6 +351,7 @@ html_js_files = [ "scripts/dropdown.js", "scripts/version-switcher.js", + "scripts/sg_plotly_resize.js", ] # Compile scss files into css files using sphinxcontrib-sass diff --git a/doc/contributor_experience_team.rst b/doc/contributor_experience_team.rst index 7d942a07e6a7d..73ccd668b20cd 100644 --- a/doc/contributor_experience_team.rst +++ b/doc/contributor_experience_team.rst @@ -6,6 +6,10 @@ img.avatar {border-radius: 10px;}
+
+

Virgil Chan

+
+

Juan Carlos Alfaro Jiménez

@@ -30,6 +34,10 @@

Norbert Preining

+
+

Stefanie Senger

+
+

Reshama Shaikh

diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst index 6ae944bd0305d..ee75579c46405 100644 --- a/doc/developers/advanced_installation.rst +++ b/doc/developers/advanced_installation.rst @@ -59,7 +59,7 @@ feature, code or documentation improvement). instead. #. Install a recent version of Python (3.9 or later at the time of writing) for - instance using Miniforge3_. Miniforge provides a conda-based distribution of + instance using Condaforge_. Conda-forge provides a conda-based distribution of Python and the most popular scientific libraries. If you installed Python with conda, we recommend to create a dedicated @@ -258,8 +258,8 @@ to enable OpenMP support: For Apple Silicon M1 hardware, only the conda-forge method below is known to work at the time of writing (January 2021). You can install the `macos/arm64` -distribution of conda using the `miniforge installer -`_ +distribution of conda using the `conda-forge installer +`_ macOS compilers from conda-forge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -482,4 +482,4 @@ the base system and these steps will not be necessary. .. _Homebrew: https://brew.sh .. _virtualenv: https://docs.python.org/3/tutorial/venv.html .. _conda environment: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html -.. _Miniforge3: https://github.com/conda-forge/miniforge#miniforge3 +.. _Condaforge: https://conda-forge.org/download/ diff --git a/doc/developers/contributing.rst b/doc/developers/contributing.rst index 129325e275963..3a939ee1be6e6 100644 --- a/doc/developers/contributing.rst +++ b/doc/developers/contributing.rst @@ -562,12 +562,15 @@ Commit Message Marker Action Taken by CI Note that, by default, the documentation is built but only the examples that are directly modified by the pull request are executed. -Lock files -^^^^^^^^^^ +.. _build_lock_files: + +Build lock files +^^^^^^^^^^^^^^^^ CIs use lock files to build environments with specific versions of dependencies. When a PR needs to modify the dependencies or their versions, the lock files should be updated -accordingly. This can be done by commenting in the PR: +accordingly. This can be done by adding the following comment directly in the GitHub +Pull Request (PR) discussion: .. code-block:: text @@ -592,6 +595,36 @@ update documentation-related lock files and add the `[doc build]` marker to the @scikit-learn-bot update lock-files --select-build doc --commit-marker "[doc build]" +Resolve conflicts in lock files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here is a bash snippet that helps resolving conflicts in environment and lock files: + +.. prompt:: bash + + # pull latest upstream/main + git pull upstream main --no-rebase + # resolve conflicts - keeping the upstream/main version for specific files + git checkout --theirs build_tools/*/*.lock build_tools/*/*environment.yml \ + build_tools/*/*lock.txt build_tools/*/*requirements.txt + git add build_tools/*/*.lock build_tools/*/*environment.yml \ + build_tools/*/*lock.txt build_tools/*/*requirements.txt + git merge --continue + +This will merge `upstream/main` into our branch, automatically prioritising the +`upstream/main` for conflicting environment and lock files (this is good enough, because +we will re-generate the lock files afterwards). + +Note that this only fixes conflicts in environment and lock files and you might have +other conflicts to resolve. + +Finally, we have to re-generate the environment and lock files for the CIs, as described +in :ref:`Build lock files `, or by running: + +.. prompt:: bash + + python build_tools/update_environments_and_lock_files.py + .. _stalled_pull_request: Stalled pull requests diff --git a/doc/developers/develop.rst b/doc/developers/develop.rst index 96061891946c1..7db68f2d40624 100644 --- a/doc/developers/develop.rst +++ b/doc/developers/develop.rst @@ -8,7 +8,12 @@ Whether you are proposing an estimator for inclusion in scikit-learn, developing a separate package compatible with scikit-learn, or implementing custom components for your own projects, this chapter details how to develop objects that safely interact with scikit-learn -Pipelines and model selection tools. +pipelines and model selection tools. + +This section details the public API you should use and implement for a scikit-learn +compatible estimator. Inside scikit-learn itself, we experiment and use some private +tools and our goal is always to make them public once they are stable enough, so that +you can also use them in your own projects. .. currentmodule:: sklearn @@ -17,10 +22,16 @@ Pipelines and model selection tools. APIs of scikit-learn objects ============================ -To have a uniform API, we try to have a common basic API for all the -objects. In addition, to avoid the proliferation of framework code, we -try to adopt simple conventions and limit to a minimum the number of -methods an object must implement. +There are two major types of estimators. You can think of the first group as simple +estimators, which consists most estimators, such as +:class:`~sklearn.linear_model.LogisticRegression` or +:class:`~sklearn.ensemble.RandomForestClassifier`. And the second group are +meta-estimators, which are estimators that wrap other estimators. +:class:`~sklearn.pipeline.Pipeline` and :class:`~sklearn.model_selection.GridSearchCV` +are two examples of meta-estimators. + +Here we start with a few vocabulary, and then we illustrate how you can implement +your own estimators. Elements of the scikit-learn API are described more definitively in the :ref:`glossary`. @@ -28,8 +39,7 @@ Elements of the scikit-learn API are described more definitively in the Different objects ----------------- -The main objects in scikit-learn are (one class can implement -multiple interfaces): +The main objects in scikit-learn are (one class can implement multiple interfaces): :Estimator: @@ -66,8 +76,9 @@ multiple interfaces): :Model: - A model that can give a `goodness of fit `_ - measure or a likelihood of unseen data, implements (higher is better):: + A model that can give a `goodness of fit + `_ measure or a likelihood of + unseen data, implements (higher is better):: score = model.score(data) @@ -81,33 +92,36 @@ classifier or a regressor. All estimators implement the fit method:: estimator.fit(X, y) -All built-in estimators also have a ``set_params`` method, which sets -data-independent parameters (overriding previous parameter values passed -to ``__init__``). - -All estimators in the main scikit-learn codebase should inherit from -``sklearn.base.BaseEstimator``. +Out of all the methods that an estimator implements, ``fit`` is usually the one you +want to implement yourself. Other methods such as ``set_params``, ``get_params``, etc. +are implemented in :class:`~sklearn.base.BaseEstimator`, which you should inherit from. +You might need to inherit from more mixins, which we will explain later. Instantiation ^^^^^^^^^^^^^ -This concerns the creation of an object. The object's ``__init__`` method -might accept constants as arguments that determine the estimator's behavior -(like the C constant in SVMs). It should not, however, take the actual training -data as an argument, as this is left to the ``fit()`` method:: +This concerns the creation of an object. The object's ``__init__`` method might accept +constants as arguments that determine the estimator's behavior (like the ``alpha`` +constant in :class:`~sklearn.linear_model.SGDClassifier`). It should not, however, take +the actual training data as an argument, as this is left to the ``fit()`` method:: + + clf2 = SGDClassifier(alpha=2.3) + clf3 = SGDClassifier([[1, 2], [2, 3]], [-1, 1]) # WRONG! - clf2 = SVC(C=2.3) - clf3 = SVC([[1, 2], [2, 3]], [-1, 1]) # WRONG! +Ideally, the arguments accepted by ``__init__`` should all be keyword arguments with a +default value. In other words, a user should be able to instantiate an estimator without +passing any arguments to it. In some cases, where there are no sane defaults for an +argument, they can be left without a default value. In scikit-learn itself, we have +very few places, only in some meta-estimators, where the sub-estimator(s) argument is +a required argument. -The arguments accepted by ``__init__`` should all be keyword arguments -with a default value. In other words, a user should be able to instantiate -an estimator without passing any arguments to it. The arguments should all -correspond to hyperparameters describing the model or the optimisation -problem the estimator tries to solve. These initial arguments (or parameters) -are always remembered by the estimator. -Also note that they should not be documented under the "Attributes" section, -but rather under the "Parameters" section for that estimator. +Most arguments correspond to hyperparameters describing the model or the optimisation +problem the estimator tries to solve. Other parameters might define how the estimator +behaves, e.g. defining the location of a cache to store some data. These initial +arguments (or parameters) are always remembered by the estimator. Also note that they +should not be documented under the "Attributes" section, but rather under the +"Parameters" section for that estimator. In addition, **every keyword argument accepted by** ``__init__`` **should correspond to an attribute on the instance**. Scikit-learn relies on this to @@ -119,10 +133,10 @@ To summarize, an ``__init__`` should look like:: self.param1 = param1 self.param2 = param2 -There should be no logic, not even input validation, -and the parameters should not be changed. -The corresponding logic should be put where the parameters are used, -typically in ``fit``. +There should be no logic, not even input validation, and the parameters should not be +changed; which also means ideally they should not be mutable objects such as lists or +dictionaries. If they're mutable, they should be copied before being modified. The +corresponding logic should be put where the parameters are used, typically in ``fit``. The following is wrong:: def __init__(self, param1=1, param2=2, param3=3): @@ -134,19 +148,26 @@ The following is wrong:: # the argument in the constructor self.param3 = param2 -The reason for postponing the validation is that the same validation -would have to be performed in ``set_params``, -which is used in algorithms like ``GridSearchCV``. +The reason for postponing the validation is that if ``__init__`` includes input +validation, then the same validation would have to be performed in ``set_params``, which +is used in algorithms like :class:`~sklearn.model_selection.GridSearchCV`. + +Also it is expected that parameters with trailing ``_`` are **not to be set +inside the** ``__init__`` **method**. More details on attributes that are not init +arguments come shortly. Fitting ^^^^^^^ -The next thing you will probably want to do is to estimate some -parameters in the model. This is implemented in the ``fit()`` method. +The next thing you will probably want to do is to estimate some parameters in the model. +This is implemented in the ``fit()`` method, and it's where the training happens. +For instance, this is where you have the computation to learn or estimate coefficients +for a linear model. The ``fit()`` method takes the training data as arguments, which can be one array in the case of unsupervised learning, or two arrays in the case -of supervised learning. +of supervised learning. Other metadata that come with the training data, such as +``sample_weight``, can also be passed to ``fit`` as keyword arguments. Note that the model is fitted using ``X`` and ``y``, but the object holds no reference to ``X`` and ``y``. There are, however, some exceptions to this, as in @@ -163,8 +184,8 @@ y array-like of shape (n_samples,) kwargs optional data-dependent parameters ============= ====================================================== -``X.shape[0]`` should be the same as ``y.shape[0]``. If this requisite -is not met, an exception of type ``ValueError`` should be raised. +The number of samples, i.e. ``X.shape[0]`` should be the same as ``y.shape[0]``. If this +requirement is not met, an exception of type ``ValueError`` should be raised. ``y`` might be ignored in the case of unsupervised learning. However, to make it possible to use the estimator as part of a pipeline that can @@ -178,17 +199,15 @@ the second place if they are implemented. The method should return the object (``self``). This pattern is useful to be able to implement quick one liners in an IPython session such as:: - y_predicted = SVC(C=100).fit(X_train, y_train).predict(X_test) + y_predicted = SGDClassifier(alpha=10).fit(X_train, y_train).predict(X_test) -Depending on the nature of the algorithm, ``fit`` can sometimes also -accept additional keywords arguments. However, any parameter that can -have a value assigned prior to having access to the data should be an -``__init__`` keyword argument. **fit parameters should be restricted -to directly data dependent variables**. For instance a Gram matrix or -an affinity matrix which are precomputed from the data matrix ``X`` are -data dependent. A tolerance stopping criterion ``tol`` is not directly -data dependent (although the optimal value according to some scoring -function probably is). +Depending on the nature of the algorithm, ``fit`` can sometimes also accept additional +keywords arguments. However, any parameter that can have a value assigned prior to +having access to the data should be an ``__init__`` keyword argument. Ideally, **fit +parameters should be restricted to directly data dependent variables**. For instance a +Gram matrix or an affinity matrix which are precomputed from the data matrix ``X`` are +data dependent. A tolerance stopping criterion ``tol`` is not directly data dependent +(although the optimal value according to some scoring function probably is). When ``fit`` is called, any previous call to ``fit`` should be ignored. In general, calling ``estimator.fit(X1)`` and then ``estimator.fit(X2)`` should @@ -203,37 +222,40 @@ default initialization strategy. Estimated Attributes ^^^^^^^^^^^^^^^^^^^^ -Attributes that have been estimated from the data must always have a name -ending with trailing underscore, for example the coefficients of -some regression estimator would be stored in a ``coef_`` attribute after -``fit`` has been called. - -The estimated attributes are expected to be overridden when you call ``fit`` -a second time. +According to scikit-learn conventions, attributes which you'd want to expose to your +users as public attributes and have been estimated or learned from the data must always +have a name ending with trailing underscore, for example the coefficients of some +regression estimator would be stored in a ``coef_`` attribute after ``fit`` has been +called. Similarly, attributes that you learn in the process and you'd like to store yet +not expose to the user, should have a leading underscore, e.g. ``_intermediate_coefs``. +You'd need to document the first group (with a trailing underscore) as "Attributes" and +no need to document the second group (with a leading underscore). -Optional Arguments -^^^^^^^^^^^^^^^^^^ - -In iterative algorithms, the number of iterations should be specified by -an integer called ``n_iter``. +The estimated attributes are expected to be overridden when you call ``fit`` a second +time. Universal attributes ^^^^^^^^^^^^^^^^^^^^ Estimators that expect tabular input should set a `n_features_in_` attribute at `fit` time to indicate the number of features that the estimator -expects for subsequent calls to `predict` or `transform`. -See -`SLEP010 -`_ +expects for subsequent calls to :term:`predict` or :term:`transform`. +See `SLEP010 +`__ for details. +Similarly, if estimators are given dataframes such as pandas or polars, they should +set a ``feature_names_in_`` attribute to indicate the features names of the input data, +detailed in `SLEP007 +`__. +Using :func:`~sklearn.utils.validation.validate_data` would automatically set these +attributes for you. + .. _rolling_your_own_estimator: Rolling your own estimator ========================== -If you want to implement a new estimator that is scikit-learn-compatible, -whether it is just for you or for contributing it to scikit-learn, there are +If you want to implement a new estimator that is scikit-learn compatible, there are several internals of scikit-learn that you should be aware of in addition to the scikit-learn API outlined above. You can check whether your estimator adheres to the scikit-learn interface and standards by running @@ -243,44 +265,46 @@ decorator can also be used (see its docstring for details and possible interactions with `pytest`):: >>> from sklearn.utils.estimator_checks import check_estimator - >>> from sklearn.svm import LinearSVC - >>> check_estimator(LinearSVC()) # passes + >>> from sklearn.tree import DecisionTreeClassifier + >>> check_estimator(DecisionTreeClassifier()) # passes The main motivation to make a class compatible to the scikit-learn estimator interface might be that you want to use it together with model evaluation and -selection tools such as :class:`model_selection.GridSearchCV` and -:class:`pipeline.Pipeline`. +selection tools such as :class:`~model_selection.GridSearchCV` and +:class:`~pipeline.Pipeline`. Before detailing the required interface below, we describe two ways to achieve the correct interface more easily. .. topic:: Project template: - We provide a `project template `_ - which helps in the creation of Python packages containing scikit-learn compatible estimators. - It provides: + We provide a `project template + `_ which helps in the + creation of Python packages containing scikit-learn compatible estimators. It + provides: * an initial git repository with Python package directory structure * a template of a scikit-learn estimator - * an initial test suite including use of ``check_estimator`` + * an initial test suite including use of :func:`~utils.parametrize_with_checks` * directory structures and scripts to compile documentation and example galleries - * scripts to manage continuous integration (testing on Linux and Windows) - * instructions from getting started to publishing on `PyPi `_ + * scripts to manage continuous integration (testing on Linux, MacOS, and Windows) + * instructions from getting started to publishing on `PyPi `__ -.. topic:: ``BaseEstimator`` and mixins: +.. topic:: :class:`base.BaseEstimator` and mixins: - We tend to use "duck typing", so building an estimator which follows - the API suffices for compatibility, without needing to inherit from or - even import any scikit-learn classes. + We tend to use "duck typing" instead of checking for :func:`isinstance`, which means + it's technically possible to implement estimator without inheriting from + scikit-learn classes. However, if you don't inherit from the right mixins, either + there will be a large amount of boilerplate code for you to implement and keep in + sync with scikit-learn development, or your estimator might not function the same + way as a scikit-learn estimator. Here we only document how to develop an estimator + using our mixins. If you're interested in implementing your estimator without + inheriting from scikit-learn mixins, you'd need to check our implementations. - However, if a dependency on scikit-learn is acceptable in your code, - you can prevent a lot of boilerplate code - by deriving a class from ``BaseEstimator`` - and optionally the mixin classes in ``sklearn.base``. - For example, below is a custom classifier, with more examples included - in the scikit-learn-contrib - `project template `__. + For example, below is a custom classifier, with more examples included in the + scikit-learn-contrib `project template + `__. It is particularly important to notice that mixins should be "on the left" while the ``BaseEstimator`` should be "on the right" in the inheritance list for proper @@ -288,7 +312,7 @@ the correct interface more easily. >>> import numpy as np >>> from sklearn.base import BaseEstimator, ClassifierMixin - >>> from sklearn.utils.validation import check_X_y, check_array, check_is_fitted + >>> from sklearn.utils.validation import validate_data, check_is_fitted >>> from sklearn.utils.multiclass import unique_labels >>> from sklearn.metrics import euclidean_distances >>> class TemplateClassifier(ClassifierMixin, BaseEstimator): @@ -298,8 +322,8 @@ the correct interface more easily. ... ... def fit(self, X, y): ... - ... # Check that X and y have correct shape - ... X, y = check_X_y(X, y) + ... # Check that X and y have correct shape, set n_features_in_, etc. + ... X, y = validate_data(self, X, y) ... # Store the classes seen during fit ... self.classes_ = unique_labels(y) ... @@ -314,23 +338,27 @@ the correct interface more easily. ... check_is_fitted(self) ... ... # Input validation - ... X = check_array(X) + ... X = validate_data(self, X, reset=False) ... ... closest = np.argmin(euclidean_distances(X, self.X_), axis=1) ... return self.y_[closest] +And you can check that the above estimator passes all common checks:: + + >>> from sklearn.utils.estimator_checks import check_estimator + >>> check_estimator(TemplateClassifier()) # passes get_params and set_params ------------------------- All scikit-learn estimators have ``get_params`` and ``set_params`` functions. + The ``get_params`` function takes no arguments and returns a dict of the ``__init__`` parameters of the estimator, together with their values. -It must take one keyword argument, ``deep``, which receives a boolean value -that determines whether the method should return the parameters of -sub-estimators (for most estimators, this can be ignored). The default value -for ``deep`` should be `True`. For instance considering the following -estimator:: +It takes one keyword argument, ``deep``, which receives a boolean value that determines +whether the method should return the parameters of sub-estimators (only relevant for +meta-estimators). The default value for ``deep`` is ``True``. For instance considering +the following estimator:: >>> from sklearn.base import BaseEstimator >>> from sklearn.linear_model import LogisticRegression @@ -339,7 +367,7 @@ estimator:: ... self.subestimator = subestimator ... self.my_extra_param = my_extra_param -The parameter `deep` will control whether or not the parameters of the +The parameter `deep` controls control whether or not the parameters of the `subestimator` should be reported. Thus when `deep=True`, the output will be:: >>> my_estimator = MyEstimator(subestimator=LogisticRegression()) @@ -363,174 +391,124 @@ The parameter `deep` will control whether or not the parameters of the subestimator__warm_start -> False subestimator -> LogisticRegression() -Often, the `subestimator` has a name (as e.g. named steps in a -:class:`~sklearn.pipeline.Pipeline` object), in which case the key should -become `__C`, `__class_weight`, etc. +If the meta-estimator takes multiple sub-estimators, often, those sub-estimators have +names (as e.g. named steps in a :class:`~pipeline.Pipeline` object), in which case the +key should become `__C`, `__class_weight`, etc. -While when `deep=False`, the output will be:: +When ``deep=False``, the output will be:: >>> for param, value in my_estimator.get_params(deep=False).items(): ... print(f"{param} -> {value}") my_extra_param -> random subestimator -> LogisticRegression() -On the other hand, ``set_params`` takes the parameters of ``__init__`` -as keyword arguments, unpacks them into a dict of the form -``'parameter': value`` and sets the parameters of the estimator using this dict. -Return value must be the estimator itself. - -While the ``get_params`` mechanism is not essential (see :ref:`cloning` below), -the ``set_params`` function is necessary as it is used to set parameters during -grid searches. - -The easiest way to implement these functions, and to get a sensible -``__repr__`` method, is to inherit from ``sklearn.base.BaseEstimator``. If you -do not want to make your code dependent on scikit-learn, the easiest way to -implement the interface is:: - - def get_params(self, deep=True): - # suppose this estimator has parameters "alpha" and "recursive" - return {"alpha": self.alpha, "recursive": self.recursive} - - def set_params(self, **parameters): - for parameter, value in parameters.items(): - setattr(self, parameter, value) - return self - - -Parameters and init -------------------- -As :class:`model_selection.GridSearchCV` uses ``set_params`` -to apply parameter setting to estimators, -it is essential that calling ``set_params`` has the same effect -as setting parameters using the ``__init__`` method. -The easiest and recommended way to accomplish this is to -**not do any parameter validation in** ``__init__``. -All logic behind estimator parameters, -like translating string arguments into functions, should be done in ``fit``. +On the other hand, ``set_params`` takes the parameters of ``__init__`` as keyword +arguments, unpacks them into a dict of the form ``'parameter': value`` and sets the +parameters of the estimator using this dict. It returns the estimator itself. -Also it is expected that parameters with trailing ``_`` are **not to be set -inside the** ``__init__`` **method**. All and only the public attributes set by -fit have a trailing ``_``. As a result the existence of parameters with -trailing ``_`` is used to check if the estimator has been fitted. +The :func:`~base.BaseEstimator.set_params` function is used to set parameters during +grid search for instance. .. _cloning: Cloning ------- -For use with the :mod:`~sklearn.model_selection` module, -an estimator must support the ``base.clone`` function to replicate an estimator. -This can be done by providing a ``get_params`` method. -If ``get_params`` is present, then ``clone(estimator)`` will be an instance of -``type(estimator)`` on which ``set_params`` has been called with clones of -the result of ``estimator.get_params()``. - -Objects that do not provide this method will be deep-copied -(using the Python standard function ``copy.deepcopy``) -if ``safe=False`` is passed to ``clone``. - -Estimators can customize the behavior of :func:`base.clone` by defining a -`__sklearn_clone__` method. `__sklearn_clone__` must return an instance of the -estimator. `__sklearn_clone__` is useful when an estimator needs to hold on to -some state when :func:`base.clone` is called on the estimator. For example, -:class:`~sklearn.frozen.FrozenEstimator` makes use of this. +As already mentioned that when constructor arguments are mutable, they should be +copied before modifying them. This also applies to constructor arguments which are +estimators. That's why meta-estimators such as :class:`~model_selection.GridSearchCV` +create a copy of the given estimator before modifying it. + +However, in scikit-learn, when we copy an estimator, we get an unfitted estimator +where only the constructor arguments are copied (with some exceptions, e.g. attributes +related to certain internal machinery such as metadata routing). -Pipeline compatibility ----------------------- -For an estimator to be usable together with ``pipeline.Pipeline`` in any but the -last step, it needs to provide a ``fit`` or ``fit_transform`` function. -To be able to evaluate the pipeline on any data but the training set, -it also needs to provide a ``transform`` function. -There are no special requirements for the last step in a pipeline, except that -it has a ``fit`` function. All ``fit`` and ``fit_transform`` functions must -take arguments ``X, y``, even if y is not used. Similarly, for ``score`` to be -usable, the last step of the pipeline needs to have a ``score`` function that -accepts an optional ``y``. +The function responsible for this behavior is :func:`~base.clone`. + +Estimators can customize the behavior of :func:`base.clone` by overriding the +:func:`base.BaseEstimator.__sklearn_clone__` method. `__sklearn_clone__` must return an +instance of the estimator. `__sklearn_clone__` is useful when an estimator needs to hold +on to some state when :func:`base.clone` is called on the estimator. For example, +:class:`~sklearn.frozen.FrozenEstimator` makes use of this. Estimator types --------------- -Some common functionality depends on the kind of estimator passed. For example, -cross-validation in :class:`model_selection.GridSearchCV` and -:func:`model_selection.cross_val_score` defaults to being stratified when used on a -classifier, but not otherwise. Similarly, scorers for average precision that take a -continuous prediction need to call ``decision_function`` for classifiers, but -``predict`` for regressors. This distinction between classifiers and regressors is -implemented by inheriting from :class:`~base.ClassifierMixin`, -:class:`~base.RegressorMixin`, :class:`~base.ClusterMixin`, :class:`~base.OutlierMixin` -or :class:`~base.DensityMixin`, which will set the corresponding :term:`estimator tags` -correctly. - -When a meta-estimator needs to distinguish among estimator types, instead of checking -the value of the tags directly, helpers like :func:`base.is_classifier` should be used. - -Specific models ---------------- - -Classifiers should accept ``y`` (target) arguments to ``fit`` that are -sequences (lists, arrays) of either strings or integers. They should not -assume that the class labels are a contiguous range of integers; instead, they -should store a list of classes in a ``classes_`` attribute or property. The -order of class labels in this attribute should match the order in which -``predict_proba``, ``predict_log_proba`` and ``decision_function`` return their -values. The easiest way to achieve this is to put:: +Among simple estimators (as opposed to meta-estimators), the most common types are +transformers, classifiers, regressors, and clustering algorithms. + +**Transformers** inherit from :class:`~base.TransformerMixin`, and implement a `transform` +method. These are estimators which take the input, and transform it in some way. Note +that they should never change the number of input samples, and the output of `transform` +should correspond to its input samples in the same given order. + +**Regressors** inherit from :class:`~base.RegressorMixin`, and implement a `predict` method. +They should accept numerical ``y`` in their `fit` method. Regressors use +:func:`~metrics.r2_score` by default in their :func:`~base.RegressorMixin.score` method. + +**Classifiers** inherit from :class:`~base.ClassifierMixin`. If it applies, classifiers can +implement ``decision_function`` to return raw decision values, based on which +``predict`` can make its decision. If calculating probabilities is supported, +classifiers can also implement ``predict_proba`` and ``predict_log_proba``. + +Classifiers should accept ``y`` (target) arguments to ``fit`` that are sequences (lists, +arrays) of either strings or integers. They should not assume that the class labels are +a contiguous range of integers; instead, they should store a list of classes in a +``classes_`` attribute or property. The order of class labels in this attribute should +match the order in which ``predict_proba``, ``predict_log_proba`` and +``decision_function`` return their values. The easiest way to achieve this is to put:: self.classes_, y = np.unique(y, return_inverse=True) -in ``fit``. This returns a new ``y`` that contains class indexes, rather than -labels, in the range [0, ``n_classes``). +in ``fit``. This returns a new ``y`` that contains class indexes, rather than labels, +in the range [0, ``n_classes``). -A classifier's ``predict`` method should return -arrays containing class labels from ``classes_``. -In a classifier that implements ``decision_function``, -this can be achieved with:: +A classifier's ``predict`` method should return arrays containing class labels from +``classes_``. In a classifier that implements ``decision_function``, this can be +achieved with:: def predict(self, X): D = self.decision_function(X) return self.classes_[np.argmax(D, axis=1)] -In linear models, coefficients are stored in an array called ``coef_``, and the -independent term is stored in ``intercept_``. ``sklearn.linear_model._base`` -contains a few base classes and mixins that implement common linear model -patterns. +The :mod:`~sklearn.utils.multiclass` module contains useful functions for working with +multiclass and multilabel problems. -The :mod:`~sklearn.utils.multiclass` module contains useful functions -for working with multiclass and multilabel problems. +**Clustering algorithms** inherit from :class:`~base.ClusterMixin`. Ideally, they should +accept a ``y`` parameter in their ``fit`` method, but it should be ignored. Clustering +algorithms should set a ``labels_`` attribute, storing the labels assigned to each +sample. If applicale, they can also implement a ``predict`` method, returning the +labels assigned to newly given samples. + +If one needs to check the type of a given estimator, e.g. in a meta-estimator, one can +check if the given object implements a ``transform`` method for transformers, and +otherwise use helper functions such as :func:`~base.is_classifier` or +:func:`~base.is_regressor`. .. _estimator_tags: Estimator Tags -------------- -.. warning:: - - The estimator tags are experimental and the API is subject to change. - .. note:: - Scikit-learn introduced estimator tags in version 0.21 as a - private API and mostly used in tests. However, these tags expanded - over time and many third party developers also need to use - them. Therefore in version 1.6 the API for the tags were revamped - and exposed as public API. - -The estimator tags are annotations of estimators that allow -programmatic inspection of their capabilities, such as sparse matrix -support, supported output types and supported methods. The estimator -tags are an instance of :class:`~sklearn.utils.Tags` returned by the -method :meth:`~sklearn.base.BaseEstimator.__sklearn_tags__()`. These -tags are used in the common checks run by the -:func:`~sklearn.utils.estimator_checks.check_estimator` function and -the :func:`~sklearn.utils.estimator_checks.parametrize_with_checks` -decorator. Tags determine which checks to run and what input data is -appropriate. Tags can depend on estimator parameters or even system -architecture and can in general only be determined at runtime and -are therefore instance attributes rather than class attributes. See -:class:`~sklearn.utils.Tags` for more information about individual -tags. - -It is unlikely that the default values for each tag will suit the -needs of your specific estimator. You can change the default values by -defining a `__sklearn_tags__()` method which returns the new values -for your estimator's tags. For example:: + Scikit-learn introduced estimator tags in version 0.21 as a private API and mostly + used in tests. However, these tags expanded over time and many third party + developers also need to use them. Therefore in version 1.6 the API for the tags were + revamped and exposed as public API. + +The estimator tags are annotations of estimators that allow programmatic inspection of +their capabilities, such as sparse matrix support, supported output types and supported +methods. The estimator tags are an instance of :class:`~sklearn.utils.Tags` returned by +the method :meth:`~sklearn.base.BaseEstimator.__sklearn_tags__()`. These tags are used +in different places, such as :func:`~base.is_regressor` or the common checks run by +:func:`~sklearn.utils.estimator_checks.check_estimator` and +:func:`~sklearn.utils.estimator_checks.parametrize_with_checks`, where tags determine +which checks to run and what input data is appropriate. Tags can depend on estimator +parameters or even system architecture and can in general only be determined at runtime +and are therefore instance attributes rather than class attributes. See +:class:`~sklearn.utils.Tags` for more information about individual tags. + +It is unlikely that the default values for each tag will suit the needs of your specific +estimator. You can change the default values by defining a `__sklearn_tags__()` method +which returns the new values for your estimator's tags. For example:: class MyMultiOutputEstimator(BaseEstimator): @@ -540,8 +518,27 @@ for your estimator's tags. For example:: tags.non_deterministic = True return tags -You can create a new subclass of :class:`~sklearn.utils.Tags` if you wish -to add new tags to the existing set. +You can create a new subclass of :class:`~sklearn.utils.Tags` if you wish to add new +tags to the existing set. Note that all attributes that you add in a child class need +to have a default value. It can be of the form:: + + from dataclasses import dataclass, asdict + + @dataclass + class MyTags(Tags): + my_tag: bool = True + + class MyEstimator(BaseEstimator): + def __sklearn_tags__(self): + tags_orig = super().__sklearn_tags__() + as_dict = { + field.name: getattr(tags_orig, field.name) + for field in fields(tags_orig) + } + tags = MyTags(**as_dict) + tags.my_tag = True + return tags + .. _developer_api_set_output: diff --git a/doc/developers/maintainer.rst.template b/doc/developers/maintainer.rst.template index 73a4572bab645..631ea125a40ce 100644 --- a/doc/developers/maintainer.rst.template +++ b/doc/developers/maintainer.rst.template @@ -118,6 +118,7 @@ Reference Steps * [ ] Update the sklearn dev0 version in main branch {%- endif %} * [ ] Set the version number in the release branch + * [ ] Generate the changelog in the release branch * [ ] Check that the wheels for the release can be built successfully * [ ] Merge the PR with `[cd build]` commit message to upload wheels to the staging repo * [ ] Upload the wheels and source tarball to https://test.pypi.org @@ -125,31 +126,79 @@ Reference Steps * [ ] Confirm bot detected at https://github.com/conda-forge/scikit-learn-feedstock and wait for merge * [ ] Upload the wheels and source tarball to PyPI + {%- if key != "rc" %} * [ ] Update news and what's new date in main branch * [ ] Backport news and what's new date in release branch + {%- endif %} {%- if key == "final" %} * [ ] Update symlink for stable in https://github.com/scikit-learn/scikit-learn.github.io {%- endif %} {%- if key != "rc" %} * [ ] Publish to https://github.com/scikit-learn/scikit-learn/releases {%- endif %} - * [ ] Announce on mailing list and on Twitter, and LinkedIn + * [ ] Announce on mailing list and on social media platforms (LinkedIn, Bluesky, etc.) {%- if key != "rc" %} * [ ] Update SECURITY.md in main branch {%- endif %} {% if key == "rc" %} - - Create a PR from `main` and targeting `main` to increment the dev0 `__version__` - variable in `sklearn/__init__.py`. This means while we are in the release - candidate period, the latest stable is two version behind the `main` branch, - instead of one. In this PR targeting `main`, you should also include a new what's - new file under the `doc/whats_new/` directory so that we prepare the - changelog for the next release. + - Create a PR from `main` and targeting `main` to prepare for the next version. In + this PR you need to: + + - Increment the dev0 `__version__` variable in `sklearn/__init__.py`. This means + that while we are in the release candidate period, the latest stable is two + versions behind the `main` branch, instead of one. + + - Include a new what's new file under the `doc/whats_new/` directory. Don't forget + to add an entry for this new file in `doc/whats_new.rst`. + + - Change the what's new file to the newly created one in the `filename` field of + the `tool.towncrier` section in `pyproject.toml`. {% endif %} - In the release branch, change the version number `__version__` in `sklearn/__init__.py` to `{{ version_full }}`. + - In the release branch, generate the changelog for the incoming version, i.e., + `doc/whats_new/{{ version_short }}.rst`. + {%- if key == "rc" %} + During the RC period we want to keep the fragments when we generate the changelog + because we'll generate it again for the final release, including the changes that + may happen in between: + + .. prompt:: bash + + towncrier build --keep --version {{ version_short }}.0 + + {%- else %} + For a non RC release, push a commit where you: + + - Generate the changelog, not keeping the fragments. + + .. prompt:: bash + + towncrier build --version {{ version_full }} + + {% if key == "final" -%} + - Link the release highlights example. + {% endif -%} + + - Add the list of contributor names. Suppose that the tag of the last release in + the previous major/minor version is `{{ previous_tag }}`, then you can use the + following command to retrieve the list of contributor names: + + .. prompt:: bash + + git shortlog -s {{ previous_tag }}.. | + cut -f2- | + sort --ignore-case | + tr "\n" ";" | + sed "s/;/, /g;s/, $//" | + fold -s + + Then create a PR targeting the `main` branch and cherry-pick this commit there. + {%- endif %} + - Trigger the wheel builder with the `[cd build]` commit marker. See also the `workflow runs of the wheel builder `_. @@ -206,6 +255,12 @@ Reference Steps https://github.com/conda-forge/scikit-learn-feedstock. If not, submit a PR for the release, targeting the `{% if key == "rc" %}rc{% else %}main{% endif %}` branch. + {%- if key == "rc" %} + Make sure to update the PR such that it will be synchronized with the `main` + branch. In particular, backport migrations that may have been added since the last + release. + {% endif %} + - Trigger the `PyPI publishing workflow `_ again, but this time to upload the artifacts to the real https://pypi.org/. To do @@ -246,24 +301,6 @@ Reference Steps twine upload dist/* {% if key != "rc" %} - - In the `main` branch, edit the corresponding file in the `doc/whats_new` directory - to update the release date - {%- if key == "final" %}, link the release highlights example,{% endif %} - and add the list of contributor names. Suppose that the tag of the last release in - the previous major/minor version is `{{ previous_tag }}`, then you can use the - following command to retrieve the list of contributor names: - - .. prompt:: bash - - git shortlog -s {{ previous_tag }}.. | - cut -f2- | - sort --ignore-case | - tr "\n" ";" | - sed "s/;/, /g;s/, $//" | - fold -s - - Then cherry-pick it in the release branch. - - In the `main` branch, edit `doc/templates/index.html` to change the "News" section in the landing page, along with the month of the release. {%- if key == "final" %} diff --git a/doc/developers/tips.rst b/doc/developers/tips.rst index 70c201b688578..207e0814dc374 100644 --- a/doc/developers/tips.rst +++ b/doc/developers/tips.rst @@ -218,12 +218,6 @@ PR-WIP: Regression test needed Please add a [non-regression test](https://en.wikipedia.org/wiki/Non-regression_testing) that would fail at main but pass in this PR. -PR-WIP: PEP8 - -:: - - You have some [PEP8](https://www.python.org/dev/peps/pep-0008/) violations, whose details you can see in the Circle CI `lint` job. It might be worth configuring your code editor to check for such errors on the fly, so you can catch them before committing. - PR-MRG: Patience :: diff --git a/doc/documentation_team.rst b/doc/documentation_team.rst index e7f13e5fe218f..64c0c2fea4b97 100644 --- a/doc/documentation_team.rst +++ b/doc/documentation_team.rst @@ -14,6 +14,10 @@

Lucy Liu

+
+

Maren Westermann

+
+

Yao Xiao

diff --git a/doc/faq.rst b/doc/faq.rst index 0139aac376098..18132c7ad3095 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -137,7 +137,7 @@ See :ref:`adding_graphical_models`. Will you add GPU support? ^^^^^^^^^^^^^^^^^^^^^^^^^ -Adding GPU support by default would introduce heavy harware-specific software +Adding GPU support by default would introduce heavy hardware-specific software dependencies and existing algorithms would need to be reimplemented. This would make it both harder for the average user to install scikit-learn and harder for the developers to maintain the code. diff --git a/doc/glossary.rst b/doc/glossary.rst index 691f8df0d308c..47af4c9e782ee 100644 --- a/doc/glossary.rst +++ b/doc/glossary.rst @@ -198,7 +198,8 @@ General Concepts This refers to the tests run on almost every estimator class in Scikit-learn to check they comply with basic API conventions. They are available for external use through - :func:`utils.estimator_checks.check_estimator`, with most of the + :func:`utils.estimator_checks.check_estimator` or + :func:`utils.estimator_checks.parametrize_with_checks`, with most of the implementation in ``sklearn/utils/estimator_checks.py``. Note: Some exceptions to the common testing regime are currently @@ -1695,9 +1696,15 @@ functions or non-estimator constructors. objects and avoid common pitfalls, you may refer to :ref:`randomness`. ``scoring`` - Specifies the score function to be maximized (usually by :ref:`cross - validation `), or -- in some cases -- multiple score - functions to be reported. The score function can be a string accepted + Depending on the object, can specify: + + * the score function to be maximized (usually by + :ref:`cross validation `), + * the multiple score functions to be reported, + * the score function to be used to check early stopping, or + * for visualization related objects, the score function to output or plot + + The score function can be a string accepted by :func:`metrics.get_scorer` or a callable :term:`scorer`, not to be confused with an :term:`evaluation metric`, as the latter have a more diverse API. ``scoring`` may also be set to None, in which case the @@ -1710,7 +1717,6 @@ functions or non-estimator constructors. this does *not* specify which score function is to be maximized, and another parameter such as ``refit`` maybe used for this purpose. - The ``scoring`` parameter is validated and interpreted using :func:`metrics.check_scoring`. @@ -1792,7 +1798,7 @@ See concept :term:`attribute`. the number of output features and :term:`n_features` is the number of input features. - See also :term:`components_` which is a similar attribute for linear + See also :term:`coef_` which is a similar attribute for linear predictors. ``coef_`` diff --git a/doc/images/ml_map.README.rst b/doc/images/ml_map.README.rst index 8d82c175dad58..645d2980591c2 100644 --- a/doc/images/ml_map.README.rst +++ b/doc/images/ml_map.README.rst @@ -13,8 +13,12 @@ for exporting the chart are: - Transparent Background: False - Appearance: Light -Each node in the chart that contains an estimator should have a link, where the root -directory is at `../../`. Note that after updating or re-exporting the SVG, the links -may be prefixed with e.g. `https://app.diagrams.net/`. Remember to check and remove -them, for instance by replacing all occurrences of `https://app.diagrams.net/../../` -with `../../`. +Note that estimators nodes are clickable and should go to the estimator +documentation. After updating or re-exporting the SVG with draw.io, the links +may be prefixed with e.g. `https://app.diagrams.net/`. Remember to check and +remove them, for instance by replacing all occurrences of +`https://app.diagrams.net/./` with `./` with the following command: + +.. prompt:: bash + + perl -pi -e 's@https://app.diagrams.net/\./@./@g' doc/images/ml_map.svg diff --git a/doc/images/ml_map.svg b/doc/images/ml_map.svg index 2dedc6cf054df..c329e0fcce24b 100644 --- a/doc/images/ml_map.svg +++ b/doc/images/ml_map.svg @@ -1,4 +1,4 @@ -
START
START
>50
samples
>50...
get
more
data
get...
NO
NO
predicting a
category
predicting...
YES
YES
do you have
labeled
data
do you hav...
YES
YES
predicting a
quantity
predicting...
NO
NO
just
looking
just...
NO
NO
predicting
structure
predicting...
NO
NO
tough
luck
tough...
<100K
samples
<100K...
YES
YES
SGD
Classifier
SGD...
NO
NO
Linear
SVC
Linear...
YES
YES
text
data
text...
😭
😭
Kernel
Approximation
Kernel...
😭
😭
KNeighbors
Classifier
KNeighbors...
NO
NO
SVC
SVC
Ensemble
Classifiers
Ensemble...
😭
😭
Naive
Bayes
Naive...
YES
YES
classification
classification
number of
categories
known
number of...
NO
NO
<10K
samples
<10K...
<10K
samples
<10K...
NO
NO
NO
NO
YES
YES
MeanShift
MeanShift
VBGMM
VBGMM
YES
YES
MiniBatch
KMeans
MiniBatch...
NO
NO
clustering
clustering
KMeans
KMeans
YES
YES
Spectral
Clustering
Spectral...
GMM
GMM
😭
😭
<100K
samples
<100K...
YES
YES
few features
should be
important
few features...
YES
YES
SGD
Regressor
SGD...
NO
NO
Lasso
Lasso
ElasticNet
ElasticNet
YES
YES
RidgeRegression
RidgeRegression
SVR(kernel="linear")
SVR(kernel="linea...
NO
NO
SVR(kernel="rbf")
SVR(kernel="rbf...
Ensemble
Regressors
Ensemble...
😭
😭
regression
regression
Ramdomized
PCA
Ramdomized...
YES
YES
<10K
samples
<10K...
😭
😭
Kernel
Approximation
Kernel...
NO
NO
IsoMap
IsoMap
Spectral
Embedding
Spectral...
YES
YES
LLE
LLE
😭
😭
dimensionality
reduction
dimensionality...
scikit-learn
algorithm cheat sheet
scikit-learn...
Text is not SVG - cannot display
+
START
START
>50
samples
>50...
get
more
data
get...
NO
NO
predicting a
category
predicting...
YES
YES
do you have
labeled
data
do you hav...
YES
YES
predicting a
quantity
predicting...
NO
NO
just
looking
just...
NO
NO
predicting
structure
predicting...
NO
NO
tough
luck
tough...
<100K
samples
<100K...
YES
YES
SGD
Classifier
SGD...
NO
NO
Linear
SVC
Linear...
YES
YES
text
data
text...
Kernel
Approximation
Kernel...
KNeighbors
Classifier
KNeighbors...
NO
NO
SVC
SVC
Ensemble
Classifiers
Ensemble...
Naive
Bayes
Naive...
YES
YES
classification
classification
number of
categories
known
number of...
NO
NO
<10K
samples
<10K...
<10K
samples
<10K...
NO
NO
NO
NO
YES
YES
MeanShift
MeanShift
VBGMM
VBGMM
YES
YES
MiniBatch
KMeans
MiniBatch...
NO
NO
clustering
clustering
KMeans
KMeans
YES
YES
Spectral
Clustering
Spectral...
GMM
GMM
<100K
samples
<100K...
YES
YES
few features
should be
important
few features...
YES
YES
SGD
Regressor
SGD...
NO
NO
Lasso
Lasso
ElasticNet
ElasticNet
YES
YES
RidgeRegression
RidgeRegression
SVR(kernel="linear")
SVR(kernel="linea...
NO
NO
SVR(kernel="rbf")
SVR(kernel="rbf...
Ensemble
Regressors
Ensemble...
regression
regression
Ramdomized
PCA
Ramdomized...
YES
YES
<10K
samples
<10K...
Kernel
Approximation
Kernel...
NO
NO
IsoMap
IsoMap
Spectral
Embedding
Spectral...
YES
YES
LLE
LLE
dimensionality
reduction
dimensionality...
scikit-learn
algorithm cheat sheet
scikit-learn...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
TRY
NEXT
TRY...
Text is not SVG - cannot display
diff --git a/doc/install_instructions_conda.rst b/doc/install_instructions_conda.rst index fe1c14bbb78d3..0b5a57b747021 100644 --- a/doc/install_instructions_conda.rst +++ b/doc/install_instructions_conda.rst @@ -1,5 +1,5 @@ Install conda using the -`miniforge installers `__ (no +`conda-forge installers `__ (no administrator permission required). Then run: .. prompt:: bash diff --git a/doc/js/scripts/sg_plotly_resize.js b/doc/js/scripts/sg_plotly_resize.js new file mode 100644 index 0000000000000..72ccb5dd50838 --- /dev/null +++ b/doc/js/scripts/sg_plotly_resize.js @@ -0,0 +1,14 @@ +// Related to https://github.com/scikit-learn/scikit-learn/issues/30279 +// There an interaction between plotly and bootstrap/pydata-sphinx-theme +// that causes plotly figures to not detect the right-hand sidebar width + +function resizePlotlyGraphs() { + const plotlyDivs = document.getElementsByClassName("plotly-graph-div"); + + for (const div of plotlyDivs) { + Plotly.Plots.resize(div); + } +} + +window.addEventListener("resize", resizePlotlyGraphs); +document.addEventListener("DOMContentLoaded", resizePlotlyGraphs); diff --git a/doc/jupyter-lite.json b/doc/jupyter-lite.json index 65ec9ca3006dc..9ad29615decb6 100644 --- a/doc/jupyter-lite.json +++ b/doc/jupyter-lite.json @@ -3,7 +3,7 @@ "jupyter-config-data": { "litePluginSettings": { "@jupyterlite/pyodide-kernel-extension:kernel": { - "pyodideUrl": "https://cdn.jsdelivr.net/pyodide/v0.26.0/full/pyodide.js" + "pyodideUrl": "https://cdn.jsdelivr.net/pyodide/v0.27.2/full/pyodide.js" } } } diff --git a/doc/machine_learning_map.rst b/doc/machine_learning_map.rst index a03bb963cb046..e63ab1b1ddce6 100644 --- a/doc/machine_learning_map.rst +++ b/doc/machine_learning_map.rst @@ -11,10 +11,10 @@ data and different problems. The flowchart below is designed to give users a bit of a rough guide on how to approach problems with regard to which estimators to try on your data. Click on any estimator in -the chart below to see its documentation. The 😭 emoji is to be read as "if this -estimator does not achieve the desired outcome, then follow the arrow and try the next -one". Use scroll wheel to zoom in and out, and click and drag to pan around. You can -also download the chart: :download:`ml_map.svg `. +the chart below to see its documentation. The **Try next** orange arrows are to be read as +"if this estimator does not achieve the desired outcome, then follow the arrow and try +the next one". Use scroll wheel to zoom in and out, and click and drag to pan around. +You can also download the chart: :download:`ml_map.svg `. .. raw:: html diff --git a/doc/maintainers.rst b/doc/maintainers.rst index 17d9f9edb48af..6b4f3a25c0ddc 100644 --- a/doc/maintainers.rst +++ b/doc/maintainers.rst @@ -10,10 +10,6 @@

Jérémie du Boisberranger

-
-

Joris Van den Bossche

-
-

Loïc Estève

@@ -30,10 +26,6 @@

Olivier Grisel

-
-

Yaroslav Halchenko

-
-

Tim Head

@@ -66,54 +58,26 @@

Christian Lorentzen

-
-

Jan Hendrik Metzen

-
-

Andreas Mueller

-
-

Vlad Niculae

-
-

Joel Nothman

-
-

Hanmin Qin

-
-

Omar Salman

-
-

Bertrand Thirion

-
-
-
-

Tom Dupré la Tour

-
-

Gael Varoquaux

-
-

Nelle Varoquaux

-
-

Yao Xiao

-
-

Roman Yurchak

-
-

Meekail Zain

diff --git a/doc/maintainers_emeritus.rst b/doc/maintainers_emeritus.rst index b979b77bba974..f5640ab2caf31 100644 --- a/doc/maintainers_emeritus.rst +++ b/doc/maintainers_emeritus.rst @@ -1,4 +1,5 @@ - Mathieu Blondel +- Joris Van den Bossche - Matthieu Brucher - Lars Buitinck - David Cournapeau @@ -11,6 +12,7 @@ - Angel Soler Gollonet - Chris Gorgolewski - Jaques Grobler +- Yaroslav Halchenko - Brian Holt - Arnaud Joly - Thouis (Ray) Jones @@ -20,14 +22,21 @@ - Wei Li - Paolo Losi - Gilles Louppe +- Jan Hendrik Metzen - Vincent Michel - Jarrod Millman +- Vlad Niculae - Alexandre Passos - Fabian Pedregosa - Peter Prettenhofer +- Hanmin Qin - (Venkat) Raghav, Rajagopalan - Jacob Schreiber - 杜世橋 Du Shiqiao +- Bertrand Thirion +- Tom Dupré la Tour - Jake Vanderplas +- Nelle Varoquaux - David Warde-Farley - Ron Weiss +- Roman Yurchak diff --git a/doc/modules/array_api.rst b/doc/modules/array_api.rst index 64d0485aa9c56..6ee4c12b7fbfc 100644 --- a/doc/modules/array_api.rst +++ b/doc/modules/array_api.rst @@ -9,7 +9,18 @@ Array API support (experimental) The `Array API `_ specification defines a standard API for all array manipulation libraries with a NumPy-like API. Scikit-learn's Array API support requires -`array-api-compat `__ to be installed. +`array-api-compat `__ to be installed, +and the environment variable `SCIPY_ARRAY_API` must be set to `1` before importing +`scipy` and `scikit-learn`: + +.. prompt:: bash $ + + export SCIPY_ARRAY_API=1 + +Please note that this environment variable is intended for temporary use. +For more details, refer to SciPy's `Array API documentation +`_. + Some scikit-learn estimators that primarily rely on NumPy (as opposed to using Cython) to implement the algorithmic logic of their `fit`, `predict` or @@ -24,6 +35,12 @@ explicitly as explained in the following. Currently, only `array-api-strict`, `cupy`, and `PyTorch` are known to work with scikit-learn's estimators. +The following video provides an overview of the standard's design principles +and how it facilitates interoperability between array libraries: + +- `Scikit-learn on GPUs with Array API `_ + by :user:`Thomas Fan ` at PyData NYC 2023. + Example usage ============= @@ -94,6 +111,7 @@ Estimators - :class:`linear_model.Ridge` (with `solver="svd"`) - :class:`discriminant_analysis.LinearDiscriminantAnalysis` (with `solver="svd"`) - :class:`preprocessing.KernelCenterer` +- :class:`preprocessing.LabelEncoder` - :class:`preprocessing.MaxAbsScaler` - :class:`preprocessing.MinMaxScaler` - :class:`preprocessing.Normalizer` @@ -115,6 +133,7 @@ Metrics - :func:`sklearn.metrics.cluster.entropy` - :func:`sklearn.metrics.accuracy_score` - :func:`sklearn.metrics.d2_tweedie_score` +- :func:`sklearn.metrics.f1_score` - :func:`sklearn.metrics.max_error` - :func:`sklearn.metrics.mean_absolute_error` - :func:`sklearn.metrics.mean_absolute_percentage_error` @@ -123,6 +142,7 @@ Metrics - :func:`sklearn.metrics.mean_squared_error` - :func:`sklearn.metrics.mean_squared_log_error` - :func:`sklearn.metrics.mean_tweedie_deviance` +- :func:`sklearn.metrics.multilabel_confusion_matrix` - :func:`sklearn.metrics.pairwise.additive_chi2_kernel` - :func:`sklearn.metrics.pairwise.chi2_kernel` - :func:`sklearn.metrics.pairwise.cosine_similarity` @@ -134,6 +154,7 @@ Metrics - :func:`sklearn.metrics.pairwise.polynomial_kernel` - :func:`sklearn.metrics.pairwise.rbf_kernel` (see :ref:`device_support_for_float64`) - :func:`sklearn.metrics.pairwise.sigmoid_kernel` +- :func:`sklearn.metrics.precision_recall_fscore_support` - :func:`sklearn.metrics.r2_score` - :func:`sklearn.metrics.root_mean_squared_error` - :func:`sklearn.metrics.root_mean_squared_log_error` diff --git a/doc/modules/classification_threshold.rst b/doc/modules/classification_threshold.rst index 8b3e6e3a68438..9adf846e75cba 100644 --- a/doc/modules/classification_threshold.rst +++ b/doc/modules/classification_threshold.rst @@ -97,7 +97,7 @@ a meaningful metric for their use case. the label of the class of interest (i.e. `pos_label`). Thus, if this label is not the right one for your application, you need to define a scorer and pass the right `pos_label` (and additional parameters) using the - :func:`~sklearn.metrics.make_scorer`. Refer to :ref:`scoring` to get + :func:`~sklearn.metrics.make_scorer`. Refer to :ref:`scoring_callable` to get information to define your own scoring function. For instance, we show how to pass the information to the scorer that the label of interest is `0` when maximizing the :func:`~sklearn.metrics.f1_score`:: diff --git a/doc/modules/clustering.rst b/doc/modules/clustering.rst index 7cf593baf20d1..53e09829c1d41 100644 --- a/doc/modules/clustering.rst +++ b/doc/modules/clustering.rst @@ -222,9 +222,10 @@ initializations of the centroids. One method to help address this issue is the k-means++ initialization scheme, which has been implemented in scikit-learn (use the ``init='k-means++'`` parameter). This initializes the centroids to be (generally) distant from each other, leading to probably better results than -random initialization, as shown in the reference. For a detailed example of -comaparing different initialization schemes, refer to -:ref:`sphx_glr_auto_examples_cluster_plot_kmeans_digits.py`. +random initialization, as shown in the reference. For detailed examples of +comparing different initialization schemes, refer to +:ref:`sphx_glr_auto_examples_cluster_plot_kmeans_digits.py` and +:ref:`sphx_glr_auto_examples_cluster_plot_kmeans_stability_low_dim_dense.py`. K-means++ can also be called independently to select seeds for other clustering algorithms, see :func:`sklearn.cluster.kmeans_plusplus` for details diff --git a/doc/modules/cross_validation.rst b/doc/modules/cross_validation.rst index 766ab712d72d9..3d06554be5815 100644 --- a/doc/modules/cross_validation.rst +++ b/doc/modules/cross_validation.rst @@ -608,7 +608,7 @@ samples that are part of the validation set, and to -1 for all other samples. Cross-validation iterators for grouped data ------------------------------------------- -The i.i.d. assumption is broken if the underlying generative process yield +The i.i.d. assumption is broken if the underlying generative process yields groups of dependent samples. Such a grouping of data is domain specific. An example would be when there is diff --git a/doc/modules/decomposition.rst b/doc/modules/decomposition.rst index 926a4482f1428..57130c49d3292 100644 --- a/doc/modules/decomposition.rst +++ b/doc/modules/decomposition.rst @@ -255,7 +255,7 @@ factorization, while larger values shrink many coefficients to zero. .. rubric:: References .. [Mrl09] `"Online Dictionary Learning for Sparse Coding" - `_ + `_ J. Mairal, F. Bach, J. Ponce, G. Sapiro, 2009 .. [Jen09] `"Structured Sparse Principal Component Analysis" `_ @@ -590,7 +590,7 @@ extracted from part of the image of a raccoon face looks like. .. rubric:: References * `"Online dictionary learning for sparse coding" - `_ + `_ J. Mairal, F. Bach, J. Ponce, G. Sapiro, 2009 .. _MiniBatchDictionaryLearning: diff --git a/doc/modules/impute.rst b/doc/modules/impute.rst index 1431f26132338..fbbb0a68acf9b 100644 --- a/doc/modules/impute.rst +++ b/doc/modules/impute.rst @@ -110,9 +110,9 @@ imputation round are returned. This estimator is still **experimental** for now: default parameters or details of behaviour might change without any deprecation cycle. Resolving the following issues would help stabilize :class:`IterativeImputer`: - convergence criteria (:issue:`14338`), default estimators (:issue:`13286`), - and use of random state (:issue:`15611`). To use it, you need to explicitly - import ``enable_iterative_imputer``. + convergence criteria (:issue:`14338`) and default estimators + (:issue:`13286`). To use it, you need to explicitly import + ``enable_iterative_imputer``. :: diff --git a/doc/modules/linear_model.rst b/doc/modules/linear_model.rst index 01920325341cb..470ffe98185ed 100644 --- a/doc/modules/linear_model.rst +++ b/doc/modules/linear_model.rst @@ -1585,10 +1585,10 @@ better than an ordinary least squares in high dimension. Huber Regression ---------------- -The :class:`HuberRegressor` is different to :class:`Ridge` because it applies a -linear loss to samples that are classified as outliers. +The :class:`HuberRegressor` is different from :class:`Ridge` because it applies a +linear loss to samples that are defined as outliers by the `epsilon` parameter. A sample is classified as an inlier if the absolute error of that sample is -lesser than a certain threshold. It differs from :class:`TheilSenRegressor` +lesser than the threshold `epsilon`. It differs from :class:`TheilSenRegressor` and :class:`RANSACRegressor` because it does not ignore the effect of the outliers but gives a lesser weight to them. @@ -1603,13 +1603,13 @@ but gives a lesser weight to them. .. dropdown:: Mathematical details - The loss function that :class:`HuberRegressor` minimizes is given by + :class:`HuberRegressor` minimizes .. math:: \min_{w, \sigma} {\sum_{i=1}^n\left(\sigma + H_{\epsilon}\left(\frac{X_{i}w - y_{i}}{\sigma}\right)\sigma\right) + \alpha {||w||_2}^2} - where + where the loss function is given by .. math:: @@ -1624,7 +1624,7 @@ but gives a lesser weight to them. .. rubric:: References * Peter J. Huber, Elvezio M. Ronchetti: Robust Statistics, Concomitant scale - estimates, pg 172 + estimates, p. 172. The :class:`HuberRegressor` differs from using :class:`SGDRegressor` with loss set to `huber` in the following ways. @@ -1638,10 +1638,10 @@ in the following ways. samples while :class:`SGDRegressor` needs a number of passes on the training data to produce the same robustness. -Note that this estimator is different from the R implementation of Robust Regression -(https://stats.oarc.ucla.edu/r/dae/robust-regression/) because the R implementation does a weighted least -squares implementation with weights given to each sample on the basis of how much the residual is -greater than a certain threshold. +Note that this estimator is different from the `R implementation of Robust +Regression `_ because the R +implementation does a weighted least squares implementation with weights given to each +sample on the basis of how much the residual is greater than a certain threshold. .. _quantile_regression: diff --git a/doc/modules/model_evaluation.rst b/doc/modules/model_evaluation.rst index b161014f5268f..39befc057a35d 100644 --- a/doc/modules/model_evaluation.rst +++ b/doc/modules/model_evaluation.rst @@ -6,18 +6,158 @@ Metrics and scoring: quantifying the quality of predictions =========================================================== +.. _which_scoring_function: + +Which scoring function should I use? +==================================== + +Before we take a closer look into the details of the many scores and +:term:`evaluation metrics`, we want to give some guidance, inspired by statistical +decision theory, on the choice of **scoring functions** for **supervised learning**, +see [Gneiting2009]_: + +- *Which scoring function should I use?* +- *Which scoring function is a good one for my task?* + +In a nutshell, if the scoring function is given, e.g. in a kaggle competition +or in a business context, use that one. +If you are free to choose, it starts by considering the ultimate goal and application +of the prediction. It is useful to distinguish two steps: + +* Predicting +* Decision making + +**Predicting:** +Usually, the response variable :math:`Y` is a random variable, in the sense that there +is *no deterministic* function :math:`Y = g(X)` of the features :math:`X`. +Instead, there is a probability distribution :math:`F` of :math:`Y`. +One can aim to predict the whole distribution, known as *probabilistic prediction*, +or---more the focus of scikit-learn---issue a *point prediction* (or point forecast) +by choosing a property or functional of that distribution :math:`F`. +Typical examples are the mean (expected value), the median or a quantile of the +response variable :math:`Y` (conditionally on :math:`X`). + +Once that is settled, use a **strictly consistent** scoring function for that +(target) functional, see [Gneiting2009]_. +This means using a scoring function that is aligned with *measuring the distance +between predictions* `y_pred` *and the true target functional using observations of* +:math:`Y`, i.e. `y_true`. +For classification **strictly proper scoring rules**, see +`Wikipedia entry for Scoring rule `_ +and [Gneiting2007]_, coincide with strictly consistent scoring functions. +The table further below provides examples. +One could say that consistent scoring functions act as *truth serum* in that +they guarantee *"that truth telling [. . .] is an optimal strategy in +expectation"* [Gneiting2014]_. + +Once a strictly consistent scoring function is chosen, it is best used for both: as +loss function for model training and as metric/score in model evaluation and model +comparison. + +Note that for regressors, the prediction is done with :term:`predict` while for +classifiers it is usually :term:`predict_proba`. + +**Decision Making:** +The most common decisions are done on binary classification tasks, where the result of +:term:`predict_proba` is turned into a single outcome, e.g., from the predicted +probability of rain a decision is made on how to act (whether to take mitigating +measures like an umbrella or not). +For classifiers, this is what :term:`predict` returns. +See also :ref:`TunedThresholdClassifierCV`. +There are many scoring functions which measure different aspects of such a +decision, most of them are covered with or derived from the +:func:`metrics.confusion_matrix`. + +**List of strictly consistent scoring functions:** +Here, we list some of the most relevant statistical functionals and corresponding +strictly consistent scoring functions for tasks in practice. Note that the list is not +complete and that there are more of them. +For further criteria on how to select a specific one, see [Fissler2022]_. + +================== =================================================== ==================== ================================= +functional scoring or loss function response `y` prediction +================== =================================================== ==================== ================================= +**Classification** +mean :ref:`Brier score ` :sup:`1` multi-class ``predict_proba`` +mean :ref:`log loss ` multi-class ``predict_proba`` +mode :ref:`zero-one loss ` :sup:`2` multi-class ``predict``, categorical +**Regression** +mean :ref:`squared error ` :sup:`3` all reals ``predict``, all reals +mean :ref:`Poisson deviance ` non-negative ``predict``, strictly positive +mean :ref:`Gamma deviance ` strictly positive ``predict``, strictly positive +mean :ref:`Tweedie deviance ` depends on ``power`` ``predict``, depends on ``power`` +median :ref:`absolute error ` all reals ``predict``, all reals +quantile :ref:`pinball loss ` all reals ``predict``, all reals +mode no consistent one exists reals +================== =================================================== ==================== ================================= + +:sup:`1` The Brier score is just a different name for the squared error in case of +classification. + +:sup:`2` The zero-one loss is only consistent but not strictly consistent for the mode. +The zero-one loss is equivalent to one minus the accuracy score, meaning it gives +different score values but the same ranking. + +:sup:`3` R² gives the same ranking as squared error. + +**Fictitious Example:** +Let's make the above arguments more tangible. Consider a setting in network reliability +engineering, such as maintaining stable internet or Wi-Fi connections. +As provider of the network, you have access to the dataset of log entries of network +connections containing network load over time and many interesting features. +Your goal is to improve the reliability of the connections. +In fact, you promise your customers that on at least 99% of all days there are no +connection discontinuities larger than 1 minute. +Therefore, you are interested in a prediction of the 99% quantile (of longest +connection interruption duration per day) in order to know in advance when to add +more bandwidth and thereby satisfy your customers. So the *target functional* is the +99% quantile. From the table above, you choose the pinball loss as scoring function +(fair enough, not much choice given), for model training (e.g. +`HistGradientBoostingRegressor(loss="quantile", quantile=0.99)`) as well as model +evaluation (`mean_pinball_loss(..., alpha=0.99)` - we apologize for the different +argument names, `quantile` and `alpha`) be it in grid search for finding +hyperparameters or in comparing to other models like +`QuantileRegressor(quantile=0.99)`. + +.. rubric:: References + +.. [Gneiting2007] T. Gneiting and A. E. Raftery. :doi:`Strictly Proper + Scoring Rules, Prediction, and Estimation <10.1198/016214506000001437>` + In: Journal of the American Statistical Association 102 (2007), + pp. 359– 378. + `link to pdf `_ + +.. [Gneiting2009] T. Gneiting. :arxiv:`Making and Evaluating Point Forecasts + <0912.0902>` + Journal of the American Statistical Association 106 (2009): 746 - 762. + +.. [Gneiting2014] T. Gneiting and M. Katzfuss. :doi:`Probabilistic Forecasting + <10.1146/annurev-st atistics-062713-085831>`. In: Annual Review of Statistics and Its Application 1.1 (2014), pp. 125–151. + +.. [Fissler2022] T. Fissler, C. Lorentzen and M. Mayer. :arxiv:`Model + Comparison and Calibration Assessment: User Guide for Consistent Scoring + Functions in Machine Learning and Actuarial Practice. <2202.12780>` + +.. _scoring_api_overview: + +Scoring API overview +==================== + There are 3 different APIs for evaluating the quality of a model's predictions: * **Estimator score method**: Estimators have a ``score`` method providing a default evaluation criterion for the problem they are designed to solve. - This is not discussed on this page, but in each estimator's documentation. + Most commonly this is :ref:`accuracy ` for classifiers and the + :ref:`coefficient of determination ` (:math:`R^2`) for regressors. + Details for each estimator can be found in its documentation. -* **Scoring parameter**: Model-evaluation tools using +* **Scoring parameter**: Model-evaluation tools that use :ref:`cross-validation ` (such as - :func:`model_selection.cross_val_score` and - :class:`model_selection.GridSearchCV`) rely on an internal *scoring* strategy. - This is discussed in the section :ref:`scoring_parameter`. + :class:`model_selection.GridSearchCV`, :func:`model_selection.validation_curve` and + :class:`linear_model.LogisticRegressionCV`) rely on an internal *scoring* strategy. + This can be specified using the `scoring` parameter of that tool and is discussed + in the section :ref:`scoring_parameter`. * **Metric functions**: The :mod:`sklearn.metrics` module implements functions assessing prediction error for specific purposes. These metrics are detailed @@ -38,24 +178,39 @@ value of those metrics for random predictions. The ``scoring`` parameter: defining model evaluation rules ========================================================== -Model selection and evaluation using tools, such as -:class:`model_selection.GridSearchCV` and -:func:`model_selection.cross_val_score`, take a ``scoring`` parameter that +Model selection and evaluation tools that internally use +:ref:`cross-validation ` (such as +:class:`model_selection.GridSearchCV`, :func:`model_selection.validation_curve` and +:class:`linear_model.LogisticRegressionCV`) take a ``scoring`` parameter that controls what metric they apply to the estimators evaluated. -Common cases: predefined values -------------------------------- +They can be specified in several ways: + +* `None`: the estimator's default evaluation criterion (i.e., the metric used in the + estimator's `score` method) is used. +* :ref:`String name `: common metrics can be passed via a string + name. +* :ref:`Callable `: more complex metrics can be passed via a custom + metric callable (e.g., function). + +Some tools do also accept multiple metric evaluation. See :ref:`multimetric_scoring` +for details. + +.. _scoring_string_names: + +String name scorers +------------------- For the most common use cases, you can designate a scorer object with the -``scoring`` parameter; the table below shows all possible values. +``scoring`` parameter via a string name; the table below shows all possible values. All scorer objects follow the convention that **higher return values are better -than lower return values**. Thus metrics which measure the distance between +than lower return values**. Thus metrics which measure the distance between the model and the data, like :func:`metrics.mean_squared_error`, are -available as neg_mean_squared_error which return the negated value +available as 'neg_mean_squared_error' which return the negated value of the metric. ==================================== ============================================== ================================== -Scoring Function Comment +Scoring string name Function Comment ==================================== ============================================== ================================== **Classification** 'accuracy' :func:`metrics.accuracy_score` @@ -123,12 +278,23 @@ Usage examples: .. currentmodule:: sklearn.metrics -.. _scoring: +.. _scoring_callable: + +Callable scorers +---------------- + +For more complex use cases and more flexibility, you can pass a callable to +the `scoring` parameter. This can be done by: + +* :ref:`scoring_adapt_metric` +* :ref:`scoring_custom` (most flexible) -Defining your scoring strategy from metric functions ------------------------------------------------------ +.. _scoring_adapt_metric: -The following metrics functions are not implemented as named scorers, +Adapting predefined metrics via `make_scorer` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following metric functions are not implemented as named scorers, sometimes because they require additional parameters, such as :func:`fbeta_score`. They cannot be passed to the ``scoring`` parameters; instead their callable needs to be passed to @@ -166,15 +332,22 @@ measuring a prediction error given ground truth and prediction: maximize, the higher the better. - functions ending with ``_error``, ``_loss``, or ``_deviance`` return a - value to minimize, the lower the better. When converting + value to minimize, the lower the better. When converting into a scorer object using :func:`make_scorer`, set the ``greater_is_better`` parameter to ``False`` (``True`` by default; see the parameter description below). +.. _scoring_custom: + +Creating a custom scorer object +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. dropdown:: Custom scorer objects +You can create your own custom scorer object using +:func:`make_scorer` or for the most flexibility, from scratch. See below for details. - The second use case is to build a completely custom scorer object +.. dropdown:: Custom scorer objects using `make_scorer` + + You can build a completely custom scorer object from a simple python function using :func:`make_scorer`, which can take several parameters: @@ -182,21 +355,21 @@ measuring a prediction error given ground truth and prediction: in the example below) * whether the python function returns a score (``greater_is_better=True``, - the default) or a loss (``greater_is_better=False``). If a loss, the output + the default) or a loss (``greater_is_better=False``). If a loss, the output of the python function is negated by the scorer object, conforming to the cross validation convention that scorers return higher values for better models. * for classification metrics only: whether the python function you provided requires continuous decision certainties. If the scoring function only accepts probability - estimates (e.g. :func:`metrics.log_loss`) then one needs to set the parameter - `response_method`, thus in this case `response_method="predict_proba"`. Some scoring - function do not necessarily require probability estimates but rather non-thresholded - decision values (e.g. :func:`metrics.roc_auc_score`). In this case, one provides a - list such as `response_method=["decision_function", "predict_proba"]`. In this case, - the scorer will use the first available method, in the order given in the list, + estimates (e.g. :func:`metrics.log_loss`), then one needs to set the parameter + `response_method="predict_proba"`. Some scoring + functions do not necessarily require probability estimates but rather non-thresholded + decision values (e.g. :func:`metrics.roc_auc_score`). In this case, one can provide a + list (e.g., `response_method=["decision_function", "predict_proba"]`), + and scorer will use the first available method, in the order given in the list, to compute the scores. - * any additional parameters, such as ``beta`` or ``labels`` in :func:`f1_score`. + * any additional parameters of the scoring function, such as ``beta`` or ``labels``. Here is an example of building custom scorers, and of using the ``greater_is_better`` parameter:: @@ -220,16 +393,10 @@ measuring a prediction error given ground truth and prediction: >>> score(clf, X, y) -0.69... -.. _diy_scoring: - -Implementing your own scoring object ------------------------------------- +.. dropdown:: Custom scorer objects from scratch -You can generate even more flexible model scorers by constructing your own -scoring object from scratch, without using the :func:`make_scorer` factory. - - -.. dropdown:: How to build a scorer from scratch + You can generate even more flexible model scorers by constructing your own + scoring object from scratch, without using the :func:`make_scorer` factory. For a callable to be a scorer, it needs to meet the protocol specified by the following two rules: @@ -252,24 +419,24 @@ scoring object from scratch, without using the :func:`make_scorer` factory. more details. - .. note:: **Using custom scorers in functions where n_jobs > 1** +.. dropdown:: Using custom scorers in functions where n_jobs > 1 - While defining the custom scoring function alongside the calling function - should work out of the box with the default joblib backend (loky), - importing it from another module will be a more robust approach and work - independently of the joblib backend. + While defining the custom scoring function alongside the calling function + should work out of the box with the default joblib backend (loky), + importing it from another module will be a more robust approach and work + independently of the joblib backend. - For example, to use ``n_jobs`` greater than 1 in the example below, - ``custom_scoring_function`` function is saved in a user-created module - (``custom_scorer_module.py``) and imported:: + For example, to use ``n_jobs`` greater than 1 in the example below, + ``custom_scoring_function`` function is saved in a user-created module + (``custom_scorer_module.py``) and imported:: - >>> from custom_scorer_module import custom_scoring_function # doctest: +SKIP - >>> cross_val_score(model, - ... X_train, - ... y_train, - ... scoring=make_scorer(custom_scoring_function, greater_is_better=False), - ... cv=5, - ... n_jobs=-1) # doctest: +SKIP + >>> from custom_scorer_module import custom_scoring_function # doctest: +SKIP + >>> cross_val_score(model, + ... X_train, + ... y_train, + ... scoring=make_scorer(custom_scoring_function, greater_is_better=False), + ... cv=5, + ... n_jobs=-1) # doctest: +SKIP .. _multimetric_scoring: @@ -2376,7 +2543,7 @@ Here is a small example of usage of the :func:`mean_absolute_error` function:: Mean squared error ------------------- -The :func:`mean_squared_error` function computes `mean square +The :func:`mean_squared_error` function computes `mean squared error `_, a risk metric corresponding to the expected value of the squared (quadratic) error or loss. @@ -2929,15 +3096,14 @@ display. .. _clustering_metrics: Clustering metrics -====================== +================== .. currentmodule:: sklearn.metrics The :mod:`sklearn.metrics` module implements several loss, score, and utility -functions. For more information see the :ref:`clustering_evaluation` -section for instance clustering, and :ref:`biclustering_evaluation` for -biclustering. - +functions to measure clustering performance. For more information see the +:ref:`clustering_evaluation` section for instance clustering, and +:ref:`biclustering_evaluation` for biclustering. .. _dummy_estimators: diff --git a/doc/modules/sgd.rst b/doc/modules/sgd.rst index 824ed4dc1ca13..e44be05d69df9 100644 --- a/doc/modules/sgd.rst +++ b/doc/modules/sgd.rst @@ -402,7 +402,7 @@ We describe here the mathematical details of the SGD procedure. A good overview with convergence rates can be found in [#6]_. Given a set of training examples :math:`(x_1, y_1), \ldots, (x_n, y_n)` where -:math:`x_i \in \mathbf{R}^m` and :math:`y_i \in \mathcal{R}` (:math:`y_i \in +:math:`x_i \in \mathbf{R}^m` and :math:`y_i \in \mathbf{R}` (:math:`y_i \in {-1, 1}` for classification), our goal is to learn a linear scoring function :math:`f(x) = w^T x + b` with model parameters :math:`w \in \mathbf{R}^m` and intercept :math:`b \in \mathbf{R}`. In order to make predictions for binary diff --git a/doc/scss/custom.scss b/doc/scss/custom.scss index f653ff66d4622..381c4173156a4 100644 --- a/doc/scss/custom.scss +++ b/doc/scss/custom.scss @@ -14,15 +14,22 @@ code.literal { /* Version switcher */ -.version-switcher__menu a.list-group-item.sk-avail-docs-link { - display: flex; - align-items: center; +.version-switcher__menu.dropdown-menu { + // The version switcher is aligned right so we need to avoid the dropdown menu + // to be cut off by the right boundary + left: unset; + right: 0; + + a.list-group-item.sk-avail-docs-link { + display: flex; + align-items: center; - &:after { - content: var(--pst-icon-external-link); - font: var(--fa-font-solid); - font-size: 0.75rem; - margin-left: 0.5rem; + &:after { + content: var(--pst-icon-external-link); + font: var(--fa-font-solid); + font-size: 0.75rem; + margin-left: 0.5rem; + } } } diff --git a/doc/templates/index.html b/doc/templates/index.html index 2893718365e2e..0f0cecf7fed96 100644 --- a/doc/templates/index.html +++ b/doc/templates/index.html @@ -206,16 +206,15 @@

News

    -
  • On-going development: scikit-learn 1.6 (Changelog).
  • +
  • On-going development: scikit-learn 1.7 (Changelog).
  • +
  • January 2025. scikit-learn 1.6.1 is available for download (Changelog).
  • +
  • December 2024. scikit-learn 1.6.0 is available for download (Changelog).
  • September 2024. scikit-learn 1.5.2 is available for download (Changelog).
  • July 2024. scikit-learn 1.5.1 is available for download (Changelog).
  • May 2024. scikit-learn 1.5.0 is available for download (Changelog).
  • April 2024. scikit-learn 1.4.2 is available for download (Changelog).
  • February 2024. scikit-learn 1.4.1.post1 is available for download (Changelog).
  • January 2024. scikit-learn 1.4.0 is available for download (Changelog).
  • -
  • October 2023. scikit-learn 1.3.2 is available for download (Changelog).
  • -
  • September 2023. scikit-learn 1.3.1 is available for download (Changelog).
  • -
  • June 2023. scikit-learn 1.3.0 is available for download (Changelog).
  • All releases: What's new (Changelog).
@@ -230,13 +229,13 @@

Community

  • Blog: blog.scikit-learn.org
  • Logos & Branding: logos and branding
  • Calendar: calendar
  • -
  • Twitter: @scikit_learn
  • LinkedIn: linkedin/scikit-learn
  • +
  • Bluesky: bluesky/scikit-learn.org
  • +
  • Mastodon: @sklearn
  • YouTube: youtube.com/scikit-learn
  • Facebook: @scikitlearnofficial
  • Instagram: @scikitlearnofficial
  • TikTok: @scikit.learn
  • -
  • Mastodon: @sklearn
  • Discord: @scikit-learn
  • Communication on all channels should respect PSF's code of conduct.
  • diff --git a/doc/whats_new/_contributors.rst b/doc/whats_new/_contributors.rst index 83f6ca5448b24..c74a2964e57bc 100644 --- a/doc/whats_new/_contributors.rst +++ b/doc/whats_new/_contributors.rst @@ -20,7 +20,7 @@ .. |API| replace:: :raw-html:`API Change` :raw-latex:`{\small\sc [API Change]}` -.. _Olivier Grisel: https://twitter.com/ogrisel +.. _Olivier Grisel: https://bsky.app/profile/ogrisel.bsky.social .. _Gael Varoquaux: http://gael-varoquaux.info diff --git a/doc/whats_new/upcoming_changes/array-api/27096.feature.rst b/doc/whats_new/upcoming_changes/array-api/27096.feature.rst deleted file mode 100644 index da3fada04419a..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/27096.feature.rst +++ /dev/null @@ -1,6 +0,0 @@ -- :class:`model_selection.GridSearchCV`, - :class:`model_selection.RandomizedSearchCV`, - :class:`model_selection.HalvingGridSearchCV` and - :class:`model_selection.HalvingRandomSearchCV` now support Array API - compatible inputs when their base estimators do. - By :user:`Tim Head ` and :user:`Olivier Grisel ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/array-api/27381.feature.rst b/doc/whats_new/upcoming_changes/array-api/27381.feature.rst deleted file mode 100644 index ee3d88b1c588d..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/27381.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -- :class:`preprocessing.LabelEncoder` now supports Array API compatible inputs. - By :user:`Omar Salman ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/array-api/27736.feature.rst b/doc/whats_new/upcoming_changes/array-api/27736.feature.rst deleted file mode 100644 index 9d524d3c8730e..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/27736.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_absolute_error` now supports Array API compatible - inputs. - By :user:`Edoardo Abati ` diff --git a/doc/whats_new/upcoming_changes/array-api/28106.feature.rst b/doc/whats_new/upcoming_changes/array-api/28106.feature.rst deleted file mode 100644 index 34fb6341a3076..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/28106.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_tweedie_deviance` now supports Array API - compatible inputs. - By :user:`Thomas Li ` diff --git a/doc/whats_new/upcoming_changes/array-api/29014.feature.rst b/doc/whats_new/upcoming_changes/array-api/29014.feature.rst deleted file mode 100644 index a60fe1f0cd2cf..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29014.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.cosine_similarity` now supports Array API - compatible inputs. - By :user:`Edoardo Abati ` diff --git a/doc/whats_new/upcoming_changes/array-api/29112.feature.rst b/doc/whats_new/upcoming_changes/array-api/29112.feature.rst deleted file mode 100644 index 4fdf49f36ea3b..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29112.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.paired_cosine_distances` now supports Array - API compatible inputs. - By :user:`Edoardo Abati ` diff --git a/doc/whats_new/upcoming_changes/array-api/29141.feature.rst b/doc/whats_new/upcoming_changes/array-api/29141.feature.rst deleted file mode 100644 index 40ba1c8f022e4..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29141.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.cluster.entropy` now supports Array API compatible - inputs. - By :user:`Yaroslav Korobko ` diff --git a/doc/whats_new/upcoming_changes/array-api/29142.feature.rst b/doc/whats_new/upcoming_changes/array-api/29142.feature.rst deleted file mode 100644 index 7c731abdbdb07..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29142.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_squared_error` now supports Array API compatible - inputs. - By :user:`Yaroslav Korobko ` diff --git a/doc/whats_new/upcoming_changes/array-api/29144.feature.rst b/doc/whats_new/upcoming_changes/array-api/29144.feature.rst deleted file mode 100644 index 397f56d301919..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29144.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.additive_chi2_kernel` now supports Array API - compatible inputs. - By :user:`Yaroslav Korobko ` diff --git a/doc/whats_new/upcoming_changes/array-api/29207.feature.rst b/doc/whats_new/upcoming_changes/array-api/29207.feature.rst deleted file mode 100644 index 8223cb6c453b6..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29207.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.d2_tweedie_score` now supports Array API compatible - inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29212.feature.rst b/doc/whats_new/upcoming_changes/array-api/29212.feature.rst deleted file mode 100644 index dc1fda61ca3c7..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29212.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -- :func:`sklearn.metrics.max_error` now supports Array API compatible inputs. - By :user:`Edoardo Abati ` diff --git a/doc/whats_new/upcoming_changes/array-api/29227.feature.rst b/doc/whats_new/upcoming_changes/array-api/29227.feature.rst deleted file mode 100644 index 7756ba99fd1c5..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29227.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_poisson_deviance` now supports Array API - compatible inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29239.feature.rst b/doc/whats_new/upcoming_changes/array-api/29239.feature.rst deleted file mode 100644 index 1e147a329e21e..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29239.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_gamma_deviance` now supports Array API compatible - inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29265.feature.rst b/doc/whats_new/upcoming_changes/array-api/29265.feature.rst deleted file mode 100644 index 880c3017ab5c5..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29265.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.cosine_distances` now supports Array API - compatible inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29267.feature.rst b/doc/whats_new/upcoming_changes/array-api/29267.feature.rst deleted file mode 100644 index 2ef45d79666a4..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29267.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.chi2_kernel` now supports Array API - compatible inputs. - By :user:`Yaroslav Korobko ` diff --git a/doc/whats_new/upcoming_changes/array-api/29300.feature.rst b/doc/whats_new/upcoming_changes/array-api/29300.feature.rst deleted file mode 100644 index 77a4f6896ae55..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29300.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.mean_absolute_percentage_error` now supports Array API - compatible inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29389.feature.rst b/doc/whats_new/upcoming_changes/array-api/29389.feature.rst deleted file mode 100644 index c19dd95f3a5c1..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29389.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.pairwise.paired_euclidean_distances` now supports - Array API compatible inputs. - By :user:`Emily Chen ` diff --git a/doc/whats_new/upcoming_changes/array-api/29433.feature.rst b/doc/whats_new/upcoming_changes/array-api/29433.feature.rst deleted file mode 100644 index 39ea6aa36dc70..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29433.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`sklearn.metrics.pairwise.euclidean_distances` and - :func:`sklearn.metrics.pairwise.rbf_kernel` now supports Array API compatible - inputs. - By :user:`Omar Salman ` diff --git a/doc/whats_new/upcoming_changes/array-api/29475.feature.rst b/doc/whats_new/upcoming_changes/array-api/29475.feature.rst deleted file mode 100644 index 5336507fe5692..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29475.feature.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :func:`sklearn.metrics.pairwise.linear_kernel`, - :func:`sklearn.metrics.pairwise.sigmoid_kernel`, and - :func:`sklearn.metrics.pairwise.polynomial_kernel` now supports Array API - compatible inputs. - By :user:`Omar Salman ` diff --git a/doc/whats_new/upcoming_changes/array-api/29639.other.rst b/doc/whats_new/upcoming_changes/array-api/29639.other.rst deleted file mode 100644 index 6bb7ac8045841..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29639.other.rst +++ /dev/null @@ -1,4 +0,0 @@ -- Support for the soon to be deprecated `cupy.array_api` module has been - removed in favor of directly supporting the top level `cupy` module, possibly - via the `array_api_compat.cupy` compatibility wrapper. - By :user:`Olivier Grisel ` diff --git a/doc/whats_new/upcoming_changes/array-api/29709.feature.rst b/doc/whats_new/upcoming_changes/array-api/29709.feature.rst deleted file mode 100644 index 027d36cd11bd2..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29709.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`sklearn.metrics.mean_squared_log_error` and - :func:`sklearn.metrics.root_mean_squared_log_error` - now supports Array API compatible inputs. - By :user:`Virgil Chan ` diff --git a/doc/whats_new/upcoming_changes/array-api/29751.feature.rst b/doc/whats_new/upcoming_changes/array-api/29751.feature.rst deleted file mode 100644 index db19c084fb8dd..0000000000000 --- a/doc/whats_new/upcoming_changes/array-api/29751.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`preprocessing.MinMaxScaler` with `clip=True` now supports Array API - compatible inputs. - By :user:`Shreekant Nandiyawar ` diff --git a/doc/whats_new/upcoming_changes/custom-top-level/29128.other.rst b/doc/whats_new/upcoming_changes/custom-top-level/29128.other.rst deleted file mode 100644 index 8eb4c92cc53f8..0000000000000 --- a/doc/whats_new/upcoming_changes/custom-top-level/29128.other.rst +++ /dev/null @@ -1,7 +0,0 @@ -Dropping official support for PyPy ----------------------------------- - -Due to limited maintainer resources and small number of users, official PyPy -support has been dropped. Some parts of scikit-learn may still work but PyPy is -not tested anymore in the scikit-learn Continuous Integration. -By :user:`Loïc Estève ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/custom-top-level/29400.other.rst b/doc/whats_new/upcoming_changes/custom-top-level/29400.other.rst deleted file mode 100644 index a1689f37d28d9..0000000000000 --- a/doc/whats_new/upcoming_changes/custom-top-level/29400.other.rst +++ /dev/null @@ -1,7 +0,0 @@ -Dropping support for building with setuptools ---------------------------------------------- - -From scikit-learn 1.6 onwards, support for building with setuptools has been -removed. Meson is the only supported way to build scikit-learn, see -:ref:`Building from source ` for more details. -By :user:`Loïc Estève ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/many-modules/29677.enhancement.rst b/doc/whats_new/upcoming_changes/many-modules/29677.enhancement.rst deleted file mode 100644 index 112cf0782379e..0000000000000 --- a/doc/whats_new/upcoming_changes/many-modules/29677.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- `__sklearn_tags__` was introduced for setting tags in estimators. - More details in :ref:`estimator_tags`. - By :user:`Thomas Fan ` and :user:`Adrin Jalali ` diff --git a/doc/whats_new/upcoming_changes/many-modules/29696.api.rst b/doc/whats_new/upcoming_changes/many-modules/29696.api.rst deleted file mode 100644 index ab397ff000b72..0000000000000 --- a/doc/whats_new/upcoming_changes/many-modules/29696.api.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :func:`utils.validation.validate_data` is introduced and replaces previously - private `base.BaseEstimator._validate_data` method. This is intended for third party - estimator developers, who should use this function in most cases instead of - :func:`utils.validation.check_array` and :func:`utils.validation.check_X_y`. - By :user:`Adrin Jalali ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/many-modules/29793.enhancement.rst b/doc/whats_new/upcoming_changes/many-modules/29793.enhancement.rst deleted file mode 100644 index 514aa97e391cc..0000000000000 --- a/doc/whats_new/upcoming_changes/many-modules/29793.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Scikit-learn classes and functions can be used while only having a - `import sklearn` import line. For example, `import sklearn; sklearn.svm.SVC()` now works. - By :user:`Thomas Fan ` diff --git a/doc/whats_new/upcoming_changes/many-modules/30023.fix.rst b/doc/whats_new/upcoming_changes/many-modules/30023.fix.rst deleted file mode 100644 index c91267804fc1b..0000000000000 --- a/doc/whats_new/upcoming_changes/many-modules/30023.fix.rst +++ /dev/null @@ -1,6 +0,0 @@ -- Classes :class:`metrics.ConfusionMatrixDisplay`, - :class:`metrics.RocCurveDisplay`, :class:`calibration.CalibrationDisplay`, - :class:`metrics.PrecisionRecallDisplay`, :class:`metrics.PredictionErrorDisplay` and - :class:`inspection.PartialDependenceDisplay` now properly handle Matplotlib aliases - for style parameters (e.g., `c` and `color`, `ls` and `linestyle`, etc). - By :user:`Joseph Barbier ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/28494.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/28494.feature.rst deleted file mode 100644 index 92e8b0617711a..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/28494.feature.rst +++ /dev/null @@ -1,7 +0,0 @@ -- :class:`semi_supervised.SelfTrainingClassifier` - now supports metadata routing. The fit method now accepts ``**fit_params`` - which are passed to the underlying estimators via their `fit` methods. - In addition, the `predict`, `predict_proba`, `predict_log_proba`, `score` - and `decision_function` methods also accept ``**params`` which are - passed to the underlying estimators via their respective methods. - By :user:`Adam Li ` diff --git a/doc/whats_new/upcoming_changes/metadata-routing/28701.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/28701.feature.rst deleted file mode 100644 index abef6f8128f6f..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/28701.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`ensemble.StackingClassifier` and - :class:`ensemble.StackingRegressor` now support metadata routing and pass - ``**fit_params`` to the underlying estimators via their `fit` methods. - By :user:`Stefanie Senger ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/28975.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/28975.feature.rst deleted file mode 100644 index a9baf1222a14e..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/28975.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`model_selection.learning_curve` now supports metadata routing for the - `fit` method of its estimator and for its underlying CV splitter and scorer. - By :user:`Stefanie Senger ` diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29136.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/29136.feature.rst deleted file mode 100644 index 280a41ac87eed..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29136.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`compose.TransformedTargetRegressor` now supports metadata - routing in its `fit` and `predict` methods and routes the corresponding - params to the underlying regressor. - By :user:`Omar Salman ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29260.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/29260.feature.rst deleted file mode 100644 index 8be997b7093fd..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29260.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`feature_selection.SequentialFeatureSelector` now supports - metadata routing in its `fit` method and passes the corresponding params to - the :func:`model_selection.cross_val_score` function. - By :user:`Omar Salman ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29266.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/29266.feature.rst deleted file mode 100644 index b5b1d6ca06231..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29266.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`model_selection.permutation_test_score` now supports metadata routing - for the `fit` method of its estimator and for its underlying CV splitter and scorer. - By :user:`Adam Li ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29312.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/29312.feature.rst deleted file mode 100644 index f7fb95bb791ce..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29312.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`feature_selection.RFE` and :class:`feature_selection.RFECV` - now support metadata routing. - By :user:`Omar Salman ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29329.feature.rst b/doc/whats_new/upcoming_changes/metadata-routing/29329.feature.rst deleted file mode 100644 index d36023de06b80..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29329.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`model_selection.validation_curve` now supports metadata routing for - the `fit` method of its estimator and for its underlying CV splitter and scorer. - By :user:`Stefanie Senger ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29634.fix.rst b/doc/whats_new/upcoming_changes/metadata-routing/29634.fix.rst deleted file mode 100644 index a8276c6053ad7..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29634.fix.rst +++ /dev/null @@ -1,5 +0,0 @@ -- Metadata is routed correctly to grouped CV splitters via - :class:`linear_model.RidgeCV` and :class:`linear_model.RidgeClassifierCV` and - `UnsetMetadataPassedError` is fixed for :class:`linear_model.RidgeClassifierCV` with - default scoring. - By :user:`Stefanie Senger ` diff --git a/doc/whats_new/upcoming_changes/metadata-routing/29920.fix.rst b/doc/whats_new/upcoming_changes/metadata-routing/29920.fix.rst deleted file mode 100644 index a15a66ce6c74f..0000000000000 --- a/doc/whats_new/upcoming_changes/metadata-routing/29920.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Many method arguments which shouldn't be included in the routing mechanism are - now excluded and the `set_{method}_request` methods are not generated for them. - By `Adrin Jalali`_ diff --git a/doc/whats_new/upcoming_changes/sklearn.base/28936.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.base/28936.enhancement.rst deleted file mode 100644 index 28fb9f1ac2f5e..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.base/28936.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Added a function :func:`base.is_clusterer` which determines whether a given - estimator is of category clusterer. - By :user:`Christian Veenhuis ` diff --git a/doc/whats_new/upcoming_changes/sklearn.base/30122.api.rst b/doc/whats_new/upcoming_changes/sklearn.base/30122.api.rst deleted file mode 100644 index 370a2adc1996d..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.base/30122.api.rst +++ /dev/null @@ -1,5 +0,0 @@ -- Passing a class object to:func:`~sklearn.base.is_classifier`, - :func:`~sklearn.base.is_regressor`, :func:`~sklearn.base.is_transformer`, and - :func:`~sklearn.base.is_outlier_detector` is now deprecated. Pass an instance - instead. - By `Adrin Jalali`_ diff --git a/doc/whats_new/upcoming_changes/sklearn.calibration/30171.api.rst b/doc/whats_new/upcoming_changes/sklearn.calibration/30171.api.rst deleted file mode 100644 index 4d550af598278..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.calibration/30171.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- `cv="prefit"` is deprecated for :class:`~sklearn.calibration.CalibratedClassifierCV`. - Use :class:`~sklearn.frozen.FrozenEstimator` instead, as - `CalibratedClassifierCV(FrozenEstimator(estimator))`. - By `Adrin Jalali`_. diff --git a/doc/whats_new/upcoming_changes/sklearn.cluster/29124.api.rst b/doc/whats_new/upcoming_changes/sklearn.cluster/29124.api.rst deleted file mode 100644 index 422679cd29081..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.cluster/29124.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- The `copy` parameter of :class:`cluster.Birch` was deprecated in 1.6 and will be - removed in 1.8. It has no effect as the estimator does not perform in-place operations - on the input data. - By :user:`Yao Xiao ` diff --git a/doc/whats_new/upcoming_changes/sklearn.compose/28934.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.compose/28934.enhancement.rst deleted file mode 100644 index 627d1e051f1ad..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.compose/28934.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.compose.ColumnTransformer` `verbose_feature_names_out` - now accepts string format or callable to generate feature names. - By :user:`Marc Bresson ` diff --git a/doc/whats_new/upcoming_changes/sklearn.covariance/29835.efficiency.rst b/doc/whats_new/upcoming_changes/sklearn.covariance/29835.efficiency.rst deleted file mode 100644 index 5efd3168006c3..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.covariance/29835.efficiency.rst +++ /dev/null @@ -1,2 +0,0 @@ -- :class:`covariance.MinCovDet` fitting is now slightly faster. - By :user:`Antony Lee ` diff --git a/doc/whats_new/upcoming_changes/sklearn.cross_decomposition/29710.fix.rst b/doc/whats_new/upcoming_changes/sklearn.cross_decomposition/29710.fix.rst deleted file mode 100644 index 75617a70cd234..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.cross_decomposition/29710.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`cross_decomposition.PLSRegression` properly raises an error when - `n_components` is larger than `n_samples`. - By :user:`Thomas Fan ` diff --git a/doc/whats_new/upcoming_changes/sklearn.datasets/29354.feature.rst b/doc/whats_new/upcoming_changes/sklearn.datasets/29354.feature.rst deleted file mode 100644 index df32a47288fd2..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.datasets/29354.feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`datasets.fetch_file` allows downloading arbitrary data-file - from the web. It handles local caching, integrity checks with SHA256 digests - and automatic retries in case of HTTP errors. - By :user:`Olivier Grisel ` diff --git a/doc/whats_new/upcoming_changes/sklearn.decomposition/30097.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.decomposition/30097.enhancement.rst deleted file mode 100644 index 6e636d78cdbf9..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.decomposition/30097.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`~sklearn.decomposition.LatentDirichletAllocation` now has a - ``normalize`` parameter in ``transform`` and ``fit_transform`` methods - to control whether the document topic distribution is normalized. - By `Adrin Jalali`_. diff --git a/doc/whats_new/upcoming_changes/sklearn.decomposition/30224.fix.rst b/doc/whats_new/upcoming_changes/sklearn.decomposition/30224.fix.rst deleted file mode 100644 index e325431c6e88f..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.decomposition/30224.fix.rst +++ /dev/null @@ -1,6 +0,0 @@ -- :class:`~sklearn.decomposition.IncrementalPCA` - will now only raise a ``ValueError`` when the number of samples in the - input data to ``partial_fit`` is less than the number of components - on the first call to ``partial_fit``. Subsequent calls to ``partial_fit`` - no longer face this restriction. - By :user:`Thomas Gessey-Jones ` diff --git a/doc/whats_new/upcoming_changes/sklearn.discriminant_analysis/19731.fix.rst b/doc/whats_new/upcoming_changes/sklearn.discriminant_analysis/19731.fix.rst deleted file mode 100644 index db446f82fa602..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.discriminant_analysis/19731.fix.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`discriminant_analysis.QuadraticDiscriminantAnalysis` - will now cause `LinAlgWarning` in case of collinear variables. These errors - can be silenced using the `reg_param` attribute. - By :user:`Alihan Zihna ` diff --git a/doc/whats_new/upcoming_changes/sklearn.ensemble/28064.efficiency.rst b/doc/whats_new/upcoming_changes/sklearn.ensemble/28064.efficiency.rst deleted file mode 100644 index 745efedc598c0..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.ensemble/28064.efficiency.rst +++ /dev/null @@ -1,5 +0,0 @@ -- Small runtime improvement of fitting - :class:`ensemble.HistGradientBoostingClassifier` and - :class:`ensemble.HistGradientBoostingRegressor` by parallelizing the initial search - for bin thresholds. - By :user:`Christian Lorentzen ` diff --git a/doc/whats_new/upcoming_changes/sklearn.ensemble/28179.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.ensemble/28179.enhancement.rst deleted file mode 100644 index c40415072a3d1..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.ensemble/28179.enhancement.rst +++ /dev/null @@ -1,5 +0,0 @@ -- The verbosity of :class:`ensemble.HistGradientBoostingClassifier` - and :class:`ensemble.HistGradientBoostingRegressor` got a more granular control. Now, - `verbose = 1` prints only summary messages, `verbose >= 2` prints the full - information as before. - By :user:`Christian Lorentzen ` diff --git a/doc/whats_new/upcoming_changes/sklearn.ensemble/28268.feature.rst b/doc/whats_new/upcoming_changes/sklearn.ensemble/28268.feature.rst deleted file mode 100644 index 886cd53abbd77..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.ensemble/28268.feature.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :class:`ensemble.ExtraTreesClassifier` and - :class:`ensemble.ExtraTreesRegressor` now support missing-values in the data matrix - `X`. Missing-values are handled by randomly moving all of the samples to the left, or - right child node as the tree is traversed. - By :user:`Adam Li ` diff --git a/doc/whats_new/upcoming_changes/sklearn.ensemble/28622.efficiency.rst b/doc/whats_new/upcoming_changes/sklearn.ensemble/28622.efficiency.rst deleted file mode 100644 index a73b03940749b..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.ensemble/28622.efficiency.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`ensemble.IsolationForest` now runs parallel jobs - during :term:`predict` offering a speedup of up to 2-4x on sample sizes - larger than 2000 using `joblib`. - By :user:`Adam Li ` and :user:`Sérgio Pereira ` diff --git a/doc/whats_new/upcoming_changes/sklearn.ensemble/29997.api.rst b/doc/whats_new/upcoming_changes/sklearn.ensemble/29997.api.rst deleted file mode 100644 index 5dce72e8eb951..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.ensemble/29997.api.rst +++ /dev/null @@ -1,3 +0,0 @@ -- The parameter `algorithm` of :class:`ensemble.AdaBoostClassifier` is deprecated - and will be removed in 1.8. - By :user:`Jérémie du Boisberranger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.feature_extraction/30022.fix.rst b/doc/whats_new/upcoming_changes/sklearn.feature_extraction/30022.fix.rst deleted file mode 100644 index cec576a7158b0..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.feature_extraction/30022.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`feature_extraction.text.TfidfVectorizer` now correctly preserves the - `dtype` of `idf_` based on the input data. - By :user:`Guillaume Lemaitre ` diff --git a/doc/whats_new/upcoming_changes/sklearn.frozen/29705.major-feature.rst b/doc/whats_new/upcoming_changes/sklearn.frozen/29705.major-feature.rst deleted file mode 100644 index e94a50efd86fa..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.frozen/29705.major-feature.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`~sklearn.frozen.FrozenEstimator` is now introduced which allows - freezing an estimator. This means calling `.fit` on it has no effect, and doing a - `clone(frozenestimator)` returns the same estimator instead of an unfitted clone. - :pr:`29705` By `Adrin Jalali`_ diff --git a/doc/whats_new/upcoming_changes/sklearn.impute/29135.fix.rst b/doc/whats_new/upcoming_changes/sklearn.impute/29135.fix.rst deleted file mode 100644 index 613c583ae17d6..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.impute/29135.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`impute.KNNImputer` excludes samples with nan distances when - computing the mean value for uniform weights. - By :user:`Xuefeng Xu ` diff --git a/doc/whats_new/upcoming_changes/sklearn.impute/29451.fix.rst b/doc/whats_new/upcoming_changes/sklearn.impute/29451.fix.rst deleted file mode 100644 index fe2551736f698..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.impute/29451.fix.rst +++ /dev/null @@ -1,4 +0,0 @@ -- When `min_value` and `max_value` are array-like and some features are dropped due to - `keep_empty_features=False`, :class:`impute.IterativeImputer` no longer raises an - error and now indexes correctly. - By :user:`Guntitat Sawadwuthikul ` diff --git a/doc/whats_new/upcoming_changes/sklearn.impute/29779.fix.rst b/doc/whats_new/upcoming_changes/sklearn.impute/29779.fix.rst deleted file mode 100644 index 919990bfc18d6..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.impute/29779.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Fixed :class:`impute.IterativeImputer` to make sure that it does not skip - the iterative process when `keep_empty_features` is set to `True`. - By :user:`Arif Qodari ` diff --git a/doc/whats_new/upcoming_changes/sklearn.impute/29950.api.rst b/doc/whats_new/upcoming_changes/sklearn.impute/29950.api.rst deleted file mode 100644 index 27ac9e06ac320..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.impute/29950.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- Add a warning in :class:`impute.SimpleImputer` when `keep_empty_feature=False` and - `strategy="constant"`. In this case empty features are not dropped and this behaviour - will change in 1.8. - By :user:`Arthur Courselle ` and :user:`Simon Riou ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/19746.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/19746.fix.rst deleted file mode 100644 index 6508ca562afe1..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/19746.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- In :class:`linear_model.Ridge` and :class:`linear_model.RidgeCV`, after `fit`, - the `coef_` attribute is now of shape `(n_samples,)` like other linear models. - By :user:`Maxwell Liu`, `Guillaume Lemaitre`_, and `AdrinJalali`_ diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/28840.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/28840.enhancement.rst deleted file mode 100644 index 2180034ef76b8..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/28840.enhancement.rst +++ /dev/null @@ -1,5 +0,0 @@ -- The `solver="newton-cholesky"` in - :class:`linear_model.LogisticRegression` and - :class:`linear_model.LogisticRegressionCV` is extended to support the full - multinomial loss in a multiclass setting. - By :user:`Christian Lorentzen `. diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29105.api.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29105.api.rst deleted file mode 100644 index fbc4f970d78a1..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29105.api.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Deprecates `copy_X` in :class:`linear_model.TheilSenRegressor` as the parameter - has no effect. `copy_X` will be removed in 1.8. - By :user:`Adam Li ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29419.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29419.fix.rst deleted file mode 100644 index 6f7fe7b4840b4..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29419.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`linear_model.LogisticRegressionCV` corrects sample weight handling - for the calculation of test scores. - By :user:`Shruti Nath ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29442.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29442.fix.rst deleted file mode 100644 index 0c77bae1a1a49..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29442.fix.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`linear_model.LassoCV` and :class:`linear_model.ElasticNetCV` now - take sample weights into accounts to define the search grid for the internally tuned - `alpha` hyper-parameter. - By :user:`John Hopfensperger ` and :user:`Shruti Nath ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29818.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29818.fix.rst deleted file mode 100644 index 4efda13bc481d..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29818.fix.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :class:`linear_model.LogisticRegression`, :class:`linear_model.PoissonRegressor`, - :class:`linear_model.GammaRegressor`, :class:`linear_model.TweedieRegressor` - now take sample weights into account to decide when to fall back to `solver='lbfgs'` - whenever `solver='newton-cholesky'` becomes numerically unstable. - By :user:`Antoine Baker ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29842.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29842.fix.rst deleted file mode 100644 index a47dee6674124..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29842.fix.rst +++ /dev/null @@ -1,8 +0,0 @@ -- :class:`linear_model.RidgeCV` now properly uses predictions on the same scale as - the target seen during `fit`. These predictions are stored in `cv_results_` when - `scoring != None`. Previously, the predictions were rescaled by the square root of the - sample weights and offset by the mean of the target, leading to an incorrect estimate - of the score. - By :user:`Guillaume Lemaitre `, - :user:`Jérôme Dockes ` and - :user:`Hanmin Qin ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/29884.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/29884.fix.rst deleted file mode 100644 index bbff81b662be9..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/29884.fix.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :class:`linear_model.RidgeCV` now properly supports custom multioutput scorers - by letting the scorer manage the multioutput averaging. Previously, the predictions - and true targets were both squeezed to a 1D array before computing the error. - By :user:`Guillaume Lemaitre ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/30040.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/30040.fix.rst deleted file mode 100644 index f4a91911345e3..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/30040.fix.rst +++ /dev/null @@ -1,6 +0,0 @@ -- :class:`linear_model.LinearRegression` now sets the `cond` parameter when - calling the `scipy.linalg.lstsq` solver on dense input data. This ensures - more numerically robust results on rank-deficient data. In particular, it - empirically fixes the expected equivalence property between fitting with - reweighted or with repeated data points. - :pr:`30040` by :user:`Antoine Baker `. diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/30100.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/30100.fix.rst deleted file mode 100644 index 4ec508ad984a2..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/30100.fix.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :class:`linear_model.LogisticRegression` and and other linear models that - accept `solver="newton-cholesky"` now report the correct number of iterations - when they fall back to the `"lbfgs"` solver because of a rank deficient - Hessian matrix. - By :user:`Olivier Grisel ` diff --git a/doc/whats_new/upcoming_changes/sklearn.linear_model/30227.fix.rst b/doc/whats_new/upcoming_changes/sklearn.linear_model/30227.fix.rst deleted file mode 100644 index d3a76ced7fc6b..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.linear_model/30227.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`~sklearn.linear_model.SGDOneClassSVM` now correctly inherits from - :class:`~sklearn.base.OutlierMixin` and the tags are correctly set. - By :user:`Guillaume Lemaitre ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.manifold/28096.efficiency.rst b/doc/whats_new/upcoming_changes/sklearn.manifold/28096.efficiency.rst deleted file mode 100644 index f5d7001b08657..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.manifold/28096.efficiency.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`manifold.locally_linear_embedding` and - :class:`manifold.LocallyLinearEmbedding` now allocate more efficiently the memory of - sparse matrices in the Hessian, Modified and LTSA methods. - By :user:`Giorgio Angelotti ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/26367.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/26367.enhancement.rst deleted file mode 100644 index 0fc5bd059c42f..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/26367.enhancement.rst +++ /dev/null @@ -1,6 +0,0 @@ -- :meth:`metrics.RocCurveDisplay.from_estimator`, - :meth:`metrics.RocCurveDisplay.from_predictions`, - :meth:`metrics.PrecisionRecallDisplay.from_estimator`, and - :meth:`metrics.PrecisionRecallDisplay.from_predictions` now accept a new keyword - `despine` to remove the top and right spines of the plot in order to make it clearer. - By :user:`Yao Xiao `. \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/27412.fix.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/27412.fix.rst deleted file mode 100644 index 350bd92a19478..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/27412.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`metrics.roc_auc_score` will now correctly return np.nan and - warn user if only one class is present in the labels. - By :user:`Gleb Levitski ` and :user:`Janez Demšar ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/28509.feature.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/28509.feature.rst deleted file mode 100644 index 755d586dbce2b..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/28509.feature.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Adds `zero_division` to :func:`metrics.matthews_corrcoef`. - When there is a zero division, the metric is undefined and this value is returned. - By :user:`Marc Torrellas Socastro ` and :user:`Noam Keidar ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/28992.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/28992.enhancement.rst deleted file mode 100644 index 9900a4ec153c0..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/28992.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`sklearn.metrics.check_scoring` now accepts `raise_exc` to specify - whether to raise an exception if a subset of the scorers in multimetric scoring fails - or to return an error code. - By :user:`Stefanie Senger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29210.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29210.enhancement.rst deleted file mode 100644 index 82059b4ba50f7..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29210.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- Adds `zero_division` to :func:`cohen_kappa_score`. When there is a - division by zero, the metric is undefined and this value is returned. - By :user:`Marc Torrellas Socastro ` and - :user:`Stefanie Senger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29213.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29213.enhancement.rst deleted file mode 100644 index 35ad57056050d..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29213.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.accuracy_score` now includes a `zero_division` - parameter to raise a warning when `y_true` and `y_pred` are empty. - By :user:`Jaimin Chauhan `. diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29404.api.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29404.api.rst deleted file mode 100644 index 720f74cde7e8b..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29404.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- The `assert_all_finite` parameter of functions - :func:`metrics.pairwise.check_pairwise_arrays` and :func:`metrics.pairwise_distances` - is renamed into `ensure_all_finite`. `force_all_finite` will be removed in 1.8. - By :user:`Jérémie du Boisberranger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29462.api.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29462.api.rst deleted file mode 100644 index 501b8aa9f8681..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29462.api.rst +++ /dev/null @@ -1,3 +0,0 @@ -- `scoring="neg_max_error"` should be used instead of `scoring="max_error"` - which is now deprecated. - By :user:`Farid "Freddie" Taba ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29709.fix.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29709.fix.rst deleted file mode 100644 index a74576af1326b..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29709.fix.rst +++ /dev/null @@ -1,8 +0,0 @@ -- The functions :func:`metrics.mean_squared_log_error` and - :func:`metrics.root_mean_squared_log_error` now check whether the inputs are within - the correct domain for the function :math:`y=\log(1+x)`, rather than - :math:`y=\log(x)`. The functions :func:`metrics.mean_absolute_error`, - :func:`metrics.mean_absolute_percentage_error`, :func:`metrics.mean_squared_error` - and :func:`metrics.root_mean_squared_error` now explicitly check whether a scalar - will be returned when `multioutput=uniform_average`. - By :user:`Virgil Chan ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/29738.efficiency.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/29738.efficiency.rst deleted file mode 100644 index 66ab06d915e45..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/29738.efficiency.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`sklearn.metrics.classification_report` is now faster by caching - classification labels. - By :user:`Adrin Jalali ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/30001.api.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/30001.api.rst deleted file mode 100644 index 9209f4ae0a897..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/30001.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- The default value of the `response_method` parameter of - :func:`metrics.make_scorer` will change from `None` to `"predict"` and `None` will be - removed in 1.8. In the mean time, `None` is equivalent to `"predict"`. - By :user:`Jérémie du Boisberranger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.metrics/30013.fix.rst b/doc/whats_new/upcoming_changes/sklearn.metrics/30013.fix.rst deleted file mode 100644 index 4cee2ec523fb8..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.metrics/30013.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :func:`metrics.roc_auc_score` will now correctly return np.nan and - warn user if only one class is present in the labels. - By :user:`Gleb Levitski ` and :user:`Janez Demšar ` \ No newline at end of file diff --git a/doc/whats_new/upcoming_changes/sklearn.model_selection/28519.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.model_selection/28519.enhancement.rst deleted file mode 100644 index 72098ca04ead5..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.model_selection/28519.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`~model_selection.GroupKFold` now has the ability to shuffle groups into - different folds when `shuffle=True`. - By :user:`Zachary Vealey ` diff --git a/doc/whats_new/upcoming_changes/sklearn.model_selection/29402.fix.rst b/doc/whats_new/upcoming_changes/sklearn.model_selection/29402.fix.rst deleted file mode 100644 index 3e2ea0259c7a2..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.model_selection/29402.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Improve error message when :func:`model_selection.RepeatedStratifiedKFold.split` - is called without a `y` argument - By :user:`Anurag Varma ` diff --git a/doc/whats_new/upcoming_changes/sklearn.model_selection/30172.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.model_selection/30172.enhancement.rst deleted file mode 100644 index 266525cf5ba24..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.model_selection/30172.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- There is no need to call `fit` on a - :class:`~sklearn.model_selection.FixedThresholdClassifier` if the underlying - estimator is already fitted. - By :user:`Adrin Jalali ` diff --git a/doc/whats_new/upcoming_changes/sklearn.neighbors/25330.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.neighbors/25330.enhancement.rst deleted file mode 100644 index ed95889127afc..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.neighbors/25330.enhancement.rst +++ /dev/null @@ -1,6 +0,0 @@ -- :class:`neighbors.NearestNeighbors`, :class:`KNeighborsClassifier`, - :class:`KNeighborsRegressor`, :class:`RadiusNeighborsClassifier`, - :class:`RadiusNeighborsRegressor`, :class:`KNeighborsTransformer`, - :class:`RadiusNeighborsTransformer`, and :class:`LocalOutlierFactor` - now work with `metric="nan_euclidean"`, supporting `nan` inputs. - By :user:`Carlo Lemos `, `Guillaume Lemaitre`_, and `Adrin Jalali`_ diff --git a/doc/whats_new/upcoming_changes/sklearn.neighbors/26689.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.neighbors/26689.enhancement.rst deleted file mode 100644 index ebc50d1bc6aaa..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.neighbors/26689.enhancement.rst +++ /dev/null @@ -1,7 +0,0 @@ -- Add :meth:`neighbors.NearestCentroid.decision_function`, - :meth:`neighbors.NearestCentroid.predict_proba` and - :meth:`neighbors.NearestCentroid.predict_log_proba` - to the :class:`neighbors.NearestCentroid` estimator class. - Support the case when `X` is sparse and `shrinking_threshold` - is not `None` in :class:`neighbors.NearestCentroid`. - By :user:`Matthew Ning ` diff --git a/doc/whats_new/upcoming_changes/sklearn.neighbors/28773.fix.rst b/doc/whats_new/upcoming_changes/sklearn.neighbors/28773.fix.rst deleted file mode 100644 index 5810ae80f0b90..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.neighbors/28773.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`neighbors.LocalOutlierFactor` raises a warning in the `fit` method - when duplicate values in the training data lead to inaccurate outlier detection. - By :user:`Henrique Caroço ` diff --git a/doc/whats_new/upcoming_changes/sklearn.neighbors/30047.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.neighbors/30047.enhancement.rst deleted file mode 100644 index ed91b39ed2e0d..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.neighbors/30047.enhancement.rst +++ /dev/null @@ -1,6 +0,0 @@ -- Make `predict`, `predict_proba`, and `score` of - :class:`neighbors.KNeighborsClassifier` and - :class:`neighbors.RadiusNeighborsClassifier` accept `X=None` as input. In this case - predictions for all training set points are returned, and points are not included - into their own neighbors. - :pr:`30047` by :user:`Dmitry Kobak `. diff --git a/doc/whats_new/upcoming_changes/sklearn.neural_network/29773.fix.rst b/doc/whats_new/upcoming_changes/sklearn.neural_network/29773.fix.rst deleted file mode 100644 index 9f4e23af1fbc4..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.neural_network/29773.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`neural_network.MLPRegressor` does no longer crash when the model - diverges and that `early_stopping` is enabled. - By :user:`Marc Bresson ` diff --git a/doc/whats_new/upcoming_changes/sklearn.pipeline/29868.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.pipeline/29868.enhancement.rst deleted file mode 100644 index ec462a0b742e3..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.pipeline/29868.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`pipeline.Pipeline` now warns about not being fitted before calling methods - that require the pipeline to be fitted. This warning will become an error in 1.8. - By `Adrin Jalali`_. diff --git a/doc/whats_new/upcoming_changes/sklearn.preprocessing/27875.fix.rst b/doc/whats_new/upcoming_changes/sklearn.preprocessing/27875.fix.rst deleted file mode 100644 index 1be507801c3f3..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.preprocessing/27875.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`preprocessing.PowerTransformer` now uses `scipy.special.inv_boxcox` - to output `nan` if the input of BoxCox's inverse is invalid. - By :user:`Xuefeng Xu ` diff --git a/doc/whats_new/upcoming_changes/sklearn.preprocessing/28637.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.preprocessing/28637.enhancement.rst deleted file mode 100644 index 506f67a9a6cda..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.preprocessing/28637.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Added `warn` option to `handle_unknown` parameter in - :class:`preprocessing.OneHotEncoder`. - By :user:`Gleb Levitski ` diff --git a/doc/whats_new/upcoming_changes/sklearn.preprocessing/29158.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.preprocessing/29158.enhancement.rst deleted file mode 100644 index 0f70f8e5277d1..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.preprocessing/29158.enhancement.rst +++ /dev/null @@ -1,3 +0,0 @@ -- The HTML representation of :class:`preprocessing.FunctionTransformer` - will show the function name in the label. - By :user:`Yao Xiao ` diff --git a/doc/whats_new/upcoming_changes/sklearn.semi_supervised/28494.api.rst b/doc/whats_new/upcoming_changes/sklearn.semi_supervised/28494.api.rst deleted file mode 100644 index c65069a27896a..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.semi_supervised/28494.api.rst +++ /dev/null @@ -1,3 +0,0 @@ -- :class:`semi_supervised.SelfTrainingClassifier` - deprecated the `base_estimator` parameter in favor of `estimator`. - By :user:`Adam Li ` diff --git a/doc/whats_new/upcoming_changes/sklearn.tree/17575.fix.rst b/doc/whats_new/upcoming_changes/sklearn.tree/17575.fix.rst deleted file mode 100644 index f04954244f19c..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.tree/17575.fix.rst +++ /dev/null @@ -1,3 +0,0 @@ -- Escape double quotes for labels and feature names when exporting trees to Graphviz - format. - By :user:`Santiago M. Mola `. diff --git a/doc/whats_new/upcoming_changes/sklearn.tree/27966.feature.rst b/doc/whats_new/upcoming_changes/sklearn.tree/27966.feature.rst deleted file mode 100644 index bc3ae222fc2cf..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.tree/27966.feature.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :class:`tree.ExtraTreeClassifier` and :class:`tree.ExtraTreeRegressor` now - support missing-values in the data matrix ``X``. Missing-values are handled by - randomly moving all of the samples to the left, or right child node as the tree is - traversed. - By :user:`Adam Li ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29404.api.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29404.api.rst deleted file mode 100644 index f5aa06dc5c5f0..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29404.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- The `assert_all_finite` parameter of functions :func:`utils.check_array`, - :func:`utils.check_X_y`, :func:`utils.as_float_array` is renamed into - `ensure_all_finite`. `force_all_finite` will be removed in 1.8. - By :user:`Jérémie du Boisberranger ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29540.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29540.enhancement.rst deleted file mode 100644 index 95741afa0f260..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29540.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`utils.validation.check_array` now accepts `ensure_non_negative` - to check for negative values in the passed array, until now only available through - calling :func:`utils.validation.check_non_negative`. - By :user:`Tamara Atanasoska ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29818.api.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29818.api.rst deleted file mode 100644 index df30e3af6ee6e..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29818.api.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`check_estimators.check_sample_weights_invariance` replaced by - :func:`check_estimators.check_sample_weight_equivalence` which uses - integer (including zero) weights. - By :user:`Antoine Baker ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29869.fix.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29869.fix.rst deleted file mode 100644 index 9bdb83c97a9d9..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29869.fix.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`utils.estimator_checks.parametrize_with_checks` and - :func:`utils.estimator_checks.check_estimator` now support estimators that - have `set_output` called on them. - By :user:`Adrin Jalali ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29874.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29874.enhancement.rst deleted file mode 100644 index 58f3919af7c2c..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29874.enhancement.rst +++ /dev/null @@ -1,5 +0,0 @@ -- :func:`~sklearn.utils.estimator_checks.check_estimator` and - :func:`~sklearn.utils.estimator_checks.parametrize_with_checks` now check and fail if - the classifier has the `tags.classifier_tags.multi_class = False` tag but does not - fail on multi-class data. - By `Adrin Jalali`_. diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/29880.enhancement.rst b/doc/whats_new/upcoming_changes/sklearn.utils/29880.enhancement.rst deleted file mode 100644 index 22f61b7059edc..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/29880.enhancement.rst +++ /dev/null @@ -1,4 +0,0 @@ -- :func:`utils.validation.check_is_fitted` now passes on stateless - estimators. An estimator can indicate it's stateless by setting the `requires_fit` - tag. See :ref:`estimator_tags` for more information. - By :user:`Adrin Jalali ` diff --git a/doc/whats_new/upcoming_changes/sklearn.utils/30122.api.rst b/doc/whats_new/upcoming_changes/sklearn.utils/30122.api.rst deleted file mode 100644 index 50dec6ff8c82d..0000000000000 --- a/doc/whats_new/upcoming_changes/sklearn.utils/30122.api.rst +++ /dev/null @@ -1,6 +0,0 @@ -- Using `_estimator_type` to set the estimator type is deprecated. Inherit from - :class:`~sklearn.base.ClassifierMixin`, :class:`~sklearn.base.RegressorMixin`, - :class:`~sklearn.base.TransformerMixin`, or :class:`~sklearn.base.OutlierMixin` - instead. Alternatively, you can set `estimator_type` in :class:`~sklearn.utils.Tags` - in the `__sklearn_tags__` method. - By `Adrin Jalali`_ diff --git a/doc/whats_new/v1.6.rst b/doc/whats_new/v1.6.rst index 92d3cc519e1e6..50edd9e1af8bb 100644 --- a/doc/whats_new/v1.6.rst +++ b/doc/whats_new/v1.6.rst @@ -8,27 +8,778 @@ Version 1.6 =========== -.. - -- UNCOMMENT WHEN 1.6.0 IS RELEASED -- - For a short description of the main highlights of the release, please refer to - :ref:`sphx_glr_auto_examples_release_highlights_plot_release_highlights_1_6_0.py`. - - -.. - DELETE WHEN 1.6.0 IS RELEASED - Since October 2024, DO NOT add your changelog entry in this file. -.. - Instead, create a file named `..rst` in the relevant sub-folder in - `doc/whats_new/upcoming_changes/`. For full details, see: - https://github.com/scikit-learn/scikit-learn/blob/main/doc/whats_new/upcoming_changes/README.md +For a short description of the main highlights of the release, please refer to +:ref:`sphx_glr_auto_examples_release_highlights_plot_release_highlights_1_6_0.py`. .. include:: changelog_legend.inc .. towncrier release notes start +.. _changes_1_6_1: + +Version 1.6.1 +============= + +**January 2025** + +Changed models +-------------- + +- |Fix| The `tags.input_tags.sparse` flag was corrected for a majority of estimators. + By :user:`Antoine Baker ` :pr:`30187` + +Changes impacting many modules +------------------------------ + +- |Fix| `_more_tags`, `_get_tags`, and `_safe_tags` are now raising a + :class:`DeprecationWarning` instead of a :class:`FutureWarning` to only notify + developers instead of end-users. + By :user:`Guillaume Lemaitre ` in :pr:`30573` + +:mod:`sklearn.metrics` +---------------------- + +- |Fix| Fix regression when scikit-learn metric called on PyTorch CPU tensors would + raise an error (with array API dispatch disabled which is the default). + By :user:`Loïc Estève ` :pr:`30454` + +:mod:`sklearn.model_selection` +------------------------------ + +- |Fix| :func:`~model_selection.cross_validate`, :func:`~model_selection.cross_val_predict`, + and :func:`~model_selection.cross_val_score` now accept `params=None` when metadata + routing is enabled. By `Adrin Jalali`_ :pr:`30451` + +:mod:`sklearn.tree` +------------------- + +- |Fix| Use `log2` instead of `ln` for building trees to maintain behavior of previous + versions. By `Thomas Fan`_ :pr:`30557` + +:mod:`sklearn.utils` +-------------------- + +- |Enhancement| :func:`utils.estimator_checks.check_estimator_sparse_tag` ensures that + the estimator tag `input_tags.sparse` is consistent with its `fit` + method (accepting sparse input `X` or raising the appropriate error). + By :user:`Antoine Baker ` :pr:`30187` + +- |Fix| Raise a `DeprecationWarning` when there is no concrete implementation of `__sklearn_tags__` + in the MRO of the estimator. We request to inherit from `BaseEstimator` that + implements `__sklearn_tags__`. + By :user:`Guillaume Lemaitre ` :pr:`30516` + +.. _changes_1_6_0: + +Version 1.6.0 +============= + +**December 2024** + +Changes impacting many modules +------------------------------ + +- |Enhancement| `__sklearn_tags__` was introduced for setting tags in estimators. + More details in :ref:`estimator_tags`. + By :user:`Thomas Fan ` and :user:`Adrin Jalali ` :pr:`29677` + +- |Enhancement| Scikit-learn classes and functions can be used while only having a + `import sklearn` import line. For example, `import sklearn; sklearn.svm.SVC()` now works. + By :user:`Thomas Fan ` :pr:`29793` + +- |Fix| Classes :class:`metrics.ConfusionMatrixDisplay`, + :class:`metrics.RocCurveDisplay`, :class:`calibration.CalibrationDisplay`, + :class:`metrics.PrecisionRecallDisplay`, :class:`metrics.PredictionErrorDisplay` and + :class:`inspection.PartialDependenceDisplay` now properly handle Matplotlib aliases + for style parameters (e.g., `c` and `color`, `ls` and `linestyle`, etc). + By :user:`Joseph Barbier ` :pr:`30023` + +- |API| :func:`utils.validation.validate_data` is introduced and replaces previously + private `base.BaseEstimator._validate_data` method. This is intended for third party + estimator developers, who should use this function in most cases instead of + :func:`utils.check_array` and :func:`utils.check_X_y`. + By :user:`Adrin Jalali ` :pr:`29696` + +Support for Array API +--------------------- + +Additional estimators and functions have been updated to include support for all +`Array API `_ compliant inputs. + +See :ref:`array_api` for more details. + +- |Feature| :class:`model_selection.GridSearchCV`, + :class:`model_selection.RandomizedSearchCV`, + :class:`model_selection.HalvingGridSearchCV` and + :class:`model_selection.HalvingRandomSearchCV` now support Array API + compatible inputs when their base estimators do. + By :user:`Tim Head ` and :user:`Olivier Grisel ` :pr:`27096` + +- |Feature| :func:`sklearn.metrics.f1_score` now supports Array API compatible + inputs. + By :user:`Omar Salman ` :pr:`27369` + +- |Feature| :class:`preprocessing.LabelEncoder` now supports Array API compatible inputs. + By :user:`Omar Salman ` :pr:`27381` + +- |Feature| :func:`sklearn.metrics.mean_absolute_error` now supports Array API compatible + inputs. + By :user:`Edoardo Abati ` :pr:`27736` + +- |Feature| :func:`sklearn.metrics.mean_tweedie_deviance` now supports Array API + compatible inputs. + By :user:`Thomas Li ` :pr:`28106` + +- |Feature| :func:`sklearn.metrics.pairwise.cosine_similarity` now supports Array API + compatible inputs. + By :user:`Edoardo Abati ` :pr:`29014` + +- |Feature| :func:`sklearn.metrics.pairwise.paired_cosine_distances` now supports Array + API compatible inputs. + By :user:`Edoardo Abati ` :pr:`29112` + +- |Feature| :func:`sklearn.metrics.cluster.entropy` now supports Array API compatible + inputs. + By :user:`Yaroslav Korobko ` :pr:`29141` + +- |Feature| :func:`sklearn.metrics.mean_squared_error` now supports Array API compatible + inputs. + By :user:`Yaroslav Korobko ` :pr:`29142` + +- |Feature| :func:`sklearn.metrics.pairwise.additive_chi2_kernel` now supports Array API + compatible inputs. + By :user:`Yaroslav Korobko ` :pr:`29144` + +- |Feature| :func:`sklearn.metrics.d2_tweedie_score` now supports Array API compatible + inputs. + By :user:`Emily Chen ` :pr:`29207` + +- |Feature| :func:`sklearn.metrics.max_error` now supports Array API compatible inputs. + By :user:`Edoardo Abati ` :pr:`29212` + +- |Feature| :func:`sklearn.metrics.mean_poisson_deviance` now supports Array API + compatible inputs. + By :user:`Emily Chen ` :pr:`29227` + +- |Feature| :func:`sklearn.metrics.mean_gamma_deviance` now supports Array API compatible + inputs. + By :user:`Emily Chen ` :pr:`29239` + +- |Feature| :func:`sklearn.metrics.pairwise.cosine_distances` now supports Array API + compatible inputs. + By :user:`Emily Chen ` :pr:`29265` + +- |Feature| :func:`sklearn.metrics.pairwise.chi2_kernel` now supports Array API + compatible inputs. + By :user:`Yaroslav Korobko ` :pr:`29267` + +- |Feature| :func:`sklearn.metrics.mean_absolute_percentage_error` now supports Array API + compatible inputs. + By :user:`Emily Chen ` :pr:`29300` + +- |Feature| :func:`sklearn.metrics.pairwise.paired_euclidean_distances` now supports + Array API compatible inputs. + By :user:`Emily Chen ` :pr:`29389` + +- |Feature| :func:`sklearn.metrics.pairwise.euclidean_distances` and + :func:`sklearn.metrics.pairwise.rbf_kernel` now supports Array API compatible + inputs. + By :user:`Omar Salman ` :pr:`29433` + +- |Feature| :func:`sklearn.metrics.pairwise.linear_kernel`, + :func:`sklearn.metrics.pairwise.sigmoid_kernel`, and + :func:`sklearn.metrics.pairwise.polynomial_kernel` now supports Array API + compatible inputs. + By :user:`Omar Salman ` :pr:`29475` + +- |Feature| :func:`sklearn.metrics.mean_squared_log_error` and + :func:`sklearn.metrics.root_mean_squared_log_error` + now supports Array API compatible inputs. + By :user:`Virgil Chan ` :pr:`29709` + +- |Feature| :class:`preprocessing.MinMaxScaler` with `clip=True` now supports Array API + compatible inputs. + By :user:`Shreekant Nandiyawar ` :pr:`29751` + +- Support for the soon to be deprecated `cupy.array_api` module has been + removed in favor of directly supporting the top level `cupy` module, possibly + via the `array_api_compat.cupy` compatibility wrapper. + By :user:`Olivier Grisel ` :pr:`29639` + +Metadata routing +---------------- + +Refer to the :ref:`Metadata Routing User Guide ` for +more details. + +- |Feature| :class:`semi_supervised.SelfTrainingClassifier` + now supports metadata routing. The fit method now accepts ``**fit_params`` + which are passed to the underlying estimators via their `fit` methods. + In addition, the + :meth:`~semi_supervised.SelfTrainingClassifier.predict`, + :meth:`~semi_supervised.SelfTrainingClassifier.predict_proba`, + :meth:`~semi_supervised.SelfTrainingClassifier.predict_log_proba`, + :meth:`~semi_supervised.SelfTrainingClassifier.score` + and :meth:`~semi_supervised.SelfTrainingClassifier.decision_function` + methods also accept ``**params`` which are + passed to the underlying estimators via their respective methods. + By :user:`Adam Li ` :pr:`28494` + +- |Feature| :class:`ensemble.StackingClassifier` and + :class:`ensemble.StackingRegressor` now support metadata routing and pass + ``**fit_params`` to the underlying estimators via their `fit` methods. + By :user:`Stefanie Senger ` :pr:`28701` + +- |Feature| :func:`model_selection.learning_curve` now supports metadata routing for the + `fit` method of its estimator and for its underlying CV splitter and scorer. + By :user:`Stefanie Senger ` :pr:`28975` + +- |Feature| :class:`compose.TransformedTargetRegressor` now supports metadata + routing in its :meth:`~compose.TransformedTargetRegressor.fit` and + :meth:`~compose.TransformedTargetRegressor.predict` methods and routes the + corresponding params to the underlying regressor. + By :user:`Omar Salman ` :pr:`29136` + +- |Feature| :class:`feature_selection.SequentialFeatureSelector` now supports + metadata routing in its `fit` method and passes the corresponding params to + the :func:`model_selection.cross_val_score` function. + By :user:`Omar Salman ` :pr:`29260` + +- |Feature| :func:`model_selection.permutation_test_score` now supports metadata routing + for the `fit` method of its estimator and for its underlying CV splitter and scorer. + By :user:`Adam Li ` :pr:`29266` + +- |Feature| :class:`feature_selection.RFE` and :class:`feature_selection.RFECV` + now support metadata routing. + By :user:`Omar Salman ` :pr:`29312` + +- |Feature| :func:`model_selection.validation_curve` now supports metadata routing for + the `fit` method of its estimator and for its underlying CV splitter and scorer. + By :user:`Stefanie Senger ` :pr:`29329` + +- |Fix| Metadata is routed correctly to grouped CV splitters via + :class:`linear_model.RidgeCV` and :class:`linear_model.RidgeClassifierCV` and + `UnsetMetadataPassedError` is fixed for :class:`linear_model.RidgeClassifierCV` with + default scoring. + By :user:`Stefanie Senger ` :pr:`29634` + +- |Fix| Many method arguments which shouldn't be included in the routing mechanism are + now excluded and the `set_{method}_request` methods are not generated for them. + By `Adrin Jalali`_ :pr:`29920` + +Dropping official support for PyPy +---------------------------------- + +Due to limited maintainer resources and small number of users, official PyPy +support has been dropped. Some parts of scikit-learn may still work but PyPy is +not tested anymore in the scikit-learn Continuous Integration. +By :user:`Loïc Estève ` :pr:`29128` + +Dropping support for building with setuptools +--------------------------------------------- + +From scikit-learn 1.6 onwards, support for building with setuptools has been +removed. Meson is the only supported way to build scikit-learn, see +:ref:`Building from source ` for more details. +By :user:`Loïc Estève ` :pr:`29400` + +Free-threaded CPython 3.13 support +---------------------------------- + +scikit-learn has preliminary support for free-threaded CPython, in particular +free-threaded wheels are available for all of our supported platforms. + +Free-threaded (also known as nogil) CPython 3.13 is an experimental version of +CPython 3.13 who aims at enabling efficient multi-threaded use cases by +removing the Global Interpreter Lock (GIL). + +For more details about free-threaded CPython see `py-free-threading doc `_, +in particular `how to install a free-threaded CPython `_ +and `Ecosystem compatibility tracking `_. + +Feel free to try free-threaded on your use case and report any issues! + +By :user:`Loïc Estève ` and many other people in the wider Scientific +Python and CPython ecosystem, for example :user:`Nathan Goldbaum `, +:user:`Ralf Gommers `, :user:`Edgar Andrés Margffoy Tuay `. :pr:`30360` + +:mod:`sklearn.base` +------------------- + +- |Enhancement| Added a function :func:`base.is_clusterer` which determines whether a given + estimator is of category clusterer. + By :user:`Christian Veenhuis ` :pr:`28936` + +- |API| Passing a class object to :func:`~sklearn.base.is_classifier`, + :func:`~sklearn.base.is_regressor`, and + :func:`~sklearn.base.is_outlier_detector` is now deprecated. Pass an instance + instead. + By `Adrin Jalali`_ :pr:`30122` + +:mod:`sklearn.calibration` +-------------------------- + +- |API| `cv="prefit"` is deprecated for :class:`~sklearn.calibration.CalibratedClassifierCV`. + Use :class:`~sklearn.frozen.FrozenEstimator` instead, as + `CalibratedClassifierCV(FrozenEstimator(estimator))`. + By `Adrin Jalali`_ :pr:`30171` + +:mod:`sklearn.cluster` +---------------------- + +- |API| The `copy` parameter of :class:`cluster.Birch` was deprecated in 1.6 and will be + removed in 1.8. It has no effect as the estimator does not perform in-place operations + on the input data. + By :user:`Yao Xiao ` :pr:`29124` + +:mod:`sklearn.compose` +---------------------- + +- |Enhancement| :func:`sklearn.compose.ColumnTransformer` `verbose_feature_names_out` + now accepts string format or callable to generate feature names. + By :user:`Marc Bresson ` :pr:`28934` + +:mod:`sklearn.covariance` +------------------------- + +- |Efficiency| :class:`covariance.MinCovDet` fitting is now slightly faster. + By :user:`Antony Lee ` :pr:`29835` + +:mod:`sklearn.cross_decomposition` +---------------------------------- + +- |Fix| :class:`cross_decomposition.PLSRegression` properly raises an error when + `n_components` is larger than `n_samples`. + By :user:`Thomas Fan ` :pr:`29710` + +:mod:`sklearn.datasets` +----------------------- + +- |Feature| :func:`datasets.fetch_file` allows downloading arbitrary data-file + from the web. It handles local caching, integrity checks with SHA256 digests + and automatic retries in case of HTTP errors. + By :user:`Olivier Grisel ` :pr:`29354` + +:mod:`sklearn.decomposition` +---------------------------- + +- |Enhancement| :class:`~sklearn.decomposition.LatentDirichletAllocation` now has a + ``normalize`` parameter in + :meth:`~sklearn.decomposition.LatentDirichletAllocation.transform` and + :meth:`~sklearn.decomposition.LatentDirichletAllocation.fit_transform` + methods to control whether the document topic distribution is normalized. + By `Adrin Jalali`_ :pr:`30097` + +- |Fix| :class:`~sklearn.decomposition.IncrementalPCA` + will now only raise a ``ValueError`` when the number of samples in the + input data to ``partial_fit`` is less than the number of components + on the first call to ``partial_fit``. Subsequent calls to ``partial_fit`` + no longer face this restriction. + By :user:`Thomas Gessey-Jones ` :pr:`30224` + +:mod:`sklearn.discriminant_analysis` +------------------------------------ + +- |Fix| :class:`discriminant_analysis.QuadraticDiscriminantAnalysis` + will now cause `LinAlgWarning` in case of collinear variables. These errors + can be silenced using the `reg_param` attribute. + By :user:`Alihan Zihna ` :pr:`19731` + +:mod:`sklearn.ensemble` +----------------------- + +- |Feature| :class:`ensemble.ExtraTreesClassifier` and + :class:`ensemble.ExtraTreesRegressor` now support missing-values in the data matrix + `X`. Missing-values are handled by randomly moving all of the samples to the left, or + right child node as the tree is traversed. + By :user:`Adam Li ` :pr:`28268` + +- |Efficiency| Small runtime improvement of fitting + :class:`ensemble.HistGradientBoostingClassifier` and + :class:`ensemble.HistGradientBoostingRegressor` by parallelizing the initial search + for bin thresholds. + By :user:`Christian Lorentzen ` :pr:`28064` + +- |Efficiency| :class:`ensemble.IsolationForest` now runs parallel jobs + during :term:`predict` offering a speedup of up to 2-4x on sample sizes + larger than 2000 using `joblib`. + By :user:`Adam Li ` and :user:`Sérgio Pereira ` :pr:`28622` + +- |Enhancement| The verbosity of :class:`ensemble.HistGradientBoostingClassifier` + and :class:`ensemble.HistGradientBoostingRegressor` got a more granular control. Now, + `verbose = 1` prints only summary messages, `verbose >= 2` prints the full + information as before. + By :user:`Christian Lorentzen ` :pr:`28179` + +- |API| The parameter `algorithm` of :class:`ensemble.AdaBoostClassifier` is deprecated + and will be removed in 1.8. + By :user:`Jérémie du Boisberranger ` :pr:`29997` + +:mod:`sklearn.feature_extraction` +--------------------------------- + +- |Fix| :class:`feature_extraction.text.TfidfVectorizer` now correctly preserves the + `dtype` of `idf_` based on the input data. + By :user:`Guillaume Lemaitre ` :pr:`30022` + +:mod:`sklearn.frozen` +--------------------- + +- |MajorFeature| :class:`~sklearn.frozen.FrozenEstimator` is now introduced which allows + freezing an estimator. This means calling `.fit` on it has no effect, and doing a + `clone(frozenestimator)` returns the same estimator instead of an unfitted clone. + :pr:`29705` By `Adrin Jalali`_ :pr:`29705` + +:mod:`sklearn.impute` +--------------------- + +- |Fix| :class:`impute.KNNImputer` excludes samples with nan distances when + computing the mean value for uniform weights. + By :user:`Xuefeng Xu ` :pr:`29135` + +- |Fix| When `min_value` and `max_value` are array-like and some features are dropped due to + `keep_empty_features=False`, :class:`impute.IterativeImputer` no longer raises an + error and now indexes correctly. + By :user:`Guntitat Sawadwuthikul ` :pr:`29451` + +- |Fix| Fixed :class:`impute.IterativeImputer` to make sure that it does not skip + the iterative process when `keep_empty_features` is set to `True`. + By :user:`Arif Qodari ` :pr:`29779` + +- |API| Add a warning in :class:`impute.SimpleImputer` when `keep_empty_feature=False` and + `strategy="constant"`. In this case empty features are not dropped and this behaviour + will change in 1.8. + By :user:`Arthur Courselle ` and :user:`Simon Riou ` :pr:`29950` + +:mod:`sklearn.linear_model` +--------------------------- + +- |Enhancement| The `solver="newton-cholesky"` in + :class:`linear_model.LogisticRegression` and + :class:`linear_model.LogisticRegressionCV` is extended to support the full + multinomial loss in a multiclass setting. + By :user:`Christian Lorentzen ` :pr:`28840` + +- |Fix| In :class:`linear_model.Ridge` and :class:`linear_model.RidgeCV`, after `fit`, + the `coef_` attribute is now of shape `(n_samples,)` like other linear models. + By :user:`Maxwell Liu`, `Guillaume Lemaitre`_, and `Adrin Jalali`_ :pr:`19746` + +- |Fix| :class:`linear_model.LogisticRegressionCV` corrects sample weight handling + for the calculation of test scores. + By :user:`Shruti Nath ` :pr:`29419` + +- |Fix| :class:`linear_model.LassoCV` and :class:`linear_model.ElasticNetCV` now + take sample weights into accounts to define the search grid for the internally tuned + `alpha` hyper-parameter. + By :user:`John Hopfensperger ` and :user:`Shruti Nath ` :pr:`29442` + +- |Fix| :class:`linear_model.LogisticRegression`, :class:`linear_model.PoissonRegressor`, + :class:`linear_model.GammaRegressor`, :class:`linear_model.TweedieRegressor` + now take sample weights into account to decide when to fall back to `solver='lbfgs'` + whenever `solver='newton-cholesky'` becomes numerically unstable. + By :user:`Antoine Baker ` :pr:`29818` + +- |Fix| :class:`linear_model.RidgeCV` now properly uses predictions on the same scale as + the target seen during `fit`. These predictions are stored in `cv_results_` when + `scoring != None`. Previously, the predictions were rescaled by the square root of the + sample weights and offset by the mean of the target, leading to an incorrect estimate + of the score. + By :user:`Guillaume Lemaitre `, + :user:`Jérôme Dockes ` and + :user:`Hanmin Qin ` :pr:`29842` + +- |Fix| :class:`linear_model.RidgeCV` now properly supports custom multioutput scorers + by letting the scorer manage the multioutput averaging. Previously, the predictions + and true targets were both squeezed to a 1D array before computing the error. + By :user:`Guillaume Lemaitre ` :pr:`29884` + +- |Fix| :class:`linear_model.LinearRegression` now sets the `cond` parameter when + calling the `scipy.linalg.lstsq` solver on dense input data. This ensures + more numerically robust results on rank-deficient data. In particular, it + empirically fixes the expected equivalence property between fitting with + reweighted or with repeated data points. + By :user:`Antoine Baker ` :pr:`30040` + +- |Fix| :class:`linear_model.LogisticRegression` and and other linear models that + accept `solver="newton-cholesky"` now report the correct number of iterations + when they fall back to the `"lbfgs"` solver because of a rank deficient + Hessian matrix. + By :user:`Olivier Grisel ` :pr:`30100` + +- |Fix| :class:`~sklearn.linear_model.SGDOneClassSVM` now correctly inherits from + :class:`~sklearn.base.OutlierMixin` and the tags are correctly set. + By :user:`Guillaume Lemaitre ` :pr:`30227` + +- |API| Deprecates `copy_X` in :class:`linear_model.TheilSenRegressor` as the parameter + has no effect. `copy_X` will be removed in 1.8. + By :user:`Adam Li ` :pr:`29105` + +:mod:`sklearn.manifold` +----------------------- + +- |Efficiency| :func:`manifold.locally_linear_embedding` and + :class:`manifold.LocallyLinearEmbedding` now allocate more efficiently the memory of + sparse matrices in the Hessian, Modified and LTSA methods. + By :user:`Giorgio Angelotti ` :pr:`28096` + +:mod:`sklearn.metrics` +---------------------- + +- |Efficiency| :func:`sklearn.metrics.classification_report` is now faster by caching + classification labels. + By :user:`Adrin Jalali ` :pr:`29738` + +- |Enhancement| :meth:`metrics.RocCurveDisplay.from_estimator`, + :meth:`metrics.RocCurveDisplay.from_predictions`, + :meth:`metrics.PrecisionRecallDisplay.from_estimator`, and + :meth:`metrics.PrecisionRecallDisplay.from_predictions` now accept a new keyword + `despine` to remove the top and right spines of the plot in order to make it clearer. + By :user:`Yao Xiao ` :pr:`26367` + +- |Enhancement| :func:`sklearn.metrics.check_scoring` now accepts `raise_exc` to specify + whether to raise an exception if a subset of the scorers in multimetric scoring fails + or to return an error code. + By :user:`Stefanie Senger ` :pr:`28992` + +- |Fix| :func:`metrics.roc_auc_score` will now correctly return np.nan and + warn user if only one class is present in the labels. + By :user:`Gleb Levitski ` and :user:`Janez Demšar ` :pr:`27412`, :pr:`30013` + +- |Fix| The functions :func:`metrics.mean_squared_log_error` and + :func:`metrics.root_mean_squared_log_error` now check whether the inputs are within + the correct domain for the function :math:`y=\log(1+x)`, rather than + :math:`y=\log(x)`. The functions :func:`metrics.mean_absolute_error`, + :func:`metrics.mean_absolute_percentage_error`, :func:`metrics.mean_squared_error` + and :func:`metrics.root_mean_squared_error` now explicitly check whether a scalar + will be returned when `multioutput=uniform_average`. + By :user:`Virgil Chan ` :pr:`29709` + +- |API| The `assert_all_finite` parameter of functions + :func:`metrics.pairwise.check_pairwise_arrays` and :func:`metrics.pairwise_distances` + is renamed into `ensure_all_finite`. `force_all_finite` will be removed in 1.8. + By :user:`Jérémie du Boisberranger ` :pr:`29404` + +- |API| `scoring="neg_max_error"` should be used instead of `scoring="max_error"` + which is now deprecated. + By :user:`Farid "Freddie" Taba ` :pr:`29462` + +- |API| The default value of the `response_method` parameter of + :func:`metrics.make_scorer` will change from `None` to `"predict"` and `None` will be + removed in 1.8. In the mean time, `None` is equivalent to `"predict"`. + By :user:`Jérémie du Boisberranger ` :pr:`30001` + +:mod:`sklearn.model_selection` +------------------------------ + +- |Enhancement| :class:`~model_selection.GroupKFold` now has the ability to shuffle groups into + different folds when `shuffle=True`. + By :user:`Zachary Vealey ` :pr:`28519` + +- |Enhancement| There is no need to call `fit` on a + :class:`~sklearn.model_selection.FixedThresholdClassifier` if the underlying + estimator is already fitted. + By :user:`Adrin Jalali ` :pr:`30172` + +- |Fix| Improve error message when :func:`model_selection.RepeatedStratifiedKFold.split` + is called without a `y` argument + By :user:`Anurag Varma ` :pr:`29402` + +:mod:`sklearn.neighbors` +------------------------ + +- |Enhancement| :class:`neighbors.NearestNeighbors`, + :class:`neighbors.KNeighborsClassifier`, + :class:`neighbors.KNeighborsRegressor`, + :class:`neighbors.RadiusNeighborsClassifier`, + :class:`neighbors.RadiusNeighborsRegressor`, + :class:`neighbors.KNeighborsTransformer`, + :class:`neighbors.RadiusNeighborsTransformer`, and + :class:`neighbors.LocalOutlierFactor` + now work with `metric="nan_euclidean"`, supporting `nan` inputs. + By :user:`Carlo Lemos `, `Guillaume Lemaitre`_, and `Adrin Jalali`_ :pr:`25330` + +- |Enhancement| Add :meth:`neighbors.NearestCentroid.decision_function`, + :meth:`neighbors.NearestCentroid.predict_proba` and + :meth:`neighbors.NearestCentroid.predict_log_proba` + to the :class:`neighbors.NearestCentroid` estimator class. + Support the case when `X` is sparse and `shrinking_threshold` + is not `None` in :class:`neighbors.NearestCentroid`. + By :user:`Matthew Ning ` :pr:`26689` + +- |Enhancement| Make `predict`, `predict_proba`, and `score` of + :class:`neighbors.KNeighborsClassifier` and + :class:`neighbors.RadiusNeighborsClassifier` accept `X=None` as input. In this case + predictions for all training set points are returned, and points are not included + into their own neighbors. + By :user:`Dmitry Kobak ` :pr:`30047` + +- |Fix| :class:`neighbors.LocalOutlierFactor` raises a warning in the `fit` method + when duplicate values in the training data lead to inaccurate outlier detection. + By :user:`Henrique Caroço ` :pr:`28773` + +:mod:`sklearn.neural_network` +----------------------------- + +- |Fix| :class:`neural_network.MLPRegressor` does no longer crash when the model + diverges and that `early_stopping` is enabled. + By :user:`Marc Bresson ` :pr:`29773` + +:mod:`sklearn.pipeline` +----------------------- + +- |MajorFeature| :class:`pipeline.Pipeline` can now transform metadata up to the step requiring the + metadata, which can be set using the `transform_input` parameter. + By `Adrin Jalali`_ :pr:`28901` + +- |Enhancement| :class:`pipeline.Pipeline` now warns about not being fitted before calling methods + that require the pipeline to be fitted. This warning will become an error in 1.8. + By `Adrin Jalali`_ :pr:`29868` + +- |Fix| Fixed an issue with tags and estimator type of :class:`~sklearn.pipeline.Pipeline` + when pipeline is empty. This allows the HTML representation of an empty + pipeline to be rendered correctly. + By :user:`Gennaro Daniele Acciaro ` :pr:`30203` + +:mod:`sklearn.preprocessing` +---------------------------- + +- |Enhancement| Added `warn` option to `handle_unknown` parameter in + :class:`preprocessing.OneHotEncoder`. + By :user:`Gleb Levitski ` :pr:`28637` + +- |Enhancement| The HTML representation of :class:`preprocessing.FunctionTransformer` + will show the function name in the label. + By :user:`Yao Xiao ` :pr:`29158` + +- |Fix| :class:`preprocessing.PowerTransformer` now uses `scipy.special.inv_boxcox` + to output `nan` if the input of BoxCox's inverse is invalid. + By :user:`Xuefeng Xu ` :pr:`27875` + +:mod:`sklearn.semi_supervised` +------------------------------ + +- |API| :class:`semi_supervised.SelfTrainingClassifier` + deprecated the `base_estimator` parameter in favor of `estimator`. + By :user:`Adam Li ` :pr:`28494` + +:mod:`sklearn.tree` +------------------- + +- |Feature| :class:`tree.ExtraTreeClassifier` and :class:`tree.ExtraTreeRegressor` now + support missing-values in the data matrix ``X``. Missing-values are handled by + randomly moving all of the samples to the left, or right child node as the tree is + traversed. + By :user:`Adam Li ` and :user:`Loïc Estève ` :pr:`27966`, :pr:`30318` + +- |Fix| Escape double quotes for labels and feature names when exporting trees to Graphviz + format. + By :user:`Santiago M. Mola `. :pr:`17575` + +:mod:`sklearn.utils` +-------------------- + +- |Enhancement| :func:`utils.check_array` now accepts `ensure_non_negative` + to check for negative values in the passed array, until now only available through + calling :func:`utils.check_non_negative`. + By :user:`Tamara Atanasoska ` :pr:`29540` + +- |Enhancement| :func:`~sklearn.utils.estimator_checks.check_estimator` and + :func:`~sklearn.utils.estimator_checks.parametrize_with_checks` now check and fail if + the classifier has the `tags.classifier_tags.multi_class = False` tag but does not + fail on multi-class data. + By `Adrin Jalali`_ :pr:`29874` + +- |Enhancement| :func:`utils.validation.check_is_fitted` now passes on stateless + estimators. An estimator can indicate it's stateless by setting the `requires_fit` + tag. See :ref:`estimator_tags` for more information. + By :user:`Adrin Jalali ` :pr:`29880` + +- |Enhancement| Changes to :func:`~utils.estimator_checks.check_estimator` and + :func:`~utils.estimator_checks.parametrize_with_checks`. + + - :func:`~utils.estimator_checks.check_estimator` introduces new arguments: + ``on_skip``, ``on_fail``, and ``callback`` to control the behavior of the check + runner. Refer to the API documentation for more details. + + - ``generate_only=True`` is deprecated in + :func:`~utils.estimator_checks.check_estimator`. Use + :func:`~utils.estimator_checks.estimator_checks_generator` instead. + + - The ``_xfail_checks`` estimator tag is now removed, and now in order to indicate + which tests are expected to fail, you can pass a dictionary to the + :func:`~utils.estimator_checks.check_estimator` as the ``expected_failed_checks`` + parameter. Similarly, the ``expected_failed_checks`` parameter in + :func:`~utils.estimator_checks.parametrize_with_checks` can be used, which is a + callable returning a dictionary of the form:: + + { + "check_name": "reason to mark this check as xfail", + } + + By `Adrin Jalali`_ :pr:`30149` + +- |Fix| :func:`utils.estimator_checks.parametrize_with_checks` and + :func:`utils.estimator_checks.check_estimator` now support estimators that + have `set_output` called on them. + By :user:`Adrin Jalali ` :pr:`29869` + +- |API| The `assert_all_finite` parameter of functions :func:`utils.check_array`, + :func:`utils.check_X_y`, :func:`utils.as_float_array` is renamed into + `ensure_all_finite`. `force_all_finite` will be removed in 1.8. + By :user:`Jérémie du Boisberranger ` :pr:`29404` + +- |API| `utils.estimator_checks.check_sample_weights_invariance` + replaced by + `utils.estimator_checks.check_sample_weight_equivalence_on_dense_data` + which uses integer (including zero) weights and + `utils.estimator_checks.check_sample_weight_equivalence_on_sparse_data` + which does the same on sparse data. + By :user:`Antoine Baker ` :pr:`29818`, :pr:`30137` + +- |API| Using `_estimator_type` to set the estimator type is deprecated. Inherit from + :class:`~sklearn.base.ClassifierMixin`, :class:`~sklearn.base.RegressorMixin`, + :class:`~sklearn.base.TransformerMixin`, or :class:`~sklearn.base.OutlierMixin` + instead. Alternatively, you can set `estimator_type` in :class:`~sklearn.utils.Tags` + in the `__sklearn_tags__` method. + By `Adrin Jalali`_ :pr:`30122` + .. rubric:: Code and documentation contributors Thanks to everyone who has contributed to the maintenance and improvement of the project since version 1.5, including: -TODO: update at the time of the release. +Aaron Schumacher, Abdulaziz Aloqeely, abhi-jha, Acciaro Gennaro Daniele, Adam +J. Stewart, Adam Li, Adeel Hassan, Adeyemi Biola, Aditi Juneja, Adrin Jalali, +Aisha, Akanksha Mhadolkar, Akihiro Kuno, Alberto Torres, alexqiao, Alihan +Zihna, Aniruddha Saha, antoinebaker, Antony Lee, Anurag Varma, Arif Qodari, +Arthur Courselle, ArthurDbrn, Arturo Amor, Aswathavicky, Audrey Flanders, +aurelienmorgan, Austin, awwwyan, AyGeeEm, a.zy.lee, baggiponte, BlazeStorm001, +bme-git, Boney Patel, brdav, Brigitta Sipőcz, Cailean Carter, Camille +Troillard, Carlo Lemos, Christian Lorentzen, Christian Veenhuis, Christine P. +Chai, claudio, Conrad Stevens, datarollhexasphericon, Davide Chicco, David +Matthew Cherney, Dea María Léon, Deepak Saldanha, Deepyaman Datta, +dependabot[bot], dinga92, Dmitry Kobak, Domenico, Drew Craeton, dymil, Edoardo +Abati, EmilyXinyi, Eric Larson, Evelyn, fabianhenning, Farid "Freddie" Taba, +Gael Varoquaux, Giorgio Angelotti, Gleb Levitski, Guillaume Lemaitre, Guntitat +Sawadwuthikul, Haesun Park, Hanjun Kim, Henrique Caroço, hhchen1105, Hugo +Boulenger, Ilya Komarov, Inessa Pawson, Ivan Pan, Ivan Wiryadi, Jaimin Chauhan, +Jakob Bull, James Lamb, Janez Demšar, Jérémie du Boisberranger, Jérôme +Dockès, Jirair Aroyan, João Morais, Joe Cainey, Joel Nothman, John Enblom, +JorgeCardenas, Joseph Barbier, jpienaar-tuks, Julian Chan, K.Bharat Reddy, +Kevin Doshi, Lars, Loic Esteve, Lucas Colley, Lucy Liu, lunovian, Marc Bresson, +Marco Edward Gorelli, Marco Maggi, Marco Wolsza, Maren Westermann, +MarieS-WiMLDS, Martin Helm, Mathew Shen, mathurinm, Matthew Feickert, Maxwell +Liu, Meekail Zain, Michael Dawson, Miguel Cárdenas, m-maggi, mrastgoo, Natalia +Mokeeva, Nathan Goldbaum, Nathan Orgera, nbrown-ScottLogic, Nikita Chistyakov, +Nithish Bolleddula, Noam Keidar, NoPenguinsLand, Norbert Preining, notPlancha, +Olivier Grisel, Omar Salman, ParsifalXu, Piotr, Priyank Shroff, Priyansh Gupta, +Quentin Barthélemy, Rachit23110261, Rahil Parikh, raisadz, Rajath, +renaissance0ne, Reshama Shaikh, Roberto Rosati, Robert Pollak, rwelsch427, +Santiago Castro, Santiago M. Mola, scikit-learn-bot, sean moiselle, SHREEKANT +VITTHAL NANDIYAWAR, Shruti Nath, Søren Bredlund Caspersen, Stefanie Senger, +Stefano Gaspari, Steffen Schneider, Štěpán Sršeň, Sylvain Combettes, +Tamara, Thomas, Thomas Gessey-Jones, Thomas J. Fan, Thomas Li, ThorbenMaa, +Tialo, Tim Head, Tuhin Sharma, Tushar Parimi, Umberto Fasci, UV, vedpawar2254, +Velislav Babatchev, Victoria Shevchenko, viktor765, Vince Carey, Virgil Chan, +Wang Jiayi, Xiao Yuan, Xuefeng Xu, Yao Xiao, yareyaredesuyo, Zachary Vealey, +Ziad Amerr \ No newline at end of file diff --git a/examples/applications/plot_cyclical_feature_engineering.py b/examples/applications/plot_cyclical_feature_engineering.py index f7c561da48f8b..253316d7dd4fd 100644 --- a/examples/applications/plot_cyclical_feature_engineering.py +++ b/examples/applications/plot_cyclical_feature_engineering.py @@ -198,7 +198,7 @@ # %% # -# Lets evaluate our gradient boosting model with the mean absolute error of the +# Let's evaluate our gradient boosting model with the mean absolute error of the # relative demand averaged across our 5 time-based cross-validation splits: import numpy as np diff --git a/examples/applications/plot_time_series_lagged_features.py b/examples/applications/plot_time_series_lagged_features.py index edb27ade48007..87b3c1f62c9ce 100644 --- a/examples/applications/plot_time_series_lagged_features.py +++ b/examples/applications/plot_time_series_lagged_features.py @@ -40,7 +40,7 @@ pl.Config.set_fmt_str_lengths(20) bike_sharing_data_file = fetch_file( - "https://openml1.win.tue.nl/datasets/0004/44063/dataset_44063.pq", + "https://github.com/scikit-learn/examples-data/raw/refs/heads/master/bike-sharing-demand/dataset_44063.pq", sha256="d120af76829af0d256338dc6dd4be5df4fd1f35bf3a283cab66a51c1c6abd06a", ) bike_sharing_data_file diff --git a/examples/exercises/README.txt b/examples/exercises/README.txt deleted file mode 100644 index 5f211eadfef5a..0000000000000 --- a/examples/exercises/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -Tutorial exercises ------------------- - -Exercises for the tutorials diff --git a/examples/exercises/plot_cv_diabetes.py b/examples/exercises/plot_cv_diabetes.py deleted file mode 100644 index 5e582b4b21571..0000000000000 --- a/examples/exercises/plot_cv_diabetes.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -=============================================== -Cross-validation on diabetes Dataset Exercise -=============================================== - -A tutorial exercise which uses cross-validation with linear models. - -This exercise is used in the :ref:`cv_estimators_tut` part of the -:ref:`model_selection_tut` section of the :ref:`stat_learn_tut_index`. - -""" - -# Authors: The scikit-learn developers -# SPDX-License-Identifier: BSD-3-Clause - -# %% -# Load dataset and apply GridSearchCV -# ----------------------------------- -import matplotlib.pyplot as plt -import numpy as np - -from sklearn import datasets -from sklearn.linear_model import Lasso -from sklearn.model_selection import GridSearchCV - -X, y = datasets.load_diabetes(return_X_y=True) -X = X[:150] -y = y[:150] - -lasso = Lasso(random_state=0, max_iter=10000) -alphas = np.logspace(-4, -0.5, 30) - -tuned_parameters = [{"alpha": alphas}] -n_folds = 5 - -clf = GridSearchCV(lasso, tuned_parameters, cv=n_folds, refit=False) -clf.fit(X, y) -scores = clf.cv_results_["mean_test_score"] -scores_std = clf.cv_results_["std_test_score"] - -# %% -# Plot error lines showing +/- std. errors of the scores -# ------------------------------------------------------ - -plt.figure().set_size_inches(8, 6) -plt.semilogx(alphas, scores) - -std_error = scores_std / np.sqrt(n_folds) - -plt.semilogx(alphas, scores + std_error, "b--") -plt.semilogx(alphas, scores - std_error, "b--") - -# alpha=0.2 controls the translucency of the fill color -plt.fill_between(alphas, scores + std_error, scores - std_error, alpha=0.2) - -plt.ylabel("CV score +/- std error") -plt.xlabel("alpha") -plt.axhline(np.max(scores), linestyle="--", color=".5") -plt.xlim([alphas[0], alphas[-1]]) - -# %% -# Bonus: how much can you trust the selection of alpha? -# ----------------------------------------------------- - -# To answer this question we use the LassoCV object that sets its alpha -# parameter automatically from the data by internal cross-validation (i.e. it -# performs cross-validation on the training data it receives). -# We use external cross-validation to see how much the automatically obtained -# alphas differ across different cross-validation folds. - -from sklearn.linear_model import LassoCV -from sklearn.model_selection import KFold - -lasso_cv = LassoCV(alphas=alphas, random_state=0, max_iter=10000) -k_fold = KFold(3) - -print("Answer to the bonus question:", "how much can you trust the selection of alpha?") -print() -print("Alpha parameters maximising the generalization score on different") -print("subsets of the data:") -for k, (train, test) in enumerate(k_fold.split(X, y)): - lasso_cv.fit(X[train], y[train]) - print( - "[fold {0}] alpha: {1:.5f}, score: {2:.5f}".format( - k, lasso_cv.alpha_, lasso_cv.score(X[test], y[test]) - ) - ) -print() -print("Answer: Not very much since we obtained different alphas for different") -print("subsets of the data and moreover, the scores for these alphas differ") -print("quite substantially.") - -plt.show() diff --git a/examples/exercises/plot_digits_classification_exercise.py b/examples/exercises/plot_digits_classification_exercise.py deleted file mode 100644 index d65006178ca4f..0000000000000 --- a/examples/exercises/plot_digits_classification_exercise.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -================================ -Digits Classification Exercise -================================ - -A tutorial exercise regarding the use of classification techniques on -the Digits dataset. - -This exercise is used in the :ref:`clf_tut` part of the -:ref:`supervised_learning_tut` section of the -:ref:`stat_learn_tut_index`. - -""" - -# Authors: The scikit-learn developers -# SPDX-License-Identifier: BSD-3-Clause - -from sklearn import datasets, linear_model, neighbors - -X_digits, y_digits = datasets.load_digits(return_X_y=True) -X_digits = X_digits / X_digits.max() - -n_samples = len(X_digits) - -X_train = X_digits[: int(0.9 * n_samples)] -y_train = y_digits[: int(0.9 * n_samples)] -X_test = X_digits[int(0.9 * n_samples) :] -y_test = y_digits[int(0.9 * n_samples) :] - -knn = neighbors.KNeighborsClassifier() -logistic = linear_model.LogisticRegression(max_iter=1000) - -print("KNN score: %f" % knn.fit(X_train, y_train).score(X_test, y_test)) -print( - "LogisticRegression score: %f" - % logistic.fit(X_train, y_train).score(X_test, y_test) -) diff --git a/examples/exercises/plot_iris_exercise.py b/examples/exercises/plot_iris_exercise.py deleted file mode 100644 index 8dcc4368ab620..0000000000000 --- a/examples/exercises/plot_iris_exercise.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -================================ -SVM Exercise -================================ - -A tutorial exercise for using different SVM kernels. - -This exercise is used in the :ref:`using_kernels_tut` part of the -:ref:`supervised_learning_tut` section of the :ref:`stat_learn_tut_index`. - -""" - -# Authors: The scikit-learn developers -# SPDX-License-Identifier: BSD-3-Clause - -import matplotlib.pyplot as plt -import numpy as np - -from sklearn import datasets, svm - -iris = datasets.load_iris() -X = iris.data -y = iris.target - -X = X[y != 0, :2] -y = y[y != 0] - -n_sample = len(X) - -np.random.seed(0) -order = np.random.permutation(n_sample) -X = X[order] -y = y[order].astype(float) - -X_train = X[: int(0.9 * n_sample)] -y_train = y[: int(0.9 * n_sample)] -X_test = X[int(0.9 * n_sample) :] -y_test = y[int(0.9 * n_sample) :] - -# fit the model -for kernel in ("linear", "rbf", "poly"): - clf = svm.SVC(kernel=kernel, gamma=10) - clf.fit(X_train, y_train) - - plt.figure() - plt.clf() - plt.scatter( - X[:, 0], X[:, 1], c=y, zorder=10, cmap=plt.cm.Paired, edgecolor="k", s=20 - ) - - # Circle out the test data - plt.scatter( - X_test[:, 0], X_test[:, 1], s=80, facecolors="none", zorder=10, edgecolor="k" - ) - - plt.axis("tight") - x_min = X[:, 0].min() - x_max = X[:, 0].max() - y_min = X[:, 1].min() - y_max = X[:, 1].max() - - XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j] - Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]) - - # Put the result into a color plot - Z = Z.reshape(XX.shape) - plt.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired) - plt.contour( - XX, - YY, - Z, - colors=["k", "k", "k"], - linestyles=["--", "-", "--"], - levels=[-0.5, 0, 0.5], - ) - - plt.title(kernel) -plt.show() diff --git a/examples/frozen/README.txt b/examples/frozen/README.txt new file mode 100644 index 0000000000000..3218ebe7c750a --- /dev/null +++ b/examples/frozen/README.txt @@ -0,0 +1,7 @@ +.. _frozen_examples: + +Frozen Estimators +----------------- + +Examples concerning the :mod:`sklearn.frozen` module. + diff --git a/examples/gaussian_process/plot_gpr_noisy.py b/examples/gaussian_process/plot_gpr_noisy.py index 986bcace5e92f..8aa01a70fc64a 100644 --- a/examples/gaussian_process/plot_gpr_noisy.py +++ b/examples/gaussian_process/plot_gpr_noisy.py @@ -151,7 +151,7 @@ def target_generator(X, add_noise=False): # Looking at the kernel hyperparameters, we see that the best combination found # has a smaller noise level and shorter length scale than the first model. # -# We can inspect the Log-Marginal-Likelihood (LML) of +# We can inspect the negative Log-Marginal-Likelihood (LML) of # :class:`~sklearn.gaussian_process.GaussianProcessRegressor` # for different hyperparameters to get a sense of the local minima. from matplotlib.colors import LogNorm @@ -181,7 +181,7 @@ def target_generator(X, add_noise=False): plt.yscale("log") plt.xlabel("Length-scale") plt.ylabel("Noise-level") -plt.title("Log-marginal-likelihood") +plt.title("Negative log-marginal-likelihood") plt.show() # %% diff --git a/examples/inspection/plot_partial_dependence.py b/examples/inspection/plot_partial_dependence.py index eace8afeb96a0..b5acc4f85952d 100644 --- a/examples/inspection/plot_partial_dependence.py +++ b/examples/inspection/plot_partial_dependence.py @@ -539,6 +539,7 @@ # # Let's make the same partial dependence plot for the 2 features interaction, # this time in 3 dimensions. + # unused but required import for doing 3d projections with matplotlib < 3.2 import mpl_toolkits.mplot3d # noqa: F401 import numpy as np diff --git a/examples/linear_model/plot_robust_fit.py b/examples/linear_model/plot_robust_fit.py index 2b447e6175cdc..874a21fb87a22 100644 --- a/examples/linear_model/plot_robust_fit.py +++ b/examples/linear_model/plot_robust_fit.py @@ -5,7 +5,7 @@ Here a sine function is fit with a polynomial of order 3, for values close to zero. -Robust fitting is demoed in different situations: +Robust fitting is demonstrated in different situations: - No measurement errors, only modelling errors (fitting a sine with a polynomial) diff --git a/examples/linear_model/plot_tweedie_regression_insurance_claims.py b/examples/linear_model/plot_tweedie_regression_insurance_claims.py index 321aa68acf0a7..e479e78ba37b7 100644 --- a/examples/linear_model/plot_tweedie_regression_insurance_claims.py +++ b/examples/linear_model/plot_tweedie_regression_insurance_claims.py @@ -613,11 +613,11 @@ def score_estimator( # %% # -# Finally, we can compare the two models using a plot of cumulated claims: for +# Finally, we can compare the two models using a plot of cumulative claims: for # each model, the policyholders are ranked from safest to riskiest based on the -# model predictions and the fraction of observed total cumulated claims is -# plotted on the y axis. This plot is often called the ordered Lorenz curve of -# the model. +# model predictions and the cumulative proportion of claim amounts is plotted +# against the cumulative proportion of exposure. This plot is often called +# the ordered Lorenz curve of the model. # # The Gini coefficient (based on the area between the curve and the diagonal) # can be used as a model selection metric to quantify the ability of the model @@ -627,7 +627,7 @@ def score_estimator( # Gini coefficient is upper bounded by 1.0 but even an oracle model that ranks # the policyholders by the observed claim amounts cannot reach a score of 1.0. # -# We observe that both models are able to rank policyholders by risky-ness +# We observe that both models are able to rank policyholders by riskiness # significantly better than chance although they are also both far from the # oracle model due to the natural difficulty of the prediction problem from a # few features: most accidents are not predictable and can be caused by @@ -653,10 +653,11 @@ def lorenz_curve(y_true, y_pred, exposure): ranking = np.argsort(y_pred) ranked_exposure = exposure[ranking] ranked_pure_premium = y_true[ranking] - cumulated_claim_amount = np.cumsum(ranked_pure_premium * ranked_exposure) - cumulated_claim_amount /= cumulated_claim_amount[-1] - cumulated_samples = np.linspace(0, 1, len(cumulated_claim_amount)) - return cumulated_samples, cumulated_claim_amount + cumulative_claim_amount = np.cumsum(ranked_pure_premium * ranked_exposure) + cumulative_claim_amount /= cumulative_claim_amount[-1] + cumulative_exposure = np.cumsum(ranked_exposure) + cumulative_exposure /= cumulative_exposure[-1] + return cumulative_exposure, cumulative_claim_amount fig, ax = plt.subplots(figsize=(8, 8)) @@ -668,27 +669,30 @@ def lorenz_curve(y_true, y_pred, exposure): ("Frequency * Severity model", y_pred_product), ("Compound Poisson Gamma", y_pred_total), ]: - ordered_samples, cum_claims = lorenz_curve( + cum_exposure, cum_claims = lorenz_curve( df_test["PurePremium"], y_pred, df_test["Exposure"] ) - gini = 1 - 2 * auc(ordered_samples, cum_claims) + gini = 1 - 2 * auc(cum_exposure, cum_claims) label += " (Gini index: {:.3f})".format(gini) - ax.plot(ordered_samples, cum_claims, linestyle="-", label=label) + ax.plot(cum_exposure, cum_claims, linestyle="-", label=label) # Oracle model: y_pred == y_test -ordered_samples, cum_claims = lorenz_curve( +cum_exposure, cum_claims = lorenz_curve( df_test["PurePremium"], df_test["PurePremium"], df_test["Exposure"] ) -gini = 1 - 2 * auc(ordered_samples, cum_claims) +gini = 1 - 2 * auc(cum_exposure, cum_claims) label = "Oracle (Gini index: {:.3f})".format(gini) -ax.plot(ordered_samples, cum_claims, linestyle="-.", color="gray", label=label) +ax.plot(cum_exposure, cum_claims, linestyle="-.", color="gray", label=label) # Random baseline ax.plot([0, 1], [0, 1], linestyle="--", color="black", label="Random baseline") ax.set( title="Lorenz Curves", - xlabel="Fraction of policyholders\n(ordered by model from safest to riskiest)", - ylabel="Fraction of total claim amount", + xlabel=( + "Cumulative proportion of exposure\n" + "(ordered by model from safest to riskiest)" + ), + ylabel="Cumulative proportion of claim amounts", ) ax.legend(loc="upper left") plt.plot() diff --git a/examples/model_selection/plot_roc.py b/examples/model_selection/plot_roc.py index 70bf3bd3f486d..1fc2dedf2943e 100644 --- a/examples/model_selection/plot_roc.py +++ b/examples/model_selection/plot_roc.py @@ -159,7 +159,7 @@ # %% # In a multi-class classification setup with highly imbalanced classes, # micro-averaging is preferable over macro-averaging. In such cases, one can -# alternatively use a weighted macro-averaging, not demoed here. +# alternatively use a weighted macro-averaging, not demonstrated here. display = RocCurveDisplay.from_predictions( y_onehot_test.ravel(), @@ -218,6 +218,12 @@ # Obtaining the macro-average requires computing the metric independently for # each class and then taking the average over them, hence treating all classes # equally a priori. We first aggregate the true/false positive rates per class: +# +# :math:`TPR=\frac{1}{C}\sum_{c}\frac{TP_c}{TP_c + FN_c}` ; +# +# :math:`FPR=\frac{1}{C}\sum_{c}\frac{FP_c}{FP_c + TN_c}` . +# +# where `C` is the total number of classes. for i in range(n_classes): fpr[i], tpr[i], _ = roc_curve(y_onehot_test[:, i], y_score[:, i]) @@ -441,7 +447,17 @@ # global performance of a classifier can still be summarized via a given # averaging strategy. # -# Micro-averaged OvR ROC is dominated by the more frequent class, since the -# counts are pooled. The macro-averaged alternative better reflects the -# statistics of the less frequent classes, and then is more appropriate when -# performance on all the classes is deemed equally important. +# When dealing with imbalanced datasets, choosing the appropriate metric based on +# the business context or problem you are addressing is crucial. +# It is also essential to select an appropriate averaging method (micro vs. macro) +# depending on the desired outcome: +# +# - Micro-averaging aggregates metrics across all instances, treating each +# individual instance equally, regardless of its class. This approach is useful +# when evaluating overall performance, but note that it can be dominated by +# the majority class in imbalanced datasets. +# +# - Macro-averaging calculates metrics for each class independently and then +# averages them, giving equal weight to each class. This is particularly useful +# when you want under-represented classes to be considered as important as highly +# populated classes. diff --git a/examples/preprocessing/plot_scaling_importance.py b/examples/preprocessing/plot_scaling_importance.py index 55b133576b540..6432a1c48ec69 100644 --- a/examples/preprocessing/plot_scaling_importance.py +++ b/examples/preprocessing/plot_scaling_importance.py @@ -12,13 +12,13 @@ algorithms require features to be normalized, often for different reasons: to ease the convergence (such as a non-penalized logistic regression), to create a completely different model fit compared to the fit with unscaled data (such as -KNeighbors models). The latter is demoed on the first part of the present +KNeighbors models). The latter is demonstrated on the first part of the present example. On the second part of the example we show how Principal Component Analysis (PCA) is impacted by normalization of features. To illustrate this, we compare the principal components found using :class:`~sklearn.decomposition.PCA` on unscaled -data with those obatined when using a +data with those obtained when using a :class:`~sklearn.preprocessing.StandardScaler` to scale data first. In the last part of the example we show the effect of the normalization on the diff --git a/examples/release_highlights/plot_release_highlights_1_6_0.py b/examples/release_highlights/plot_release_highlights_1_6_0.py new file mode 100644 index 0000000000000..c450d4b42905c --- /dev/null +++ b/examples/release_highlights/plot_release_highlights_1_6_0.py @@ -0,0 +1,212 @@ +# ruff: noqa +""" +======================================= +Release Highlights for scikit-learn 1.6 +======================================= + +.. currentmodule:: sklearn + +We are pleased to announce the release of scikit-learn 1.6! Many bug fixes +and improvements were added, as well as some key new features. Below we +detail the highlights of this release. **For an exhaustive list of +all the changes**, please refer to the :ref:`release notes `. + +To install the latest version (with pip):: + + pip install --upgrade scikit-learn + +or with conda:: + + conda install -c conda-forge scikit-learn + +""" + +# %% +# FrozenEstimator: Freezing an estimator +# -------------------------------------- +# +# This meta-estimator allows you to take an estimator and freeze its fit method, meaning +# that calling `fit` does not perform any operations; also, `fit_predict` and +# `fit_transform` call `predict` and `transform` respectively without calling `fit`. The +# original estimator's other methods and properties are left unchanged. An interesting +# use case for this is to use a pre-fitted model as a transformer step in a pipeline +# or to pass a pre-fitted model to some of the meta-estimators. Here's a short example: + +import time +from sklearn.datasets import make_classification +from sklearn.frozen import FrozenEstimator +from sklearn.linear_model import SGDClassifier +from sklearn.model_selection import FixedThresholdClassifier + +X, y = make_classification(n_samples=1000, random_state=0) + +start = time.time() +classifier = SGDClassifier().fit(X, y) +print(f"Fitting the classifier took {(time.time() - start) * 1_000:.2f} milliseconds") + +start = time.time() +threshold_classifier = FixedThresholdClassifier( + estimator=FrozenEstimator(classifier), threshold=0.9 +).fit(X, y) +print( + f"Fitting the threshold classifier took {(time.time() - start) * 1_000:.2f} " + "milliseconds" +) + +# %% +# Fitting the threshold classifier skipped fitting the inner `SGDClassifier`. For more +# details refer to the example :ref:`sphx_glr_auto_examples_frozen_plot_frozen_examples.py`. + +# %% +# Transforming data other than X in a Pipeline +# -------------------------------------------- +# +# The :class:`~pipeline.Pipeline` now supports transforming passed data other than `X` +# if necessary. This can be done by setting the new `transform_input` parameter. This +# is particularly useful when passing a validation set through the pipeline. +# +# As an example, imagine `EstimatorWithValidationSet` is an estimator which accepts +# a validation set. We can now have a pipeline which will transform the validation set +# and pass it to the estimator:: +# +# sklearn.set_config(enable_metadata_routing=True) +# est_gs = GridSearchCV( +# Pipeline( +# ( +# StandardScaler(), +# EstimatorWithValidationSet(...).set_fit_request(X_val=True, y_val=True), +# ), +# # telling pipeline to transform these inputs up to the step which is +# # requesting them. +# transform_input=["X_val"], +# ), +# param_grid={"estimatorwithvalidationset__param_to_optimize": list(range(5))}, +# cv=5, +# ).fit(X, y, X_val=X_val, y_val=y_val) +# +# In the above code, the key parts are the call to `set_fit_request` to specify that +# `X_val` and `y_val` are required by the `EstimatorWithValidationSet.fit` method, and +# the `transform_input` parameter to tell the pipeline to transform `X_val` before +# passing it to `EstimatorWithValidationSet.fit`. +# +# Note that at this time scikit-learn estimators have not yet been extended to accept +# user specified validation sets. This feature is released early to collect feedback +# from third-party libraries who might benefit from it. + +# %% +# Multiclass support for `LogisticRegression(solver="newton-cholesky")` +# --------------------------------------------------------------------- +# +# The `"newton-cholesky"` solver (originally introduced in scikit-learn version +# 1.2) was previously limited to binary +# :class:`~linear_model.LogisticRegression` and some other generalized linear +# regression estimators (namely :class:`~linear_model.PoissonRegressor`, +# :class:`~linear_model.GammaRegressor` and +# :class:`~linear_model.TweedieRegressor`). +# +# This new release includes support for multiclass (multinomial) +# :class:`~linear_model.LogisticRegression`. +# +# This solver is particularly useful when the number of features is small to +# medium. It has been empirically shown to converge more reliably and faster +# than other solvers on some medium sized datasets with one-hot encoded +# categorical features as can be seen in the `benchmark results of the +# pull-request +# `_. + +# %% +# Missing value support for Extra Trees +# ------------------------------------- +# +# The classes :class:`ensemble.ExtraTreesClassifier` and +# :class:`ensemble.ExtraTreesRegressor` now support missing values. More details in the +# :ref:`User Guide `. +import numpy as np +from sklearn.ensemble import ExtraTreesClassifier + +X = np.array([0, 1, 6, np.nan]).reshape(-1, 1) +y = [0, 0, 1, 1] + +forest = ExtraTreesClassifier(random_state=0).fit(X, y) +forest.predict(X) + +# %% +# Download any dataset from the web +# --------------------------------- +# +# The function :func:`datasets.fetch_file` allows downloading a file from any given URL. +# This convenience function provides built-in local disk caching, sha256 digest +# integrity check and an automated retry mechanism on network error. +# +# The goal is to provide the same convenience and reliability as dataset fetchers while +# giving the flexibility to work with data from arbitrary online sources and file +# formats. +# +# The dowloaded file can then be loaded with generic or domain specific functions such +# as `pandas.read_csv`, `pandas.read_parquet`, etc. + +# %% +# Array API support +# ----------------- +# +# Many more estimators and functions have been updated to support array API compatible +# inputs since version 1.5, in particular the meta-estimators for hyperparameter tuning +# from the :mod:`sklearn.model_selection` module and the metrics from the +# :mod:`sklearn.metrics` module. +# +# Please refer to the :ref:`array API support` page for instructions to use +# scikit-learn with array API compatible libraries such as PyTorch or CuPy. + +# %% +# Almost complete Metadata Routing support +# ---------------------------------------- +# +# Support for routing metadata has been added to all remaining estimators and +# functions except AdaBoost. See :ref:`Metadata Routing User Guide ` +# for more details. + +# %% +# Free-threaded CPython 3.13 support +# ---------------------------------- +# +# scikit-learn has preliminary support for free-threaded CPython, in particular +# free-threaded wheels are available for all of our supported platforms. +# +# Free-threaded (also known as nogil) CPython 3.13 is an experimental version of +# CPython 3.13 which aims at enabling efficient multi-threaded use cases by +# removing the Global Interpreter Lock (GIL). +# +# For more details about free-threaded CPython see `py-free-threading doc `_, +# in particular `how to install a free-threaded CPython `_ +# and `Ecosystem compatibility tracking `_. +# +# Feel free to try free-threaded CPython on your use case and report any issues! + +# %% +# Improvements to the developer API for third party libraries +# ----------------------------------------------------------- +# +# We have been working on improving the developer API for third party libraries. +# This is still a work in progress, but a fair amount of work has been done in this +# release. This release includes: +# +# - :func:`sklearn.utils.validation.validate_data` is introduced and replaces the +# previously private `BaseEstimator._validate_data` method. This function extends +# :func:`~sklearn.utils.validation.check_array` and adds support for remembering +# input feature counts and names. +# - Estimator tags are now revamped and a part of the public API via +# :class:`sklearn.utils.Tags`. Estimators should now override the +# :meth:`BaseEstimator.__sklearn_tags__` method instead of implementing a `_more_tags` +# method. If you'd like to support multiple scikit-learn versions, you can implement +# both methods in your class. +# - As a consequence of developing a public tag API, we've removed the `_xfail_checks` +# tag and tests which are expected to fail are directly passed to +# :func:`~sklearn.utils.estimator_checks.check_estimator` and +# :func:`~sklearn.utils.estimator_checks.parametrize_with_checks`. See their +# corresponding API docs for more details. +# - Many tests in the common test suite are updated and raise more helpful error +# messages. We've also added some new tests, which should help you more easily fix +# potential issues with your estimators. +# +# An updated version of our :ref:`develop` is also available, which we recommend you +# check out. diff --git a/maint_tools/check_xfailed_checks.py b/maint_tools/check_xfailed_checks.py new file mode 100644 index 0000000000000..d1108c6ab51a5 --- /dev/null +++ b/maint_tools/check_xfailed_checks.py @@ -0,0 +1,37 @@ +# This script checks that the common tests marked with xfail are actually +# failing. +# Note that in some cases, a test might be marked with xfail because it is +# failing on certain machines, and might not be triggered by this script. + +import contextlib +import io + +from sklearn.utils._test_common.instance_generator import ( + _get_expected_failed_checks, + _tested_estimators, +) +from sklearn.utils.estimator_checks import check_estimator + +for estimator in _tested_estimators(): + # calling check_estimator w/o passing expected_failed_checks will find + # all the failing tests in your environment. + # suppress stdout/stderr while running checks + with ( + contextlib.redirect_stdout(io.StringIO()), + contextlib.redirect_stderr(io.StringIO()), + ): + check_results = check_estimator(estimator, on_skip=None, on_fail=None) + failed_tests = [e for e in check_results if e["status"] == "failed"] + failed_test_names = set(e["check_name"] for e in failed_tests) + expected_failed_tests = set(_get_expected_failed_checks(estimator).keys()) + unexpected_failures = failed_test_names - expected_failed_tests + if unexpected_failures: + print(f"{estimator.__class__.__name__} failed with unexpected failures:") + for failure in unexpected_failures: + print(f" {failure}") + + expected_but_not_raised = expected_failed_tests - failed_test_names + if expected_but_not_raised: + print(f"{estimator.__class__.__name__} did not fail expected failures:") + for failure in expected_but_not_raised: + print(f" {failure}") diff --git a/pyproject.toml b/pyproject.toml index 7b1a31b80f0aa..8a7f4f0db86ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ classifiers=[ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", ] diff --git a/sklearn/__init__.py b/sklearn/__init__.py index 0f6ad7a71c645..34aaea702787c 100644 --- a/sklearn/__init__.py +++ b/sklearn/__init__.py @@ -42,7 +42,7 @@ # Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer. # 'X.Y.dev0' is the canonical version of 'X.Y.dev' # -__version__ = "1.6.dev0" +__version__ = "1.6.1" # On OSX, we can get a runtime error due to multiple OpenMP libraries loaded diff --git a/sklearn/_loss/_loss.pyx.tp b/sklearn/_loss/_loss.pyx.tp index 56d3aebb6c6f1..6054d4c9472ca 100644 --- a/sklearn/_loss/_loss.pyx.tp +++ b/sklearn/_loss/_loss.pyx.tp @@ -818,6 +818,9 @@ cdef inline double_pair cgrad_hess_exponential( cdef class CyLossFunction: """Base class for convex loss functions.""" + def __reduce__(self): + return (self.__class__, ()) + cdef double cy_loss(self, double y_true, double raw_prediction) noexcept nogil: """Compute the loss for a single sample. @@ -1013,6 +1016,11 @@ cdef class {{name}}(CyLossFunction): self.{{param}} = {{param}} {{endif}} + {{if param is not None}} + def __reduce__(self): + return (self.__class__, (self.{{param}},)) + {{endif}} + cdef inline double cy_loss(self, double y_true, double raw_prediction) noexcept nogil: return {{closs}}(y_true, raw_prediction{{with_param}}) diff --git a/sklearn/base.py b/sklearn/base.py index bd5e07c2167dd..3343caa05ca02 100644 --- a/sklearn/base.py +++ b/sklearn/base.py @@ -30,11 +30,14 @@ ) from .utils.fixes import _IS_32BIT from .utils.validation import ( + _check_feature_names, _check_feature_names_in, + _check_n_features, _generate_get_feature_names_out, _is_fitted, check_array, check_is_fitted, + validate_data, ) @@ -386,6 +389,33 @@ def __setstate__(self, state): except AttributeError: self.__dict__.update(state) + # TODO(1.7): Remove this method + def _more_tags(self): + """This code should never be reached since our `get_tags` will fallback on + `__sklearn_tags__` implemented below. We keep it for backward compatibility. + It is tested in `test_base_estimator_more_tags` in + `sklearn/utils/testing/test_tags.py`.""" + from sklearn.utils._tags import _to_old_tags, default_tags + + warnings.warn( + "The `_more_tags` method is deprecated in 1.6 and will be removed in " + "1.7. Please implement the `__sklearn_tags__` method.", + category=DeprecationWarning, + ) + return _to_old_tags(default_tags(self)) + + # TODO(1.7): Remove this method + def _get_tags(self): + from sklearn.utils._tags import _to_old_tags, get_tags + + warnings.warn( + "The `_get_tags` method is deprecated in 1.6 and will be removed in " + "1.7. Please implement the `__sklearn_tags__` method.", + category=DeprecationWarning, + ) + + return _to_old_tags(get_tags(self)) + def __sklearn_tags__(self): return Tags( estimator_type=None, @@ -439,6 +469,35 @@ def _repr_mimebundle_(self, **kwargs): output["text/html"] = estimator_html_repr(self) return output + # TODO(1.7): Remove this method + def _validate_data(self, *args, **kwargs): + warnings.warn( + "`BaseEstimator._validate_data` is deprecated in 1.6 and will be removed " + "in 1.7. Use `sklearn.utils.validation.validate_data` instead. This " + "function becomes public and is part of the scikit-learn developer API.", + FutureWarning, + ) + return validate_data(self, *args, **kwargs) + + # TODO(1.7): Remove this method + def _check_n_features(self, *args, **kwargs): + warnings.warn( + "`BaseEstimator._check_n_features` is deprecated in 1.6 and will be " + "removed in 1.7. Use `sklearn.utils.validation._check_n_features` instead.", + FutureWarning, + ) + _check_n_features(self, *args, **kwargs) + + # TODO(1.7): Remove this method + def _check_feature_names(self, *args, **kwargs): + warnings.warn( + "`BaseEstimator._check_feature_names` is deprecated in 1.6 and will be " + "removed in 1.7. Use `sklearn.utils.validation._check_feature_names` " + "instead.", + FutureWarning, + ) + _check_feature_names(self, *args, **kwargs) + class ClassifierMixin: """Mixin class for all classifiers in scikit-learn. diff --git a/sklearn/calibration.py b/sklearn/calibration.py index b4023172bb20c..1a39315ba6557 100644 --- a/sklearn/calibration.py +++ b/sklearn/calibration.py @@ -28,11 +28,7 @@ from .model_selection import LeaveOneOut, check_cv, cross_val_predict from .preprocessing import LabelEncoder, label_binarize from .svm import LinearSVC -from .utils import ( - _safe_indexing, - column_or_1d, - indexable, -) +from .utils import _safe_indexing, column_or_1d, get_tags, indexable from .utils._param_validation import ( HasMethods, Hidden, @@ -554,6 +550,11 @@ def get_metadata_routing(self): ) return router + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self._get_estimator()).input_tags.sparse + return tags + def _fit_classifier_calibrator_pair( estimator, diff --git a/sklearn/cluster/_affinity_propagation.py b/sklearn/cluster/_affinity_propagation.py index 677421974bdc0..e5cb501984762 100644 --- a/sklearn/cluster/_affinity_propagation.py +++ b/sklearn/cluster/_affinity_propagation.py @@ -483,6 +483,7 @@ def __init__( def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.pairwise = self.affinity == "precomputed" + tags.input_tags.sparse = self.affinity != "precomputed" return tags @_fit_context(prefer_skip_nested_validation=True) diff --git a/sklearn/cluster/_bicluster.py b/sklearn/cluster/_bicluster.py index 08cd63b58cbaa..95f49056ef646 100644 --- a/sklearn/cluster/_bicluster.py +++ b/sklearn/cluster/_bicluster.py @@ -195,16 +195,7 @@ def _k_means(self, data, n_clusters): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_estimators_dtypes": "raises nan error", - "check_fit2d_1sample": "_scale_normalize fails", - "check_fit2d_1feature": "raises apply_along_axis error", - "check_estimator_sparse_matrix": "does not fail gracefully", - "check_estimator_sparse_array": "does not fail gracefully", - "check_methods_subset_invariance": "empty array passed inside", - "check_dont_overwrite_parameters": "empty array passed inside", - "check_fit2d_predict1d": "empty array passed inside", - } + tags.input_tags.sparse = True return tags @@ -362,17 +353,6 @@ def _fit(self, X): [self.column_labels_ == c for c in range(self.n_clusters)] ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks.update( - { - # ValueError: Found array with 0 feature(s) (shape=(23, 0)) - # while a minimum of 1 is required. - "check_dict_unchanged": "FIXME", - } - ) - return tags - class SpectralBiclustering(BaseSpectral): """Spectral biclustering (Kluger, 2003). diff --git a/sklearn/cluster/_birch.py b/sklearn/cluster/_birch.py index 3e5f9d10a79e8..4d8abb43513dc 100644 --- a/sklearn/cluster/_birch.py +++ b/sklearn/cluster/_birch.py @@ -742,4 +742,5 @@ def _global_clustering(self, X=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.transformer_tags.preserves_dtype = ["float64", "float32"] + tags.input_tags.sparse = True return tags diff --git a/sklearn/cluster/_bisect_k_means.py b/sklearn/cluster/_bisect_k_means.py index 3c9ccdcf06414..77e24adbf8084 100644 --- a/sklearn/cluster/_bisect_k_means.py +++ b/sklearn/cluster/_bisect_k_means.py @@ -538,5 +538,6 @@ def _predict_recursive(self, X, sample_weight, cluster_node): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags diff --git a/sklearn/cluster/_dbscan.py b/sklearn/cluster/_dbscan.py index 7764bff94582f..d79c4f286d76d 100644 --- a/sklearn/cluster/_dbscan.py +++ b/sklearn/cluster/_dbscan.py @@ -473,4 +473,5 @@ def fit_predict(self, X, y=None, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.pairwise = self.metric == "precomputed" + tags.input_tags.sparse = True return tags diff --git a/sklearn/cluster/_hdbscan/hdbscan.py b/sklearn/cluster/_hdbscan/hdbscan.py index 8bf402a5081c9..02061753ff573 100644 --- a/sklearn/cluster/_hdbscan/hdbscan.py +++ b/sklearn/cluster/_hdbscan/hdbscan.py @@ -627,14 +627,17 @@ class HDBSCAN(ClusterMixin, BaseEstimator): Examples -------- + >>> import numpy as np >>> from sklearn.cluster import HDBSCAN >>> from sklearn.datasets import load_digits >>> X, _ = load_digits(return_X_y=True) >>> hdb = HDBSCAN(min_cluster_size=20) >>> hdb.fit(X) HDBSCAN(min_cluster_size=20) - >>> hdb.labels_ - array([ 2, 6, -1, ..., -1, -1, -1]) + >>> hdb.labels_.shape == (X.shape[0],) + True + >>> np.unique(hdb.labels_).tolist() + [-1, 0, 1, 2, 3, 4, 5, 6, 7] """ _parameter_constraints = { @@ -1003,5 +1006,6 @@ def dbscan_clustering(self, cut_distance, min_cluster_size=5): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.allow_nan = self.metric != "precomputed" return tags diff --git a/sklearn/cluster/_kmeans.py b/sklearn/cluster/_kmeans.py index 80958f8c845a2..6955de3c385a2 100644 --- a/sklearn/cluster/_kmeans.py +++ b/sklearn/cluster/_kmeans.py @@ -1179,12 +1179,7 @@ def score(self, X, y=None, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } + tags.input_tags.sparse = True return tags @@ -1223,8 +1218,11 @@ class KMeans(_BaseKMeans): * If a callable is passed, it should take arguments X, n_clusters and a\ random state and return an initialization. - For an example of how to use the different `init` strategy, see the example - entitled :ref:`sphx_glr_auto_examples_cluster_plot_kmeans_digits.py`. + For an example of how to use the different `init` strategies, see + :ref:`sphx_glr_auto_examples_cluster_plot_kmeans_digits.py`. + + For an evaluation of the impact of initialization, see the example + :ref:`sphx_glr_auto_examples_cluster_plot_kmeans_stability_low_dim_dense.py`. n_init : 'auto' or int, default='auto' Number of times the k-means algorithm is run with different centroid @@ -1710,6 +1708,9 @@ class MiniBatchKMeans(_BaseKMeans): If a callable is passed, it should take arguments X, n_clusters and a random state and return an initialization. + For an evaluation of the impact of initialization, see the example + :ref:`sphx_glr_auto_examples_cluster_plot_kmeans_stability_low_dim_dense.py`. + max_iter : int, default=100 Maximum number of iterations over the complete dataset before stopping independently of any early stopping criterion heuristics. diff --git a/sklearn/cluster/_spectral.py b/sklearn/cluster/_spectral.py index ebfeccee677a9..6d1dcd093e803 100644 --- a/sklearn/cluster/_spectral.py +++ b/sklearn/cluster/_spectral.py @@ -794,6 +794,7 @@ def fit_predict(self, X, y=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.pairwise = self.affinity in [ "precomputed", "precomputed_nearest_neighbors", diff --git a/sklearn/compose/_column_transformer.py b/sklearn/compose/_column_transformer.py index be7b2f7faeea5..e088f534707d2 100644 --- a/sklearn/compose/_column_transformer.py +++ b/sklearn/compose/_column_transformer.py @@ -29,6 +29,7 @@ _get_output_config, _safe_set_output, ) +from ..utils._tags import get_tags from ..utils.metadata_routing import ( MetadataRouter, MethodMapping, @@ -1317,16 +1318,17 @@ def get_metadata_routing(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_estimators_empty_data_messages": "FIXME", - "check_estimators_nan_inf": "FIXME", - "check_estimator_sparse_array": "FIXME", - "check_estimator_sparse_matrix": "FIXME", - "check_fit1d": "FIXME", - "check_fit2d_predict1d": "FIXME", - "check_complex_data": "FIXME", - "check_fit2d_1feature": "FIXME", - } + try: + tags.input_tags.sparse = all( + get_tags(trans).input_tags.sparse + for name, trans, _ in self.transformers + if trans not in {"passthrough", "drop"} + ) + except Exception: + # If `transformers` does not comply with our API (list of tuples) + # then it will fail. In this case, we assume that `sparse` is False + # but the parameter validation will raise an error during `fit`. + pass # pragma: no cover return tags diff --git a/sklearn/compose/_target.py b/sklearn/compose/_target.py index d90ee17d13f49..86fc6294878b9 100644 --- a/sklearn/compose/_target.py +++ b/sklearn/compose/_target.py @@ -348,6 +348,7 @@ def __sklearn_tags__(self): regressor = self._get_regressor() tags = super().__sklearn_tags__() tags.regressor_tags.poor_score = True + tags.input_tags.sparse = get_tags(regressor).input_tags.sparse tags.target_tags.multi_output = get_tags(regressor).target_tags.multi_output return tags diff --git a/sklearn/covariance/_shrunk_covariance.py b/sklearn/covariance/_shrunk_covariance.py index 2a5e09f2ca8f3..ab875d83b30ec 100644 --- a/sklearn/covariance/_shrunk_covariance.py +++ b/sklearn/covariance/_shrunk_covariance.py @@ -563,6 +563,9 @@ class LedoitWolf(EmpiricalCovariance): [0.1616..., 0.8022...]]) >>> cov.location_ array([ 0.0595... , -0.0075...]) + + See also :ref:`sphx_glr_auto_examples_covariance_plot_covariance_estimation.py` + for a more detailed example. """ _parameter_constraints: dict = { @@ -780,6 +783,9 @@ class OAS(EmpiricalCovariance): [-1.2431..., 3.3889...]]) >>> oas.shrinkage_ np.float64(0.0195...) + + See also :ref:`sphx_glr_auto_examples_covariance_plot_covariance_estimation.py` + for a more detailed example. """ @_fit_context(prefer_skip_nested_validation=True) diff --git a/sklearn/datasets/_openml.py b/sklearn/datasets/_openml.py index 4790431506bce..8a35e4f3680a0 100644 --- a/sklearn/datasets/_openml.py +++ b/sklearn/datasets/_openml.py @@ -1066,7 +1066,7 @@ def fetch_openml( ) else: err_msg = ( - f"Using `parser={parser!r}` wit dense data requires pandas to be " + f"Using `parser={parser!r}` with dense data requires pandas to be " "installed. Alternatively, explicitly set `parser='liac-arff'`." ) raise ImportError(err_msg) from exc diff --git a/sklearn/decomposition/_dict_learning.py b/sklearn/decomposition/_dict_learning.py index b1f1ed8db865b..7410eeb4405df 100644 --- a/sklearn/decomposition/_dict_learning.py +++ b/sklearn/decomposition/_dict_learning.py @@ -1513,7 +1513,7 @@ class DictionaryLearning(_BaseSparseCoding, BaseEstimator): ---------- J. Mairal, F. Bach, J. Ponce, G. Sapiro, 2009: Online dictionary learning - for sparse coding (https://www.di.ens.fr/sierra/pdfs/icml09.pdf) + for sparse coding (https://www.di.ens.fr/~fbach/mairal_icml09.pdf) Examples -------- @@ -1874,7 +1874,7 @@ class MiniBatchDictionaryLearning(_BaseSparseCoding, BaseEstimator): ---------- J. Mairal, F. Bach, J. Ponce, G. Sapiro, 2009: Online dictionary learning - for sparse coding (https://www.di.ens.fr/sierra/pdfs/icml09.pdf) + for sparse coding (https://www.di.ens.fr/~fbach/mairal_icml09.pdf) Examples -------- diff --git a/sklearn/decomposition/_incremental_pca.py b/sklearn/decomposition/_incremental_pca.py index 8fda4ddd1470f..da617ef8fa787 100644 --- a/sklearn/decomposition/_incremental_pca.py +++ b/sklearn/decomposition/_incremental_pca.py @@ -418,3 +418,9 @@ def transform(self, X): return np.vstack(output) else: return super().transform(X) + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + # Beware that fit accepts sparse data but partial_fit doesn't + tags.input_tags.sparse = True + return tags diff --git a/sklearn/decomposition/_kernel_pca.py b/sklearn/decomposition/_kernel_pca.py index d9757c7845be1..37ff77c8d7c64 100644 --- a/sklearn/decomposition/_kernel_pca.py +++ b/sklearn/decomposition/_kernel_pca.py @@ -566,6 +566,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] tags.input_tags.pairwise = self.kernel == "precomputed" return tags diff --git a/sklearn/decomposition/_lda.py b/sklearn/decomposition/_lda.py index 875c6e25fbb10..4580ff073bca5 100644 --- a/sklearn/decomposition/_lda.py +++ b/sklearn/decomposition/_lda.py @@ -549,6 +549,7 @@ def _em_step(self, X, total_samples, batch_update, parallel=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.positive_only = True + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float32", "float64"] return tags diff --git a/sklearn/decomposition/_nmf.py b/sklearn/decomposition/_nmf.py index 6be97f2223fb5..dc21e389f6849 100644 --- a/sklearn/decomposition/_nmf.py +++ b/sklearn/decomposition/_nmf.py @@ -1331,6 +1331,7 @@ def _n_features_out(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.positive_only = True + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags diff --git a/sklearn/decomposition/_pca.py b/sklearn/decomposition/_pca.py index 24cb1649c5fee..f8882a7a6b5d6 100644 --- a/sklearn/decomposition/_pca.py +++ b/sklearn/decomposition/_pca.py @@ -851,4 +851,9 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.transformer_tags.preserves_dtype = ["float64", "float32"] tags.array_api_support = True + tags.input_tags.sparse = self.svd_solver in ( + "auto", + "arpack", + "covariance_eigh", + ) return tags diff --git a/sklearn/decomposition/_truncated_svd.py b/sklearn/decomposition/_truncated_svd.py index b87a53684c140..b77882f5da78d 100644 --- a/sklearn/decomposition/_truncated_svd.py +++ b/sklearn/decomposition/_truncated_svd.py @@ -312,6 +312,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags diff --git a/sklearn/dummy.py b/sklearn/dummy.py index 6332ff43cd482..dbcb36c4c0025 100644 --- a/sklearn/dummy.py +++ b/sklearn/dummy.py @@ -423,12 +423,9 @@ def predict_log_proba(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.classifier_tags.poor_score = True tags.no_validation = True - tags._xfail_checks = { - "check_methods_subset_invariance": "fails for the predict method", - "check_methods_sample_order_invariance": "fails for the predict method", - } return tags def score(self, X, y, sample_weight=None): @@ -544,7 +541,7 @@ def __init__(self, *, strategy="mean", constant=None, quantile=None): @_fit_context(prefer_skip_nested_validation=True) def fit(self, X, y, sample_weight=None): - """Fit the random regressor. + """Fit the baseline regressor. Parameters ---------- @@ -666,6 +663,7 @@ def predict(self, X, return_std=False): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.regressor_tags.poor_score = True tags.no_validation = True return tags diff --git a/sklearn/ensemble/_bagging.py b/sklearn/ensemble/_bagging.py index dd39b8cb607a8..20013e1f6d000 100644 --- a/sklearn/ensemble/_bagging.py +++ b/sklearn/ensemble/_bagging.py @@ -627,13 +627,8 @@ def _get_estimator(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self._get_estimator()).input_tags.sparse tags.input_tags.allow_nan = get_tags(self._get_estimator()).input_tags.allow_nan - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } return tags diff --git a/sklearn/ensemble/_base.py b/sklearn/ensemble/_base.py index 386c4875a1804..db5a0944a72c3 100644 --- a/sklearn/ensemble/_base.py +++ b/sklearn/ensemble/_base.py @@ -288,14 +288,17 @@ def get_params(self, deep=True): def __sklearn_tags__(self): tags = super().__sklearn_tags__() try: - allow_nan = all( + tags.input_tags.allow_nan = all( get_tags(est[1]).input_tags.allow_nan if est[1] != "drop" else True for est in self.estimators ) + tags.input_tags.sparse = all( + get_tags(est[1]).input_tags.sparse if est[1] != "drop" else True + for est in self.estimators + ) except Exception: # If `estimators` does not comply with our API (list of tuples) then it will - # fail. In this case, we assume that `allow_nan` is False but the parameter - # validation will raise an error during `fit`. - allow_nan = False - tags.input_tags.allow_nan = allow_nan + # fail. In this case, we assume that `allow_nan` and `sparse` are False but + # the parameter validation will raise an error during `fit`. + pass # pragma: no cover return tags diff --git a/sklearn/ensemble/_forest.py b/sklearn/ensemble/_forest.py index 92713eecec9dd..5c2152f34e93d 100644 --- a/sklearn/ensemble/_forest.py +++ b/sklearn/ensemble/_forest.py @@ -1002,6 +1002,7 @@ def predict_log_proba(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.classifier_tags.multi_label = True + tags.input_tags.sparse = True return tags @@ -1167,7 +1168,7 @@ def _compute_partial_dependence_recursion(self, grid, target_features): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags.regressor_tags.multi_label = True + tags.input_tags.sparse = True return tags @@ -1557,16 +1558,6 @@ def __init__( self.monotonic_cst = monotonic_cst self.ccp_alpha = ccp_alpha - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class RandomForestRegressor(ForestRegressor): """ @@ -1928,16 +1919,6 @@ def __init__( self.ccp_alpha = ccp_alpha self.monotonic_cst = monotonic_cst - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class ExtraTreesClassifier(ForestClassifier): """ @@ -2666,6 +2647,10 @@ class RandomTreesEmbedding(TransformerMixin, BaseForest): ``n_out <= n_estimators * max_leaf_nodes``. If ``max_leaf_nodes == None``, the number of leaf nodes is at most ``n_estimators * 2 ** max_depth``. + For an example of applying Random Trees Embedding to non-linear + classification, see + :ref:`sphx_glr_auto_examples_ensemble_plot_random_forest_embedding.py`. + Read more in the :ref:`User Guide `. Parameters @@ -3015,10 +3000,5 @@ def transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } + tags.input_tags.sparse = True return tags diff --git a/sklearn/ensemble/_gb.py b/sklearn/ensemble/_gb.py index 8f85f2f7aa3cd..fded8a535413d 100644 --- a/sklearn/ensemble/_gb.py +++ b/sklearn/ensemble/_gb.py @@ -1117,6 +1117,11 @@ def apply(self, X): return leaves + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class GradientBoostingClassifier(ClassifierMixin, BaseGradientBoosting): """Gradient Boosting for classification. @@ -1725,16 +1730,6 @@ def staged_predict_proba(self, X): "loss=%r does not support predict_proba" % self.loss ) from e - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: investigate failure see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class GradientBoostingRegressor(RegressorMixin, BaseGradientBoosting): """Gradient Boosting for regression. @@ -1759,6 +1754,10 @@ class GradientBoostingRegressor(RegressorMixin, BaseGradientBoosting): regression and is a robust loss function. 'huber' is a combination of the two. 'quantile' allows quantile regression (use `alpha` to specify the quantile). + See + :ref:`sphx_glr_auto_examples_ensemble_plot_gradient_boosting_quantile.py` + for an example that demonstrates quantile regression for creating + prediction intervals with `loss='quantile'`. learning_rate : float, default=0.1 Learning rate shrinks the contribution of each tree by `learning_rate`. @@ -2191,13 +2190,3 @@ def apply(self, X): leaves = super().apply(X) leaves = leaves.reshape(X.shape[0], self.estimators_.shape[0]) return leaves - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: investigate failure see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags diff --git a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py index b136cd373a03f..38ff9a7ba3ba2 100644 --- a/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py +++ b/sklearn/ensemble/_hist_gradient_boosting/gradient_boosting.py @@ -1389,12 +1389,6 @@ def _compute_partial_dependence_recursion(self, grid, target_features): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = True - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } return tags @abstractmethod @@ -1585,7 +1579,7 @@ class HistGradientBoostingRegressor(RegressorMixin, BaseHistGradientBoosting): scoring : str or callable or None, default='loss' Scoring parameter to use for early stopping. It can be a single string (see :ref:`scoring_parameter`) or a callable (see - :ref:`scoring`). If None, the estimator's default scorer is used. If + :ref:`scoring_callable`). If None, the estimator's default scorer is used. If ``scoring='loss'``, early stopping is checked w.r.t the loss value. Only used if early stopping is performed. validation_fraction : int or float or None, default=0.1 @@ -1967,7 +1961,7 @@ class HistGradientBoostingClassifier(ClassifierMixin, BaseHistGradientBoosting): scoring : str or callable or None, default='loss' Scoring parameter to use for early stopping. It can be a single string (see :ref:`scoring_parameter`) or a callable (see - :ref:`scoring`). If None, the estimator's default scorer + :ref:`scoring_callable`). If None, the estimator's default scorer is used. If ``scoring='loss'``, early stopping is checked w.r.t the loss value. Only used if early stopping is performed. validation_fraction : int or float or None, default=0.1 diff --git a/sklearn/ensemble/_iforest.py b/sklearn/ensemble/_iforest.py index 89ae067a43dbb..15ab0d6b382eb 100644 --- a/sklearn/ensemble/_iforest.py +++ b/sklearn/ensemble/_iforest.py @@ -22,7 +22,6 @@ from ..utils.parallel import Parallel, delayed from ..utils.validation import _num_samples, check_is_fitted, validate_data from ._bagging import BaseBagging -from ._base import _partition_estimators __all__ = ["IsolationForest"] @@ -120,10 +119,9 @@ class IsolationForest(OutlierMixin, BaseBagging): is performed. n_jobs : int, default=None - The number of jobs to run in parallel for both :meth:`fit` and - :meth:`predict`. ``None`` means 1 unless in a - :obj:`joblib.parallel_backend` context. ``-1`` means using all - processors. See :term:`Glossary ` for more details. + The number of jobs to run in parallel for :meth:`fit`. ``None`` means 1 + unless in a :obj:`joblib.parallel_backend` context. ``-1`` means using + all processors. See :term:`Glossary ` for more details. random_state : int, RandomState instance or None, default=None Controls the pseudo-randomness of the selection of the feature @@ -596,14 +594,16 @@ def _compute_score_samples(self, X, subsample_features): average_path_length_max_samples = _average_path_length([self._max_samples]) - # Note: using joblib.parallel_backend allows for setting the number of jobs - # separately from the n_jobs parameter specified during fit. This is useful for - # parallelizing the computation of the scores, which will not require a high - # n_jobs value for e.g. < 1k samples. - n_jobs, _, _ = _partition_estimators(self.n_estimators, None) + # Note: we use default n_jobs value, i.e. sequential computation, which + # we expect to be more performant that parallelizing for small number + # of samples, e.g. < 1k samples. Default n_jobs value can be overriden + # by using joblib.parallel_backend context manager around + # ._compute_score_samples. Using a higher n_jobs may speed up the + # computation of the scores, e.g. for > 1k samples. See + # https://github.com/scikit-learn/scikit-learn/pull/28622 for more + # details. lock = threading.Lock() Parallel( - n_jobs=n_jobs, verbose=self.verbose, require="sharedmem", )( @@ -633,12 +633,6 @@ def _compute_score_samples(self, X, subsample_features): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } tags.input_tags.allow_nan = True return tags diff --git a/sklearn/ensemble/_weight_boosting.py b/sklearn/ensemble/_weight_boosting.py index 7780230b046cb..8503c4fdb8ae7 100644 --- a/sklearn/ensemble/_weight_boosting.py +++ b/sklearn/ensemble/_weight_boosting.py @@ -312,6 +312,11 @@ def feature_importances_(self): "feature_importances_ attribute" ) from e + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + def _samme_proba(estimator, n_classes, X): """Calculate algorithm 4, step 2, equation c) of Zhu et al [1]. @@ -858,16 +863,6 @@ def predict_log_proba(self, X): """ return np.log(self.predict_proba(X)) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class AdaBoostRegressor(_RoutingNotSupportedMixin, RegressorMixin, BaseWeightBoosting): """An AdaBoost regressor. @@ -1176,13 +1171,3 @@ def staged_predict(self, X): for i, _ in enumerate(self.estimators_, 1): yield self._get_median_predict(X, limit=i) - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags diff --git a/sklearn/exceptions.py b/sklearn/exceptions.py index caba4e174817a..1c9162dc760f9 100644 --- a/sklearn/exceptions.py +++ b/sklearn/exceptions.py @@ -14,6 +14,7 @@ "UndefinedMetricWarning", "PositiveSpectrumWarning", "UnsetMetadataPassedError", + "EstimatorCheckFailedWarning", ] @@ -189,3 +190,60 @@ def __str__(self): "https://scikit-learn.org/stable/model_persistence.html" "#security-maintainability-limitations" ) + + +class EstimatorCheckFailedWarning(UserWarning): + """Warning raised when an estimator check from the common tests fails. + + Parameters + ---------- + estimator : estimator object + Estimator instance for which the test failed. + + check_name : str + Name of the check that failed. + + exception : Exception + Exception raised by the failed check. + + status : str + Status of the check. + + expected_to_fail : bool + Whether the check was expected to fail. + + expected_to_fail_reason : str + Reason for the expected failure. + """ + + def __init__( + self, + *, + estimator, + check_name: str, + exception: Exception, + status: str, + expected_to_fail: bool, + expected_to_fail_reason: str, + ): + self.estimator = estimator + self.check_name = check_name + self.exception = exception + self.status = status + self.expected_to_fail = expected_to_fail + self.expected_to_fail_reason = expected_to_fail_reason + + def __repr__(self): + expected_to_fail_str = ( + f"Expected to fail: {self.expected_to_fail_reason}" + if self.expected_to_fail + else "Not expected to fail" + ) + return ( + f"Test {self.check_name} failed for estimator {self.estimator!r}.\n" + f"Expected to fail reason: {expected_to_fail_str}\n" + f"Exception: {self.exception}" + ) + + def __str__(self): + return self.__repr__() diff --git a/sklearn/feature_selection/_from_model.py b/sklearn/feature_selection/_from_model.py index 28af66d524623..d73b53eea647e 100644 --- a/sklearn/feature_selection/_from_model.py +++ b/sklearn/feature_selection/_from_model.py @@ -501,5 +501,6 @@ def get_metadata_routing(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse tags.input_tags.allow_nan = get_tags(self.estimator).input_tags.allow_nan return tags diff --git a/sklearn/feature_selection/_rfe.py b/sklearn/feature_selection/_rfe.py index bd6a28b97b557..3c2a351440342 100644 --- a/sklearn/feature_selection/_rfe.py +++ b/sklearn/feature_selection/_rfe.py @@ -521,6 +521,7 @@ def __sklearn_tags__(self): if tags.regressor_tags is not None: tags.regressor_tags.poor_score = True tags.target_tags.required = True + tags.input_tags.sparse = sub_estimator_tags.input_tags.sparse tags.input_tags.allow_nan = sub_estimator_tags.input_tags.allow_nan return tags diff --git a/sklearn/feature_selection/_sequential.py b/sklearn/feature_selection/_sequential.py index ac5f13fd00e7d..80cf1fb171cc0 100644 --- a/sklearn/feature_selection/_sequential.py +++ b/sklearn/feature_selection/_sequential.py @@ -78,7 +78,7 @@ class SequentialFeatureSelector(SelectorMixin, MetaEstimatorMixin, BaseEstimator scoring : str or callable, default=None A single str (see :ref:`scoring_parameter`) or a callable - (see :ref:`scoring`) to evaluate the predictions on the test set. + (see :ref:`scoring_callable`) to evaluate the predictions on the test set. NOTE that when using a custom scorer, it should return a single value. @@ -329,6 +329,7 @@ def _get_support_mask(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = get_tags(self.estimator).input_tags.allow_nan + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags def get_metadata_routing(self): diff --git a/sklearn/feature_selection/_univariate_selection.py b/sklearn/feature_selection/_univariate_selection.py index 7933818a6a19b..855ba5ad70f12 100644 --- a/sklearn/feature_selection/_univariate_selection.py +++ b/sklearn/feature_selection/_univariate_selection.py @@ -203,9 +203,12 @@ def chi2(X, y): This score can be used to select the `n_features` features with the highest values for the test chi-squared statistic from X, which must - contain only **non-negative features** such as booleans or frequencies + contain only **non-negative integer feature values** such as booleans or frequencies (e.g., term counts in document classification), relative to the classes. + If some of your features are continuous, you need to bin them, for + example by using :class:`~sklearn.preprocessing.KBinsDiscretizer`. + Recall that the chi-square test measures dependence between stochastic variables, so using this function "weeds out" the features that are the most likely to be independent of class and therefore irrelevant for @@ -581,6 +584,7 @@ def _check_params(self, X, y): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.target_tags.required = True + tags.input_tags.sparse = True return tags diff --git a/sklearn/feature_selection/_variance_threshold.py b/sklearn/feature_selection/_variance_threshold.py index 1aab9080b964d..f26d70ecf8f82 100644 --- a/sklearn/feature_selection/_variance_threshold.py +++ b/sklearn/feature_selection/_variance_threshold.py @@ -137,4 +137,5 @@ def _get_support_mask(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = True + tags.input_tags.sparse = True return tags diff --git a/sklearn/impute/_base.py b/sklearn/impute/_base.py index faf1f9e23b678..7a8f2cc4483e2 100644 --- a/sklearn/impute/_base.py +++ b/sklearn/impute/_base.py @@ -739,6 +739,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.allow_nan = is_pandas_na(self.missing_values) or is_scalar_nan( self.missing_values ) @@ -1130,5 +1131,6 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = True tags.input_tags.string = True + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = [] return tags diff --git a/sklearn/inspection/_permutation_importance.py b/sklearn/inspection/_permutation_importance.py index fb3c646a271a6..74000aa9e8556 100644 --- a/sklearn/inspection/_permutation_importance.py +++ b/sklearn/inspection/_permutation_importance.py @@ -177,7 +177,7 @@ def permutation_importance( If `scoring` represents a single score, one can use: - a single string (see :ref:`scoring_parameter`); - - a callable (see :ref:`scoring`) that returns a single value. + - a callable (see :ref:`scoring_callable`) that returns a single value. If `scoring` represents multiple scores, one can use: diff --git a/sklearn/kernel_approximation.py b/sklearn/kernel_approximation.py index 96f9b7e9d4778..35da4d08dcbf4 100644 --- a/sklearn/kernel_approximation.py +++ b/sklearn/kernel_approximation.py @@ -235,6 +235,11 @@ def transform(self, X): return data_sketch + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class RBFSampler(ClassNamePrefixFeaturesOutMixin, TransformerMixin, BaseEstimator): """Approximate a RBF kernel feature map using random Fourier features. @@ -404,6 +409,7 @@ def transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags @@ -826,6 +832,7 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.requires_fit = False tags.input_tags.positive_only = True + tags.input_tags.sparse = True return tags @@ -1094,10 +1101,6 @@ def _get_kernel_params(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_transformer_preserves_dtypes": ( - "dtypes are preserved but not at a close enough precision" - ) - } + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags diff --git a/sklearn/kernel_ridge.py b/sklearn/kernel_ridge.py index 983b463508c5b..29e744647acc9 100644 --- a/sklearn/kernel_ridge.py +++ b/sklearn/kernel_ridge.py @@ -169,6 +169,7 @@ def _get_kernel(self, X, Y=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.pairwise = self.kernel == "precomputed" return tags diff --git a/sklearn/linear_model/_base.py b/sklearn/linear_model/_base.py index 3bb3b8b7626d8..bb71cbe9ed550 100644 --- a/sklearn/linear_model/_base.py +++ b/sklearn/linear_model/_base.py @@ -687,6 +687,11 @@ def rmatvec(b): self._set_intercept(X_offset, y_offset, X_scale) return self + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = not self.positive + return tags + def _check_precomputed_gram_matrix( X, precompute, X_offset, X_scale, rtol=None, atol=1e-5 diff --git a/sklearn/linear_model/_bayes.py b/sklearn/linear_model/_bayes.py index 555b4ec13df69..b6527d4f22b1f 100644 --- a/sklearn/linear_model/_bayes.py +++ b/sklearn/linear_model/_bayes.py @@ -430,16 +430,6 @@ def _log_marginal_likelihood( return score - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - ############################################################################### # ARD (Automatic Relevance Determination) regression diff --git a/sklearn/linear_model/_coordinate_descent.py b/sklearn/linear_model/_coordinate_descent.py index 2dbb83c82fbaa..b98cf08925910 100644 --- a/sklearn/linear_model/_coordinate_descent.py +++ b/sklearn/linear_model/_coordinate_descent.py @@ -1149,6 +1149,11 @@ def _decision_function(self, X): else: return super()._decision_function(X) + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + ############################################################################### # Lasso model @@ -1864,6 +1869,13 @@ def get_metadata_routing(self): ) return router + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + multitask = self._is_multitask() + tags.input_tags.sparse = not multitask + tags.target_tags.multi_output = multitask + return tags + class LassoCV(RegressorMixin, LinearModelCV): """Lasso linear model with iterative fitting along a regularization path. @@ -2076,11 +2088,6 @@ def _get_estimator(self): def _is_multitask(self): return False - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags.target_tags.multi_output = False - return tags - def fit(self, X, y, sample_weight=None, **params): """Fit Lasso model with coordinate descent. @@ -2357,11 +2364,6 @@ def _get_estimator(self): def _is_multitask(self): return False - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags.target_tags.multi_output = False - return tags - def fit(self, X, y, sample_weight=None, **params): """Fit ElasticNet model with coordinate descent. @@ -2654,6 +2656,7 @@ def fit(self, X, y): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = False tags.target_tags.multi_output = True tags.target_tags.single_output = False return tags @@ -3024,7 +3027,6 @@ def _is_multitask(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags.target_tags.multi_output = True tags.target_tags.single_output = False return tags @@ -3265,7 +3267,6 @@ def _is_multitask(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags.target_tags.multi_output = True tags.target_tags.single_output = False return tags diff --git a/sklearn/linear_model/_glm/glm.py b/sklearn/linear_model/_glm/glm.py index 093a813f60550..fc31f9825d2e5 100644 --- a/sklearn/linear_model/_glm/glm.py +++ b/sklearn/linear_model/_glm/glm.py @@ -442,6 +442,7 @@ def score(self, X, y, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True try: # Create instance of BaseLoss if fit wasn't called yet. This is necessary as # TweedieRegressor might set the used loss during fit different from diff --git a/sklearn/linear_model/_huber.py b/sklearn/linear_model/_huber.py index 9e41cc4eae3b5..598d208df535c 100644 --- a/sklearn/linear_model/_huber.py +++ b/sklearn/linear_model/_huber.py @@ -132,10 +132,10 @@ class HuberRegressor(LinearModel, RegressorMixin, BaseEstimator): ``|(y - Xw - c) / sigma| < epsilon`` and the absolute loss for the samples where ``|(y - Xw - c) / sigma| > epsilon``, where the model coefficients ``w``, the intercept ``c`` and the scale ``sigma`` are parameters - to be optimized. The parameter sigma makes sure that if y is scaled up - or down by a certain factor, one does not need to rescale epsilon to + to be optimized. The parameter `sigma` makes sure that if `y` is scaled up + or down by a certain factor, one does not need to rescale `epsilon` to achieve the same robustness. Note that this does not take into account - the fact that the different features of X may be of different scales. + the fact that the different features of `X` may be of different scales. The Huber loss function has the advantage of not being heavily influenced by the outliers while not completely ignoring their effect. @@ -219,9 +219,9 @@ class HuberRegressor(LinearModel, RegressorMixin, BaseEstimator): References ---------- .. [1] Peter J. Huber, Elvezio M. Ronchetti, Robust Statistics - Concomitant scale estimates, pg 172 - .. [2] Art B. Owen (2006), A robust hybrid of lasso and ridge regression. - https://statweb.stanford.edu/~owen/reports/hhu.pdf + Concomitant scale estimates, p. 172 + .. [2] Art B. Owen (2006), `A robust hybrid of lasso and ridge regression. + `_ Examples -------- @@ -351,3 +351,8 @@ def fit(self, X, y, sample_weight=None): residual = np.abs(y - safe_sparse_dot(X, self.coef_) - self.intercept_) self.outliers_ = residual > self.scale_ * self.epsilon return self + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags diff --git a/sklearn/linear_model/_logistic.py b/sklearn/linear_model/_logistic.py index fe5ee918066fa..291c3972eb3e5 100644 --- a/sklearn/linear_model/_logistic.py +++ b/sklearn/linear_model/_logistic.py @@ -1459,13 +1459,7 @@ def predict_log_proba(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks.update( - { - "check_non_transformer_estimators_n_iter": ( - "n_iter_ cannot be easily accessed." - ) - } - ) + tags.input_tags.sparse = True return tags @@ -2285,3 +2279,8 @@ def _get_scorer(self): """ scoring = self.scoring or "accuracy" return get_scorer(scoring) + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags diff --git a/sklearn/linear_model/_perceptron.py b/sklearn/linear_model/_perceptron.py index f656b44c0c676..e93200ba385fa 100644 --- a/sklearn/linear_model/_perceptron.py +++ b/sklearn/linear_model/_perceptron.py @@ -224,13 +224,3 @@ def __init__( class_weight=class_weight, n_jobs=n_jobs, ) - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags diff --git a/sklearn/linear_model/_quantile.py b/sklearn/linear_model/_quantile.py index 883a41558f2f7..446d232958e8d 100644 --- a/sklearn/linear_model/_quantile.py +++ b/sklearn/linear_model/_quantile.py @@ -294,3 +294,8 @@ def fit(self, X, y, sample_weight=None): self.coef_ = params self.intercept_ = 0.0 return self + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags diff --git a/sklearn/linear_model/_ransac.py b/sklearn/linear_model/_ransac.py index b0678bf53d696..90dc6d6bc5e70 100644 --- a/sklearn/linear_model/_ransac.py +++ b/sklearn/linear_model/_ransac.py @@ -15,7 +15,7 @@ clone, ) from ..exceptions import ConvergenceWarning -from ..utils import check_consistent_length, check_random_state +from ..utils import check_consistent_length, check_random_state, get_tags from ..utils._bunch import Bunch from ..utils._param_validation import ( HasMethods, @@ -724,10 +724,8 @@ def get_metadata_routing(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } + if self.estimator is None: + tags.input_tags.sparse = True # default estimator is LinearRegression + else: + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags diff --git a/sklearn/linear_model/_ridge.py b/sklearn/linear_model/_ridge.py index 56bb9fbc50570..9a94ba1caec1c 100644 --- a/sklearn/linear_model/_ridge.py +++ b/sklearn/linear_model/_ridge.py @@ -665,10 +665,8 @@ def _ridge_regression( if y.ndim > 2: raise ValueError("Target y has the wrong shape %s" % str(y.shape)) - ravel = False if y.ndim == 1: y = xp.reshape(y, (-1, 1)) - ravel = True n_samples_, n_targets = y.shape @@ -1253,12 +1251,8 @@ def fit(self, X, y, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.array_api_support = True - tags._xfail_checks.update( - { - "check_non_transformer_estimators_n_iter": ( - "n_iter_ cannot be easily accessed." - ) - } + tags.input_tags.sparse = (self.solver != "svd") and ( + self.solver != "cholesky" or not self.fit_intercept ) return tags @@ -1579,12 +1573,8 @@ def fit(self, X, y, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks.update( - { - "check_non_transformer_estimators_n_iter": ( - "n_iter_ cannot be easily accessed." - ) - } + tags.input_tags.sparse = (self.solver != "svd") and ( + self.solver != "cholesky" or not self.fit_intercept ) return tags @@ -2552,6 +2542,11 @@ def _get_scorer(self): def cv_values_(self): return self.cv_results_ + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class RidgeCV(MultiOutputMixin, RegressorMixin, _BaseRidgeCV): """Ridge regression with built-in cross-validation. @@ -2615,7 +2610,7 @@ class RidgeCV(MultiOutputMixin, RegressorMixin, _BaseRidgeCV): store_cv_results : bool, default=False Flag indicating if the cross-validation values corresponding to - each alpha should be stored in the ``cv_values_`` attribute (see + each alpha should be stored in the ``cv_results_`` attribute (see below). This flag is only compatible with ``cv=None`` (i.e. using Leave-One-Out Cross-Validation). @@ -2741,15 +2736,6 @@ def fit(self, X, y, sample_weight=None, **params): super().fit(X, y, sample_weight=sample_weight, **params) return self - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "GridSearchCV does not forward the weights to the scorer by default." - ), - } - return tags - class RidgeClassifierCV(_RidgeClassifierMixin, _BaseRidgeCV): """Ridge classifier with built-in cross-validation. diff --git a/sklearn/linear_model/_stochastic_gradient.py b/sklearn/linear_model/_stochastic_gradient.py index d5f2247e2af34..d4c196a6fc8ca 100644 --- a/sklearn/linear_model/_stochastic_gradient.py +++ b/sklearn/linear_model/_stochastic_gradient.py @@ -941,6 +941,11 @@ def fit(self, X, y, coef_init=None, intercept_init=None, sample_weight=None): sample_weight=sample_weight, ) + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class SGDClassifier(BaseSGDClassifier): """Linear classifiers (SVM, logistic regression, etc.) with SGD training. @@ -1382,16 +1387,6 @@ def predict_log_proba(self, X): """ return np.log(self.predict_proba(X)) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class BaseSGDRegressor(RegressorMixin, BaseSGD): loss_functions = { @@ -1782,6 +1777,11 @@ def _fit_regressor( else: self.intercept_ = np.atleast_1d(intercept) + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class SGDRegressor(BaseSGDRegressor): """Linear model fitted by minimizing a regularized empirical loss with SGD. @@ -2073,16 +2073,6 @@ def __init__( average=average, ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class SGDOneClassSVM(OutlierMixin, BaseSGD): """Solves linear One-Class SVM using Stochastic Gradient Descent. @@ -2656,10 +2646,5 @@ def predict(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } + tags.input_tags.sparse = True return tags diff --git a/sklearn/manifold/_isomap.py b/sklearn/manifold/_isomap.py index ee302bc07b384..90154470c18a4 100644 --- a/sklearn/manifold/_isomap.py +++ b/sklearn/manifold/_isomap.py @@ -438,4 +438,5 @@ def transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.transformer_tags.preserves_dtype = ["float64", "float32"] + tags.input_tags.sparse = True return tags diff --git a/sklearn/manifold/_spectral_embedding.py b/sklearn/manifold/_spectral_embedding.py index ebd5d7c5b651b..d3d45ec0773c3 100644 --- a/sklearn/manifold/_spectral_embedding.py +++ b/sklearn/manifold/_spectral_embedding.py @@ -650,6 +650,7 @@ def __init__( def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.pairwise = self.affinity in [ "precomputed", "precomputed_nearest_neighbors", diff --git a/sklearn/metrics/_classification.py b/sklearn/metrics/_classification.py index c320183380a07..dc9252c2c9fda 100644 --- a/sklearn/metrics/_classification.py +++ b/sklearn/metrics/_classification.py @@ -15,7 +15,7 @@ from numbers import Integral, Real import numpy as np -from scipy.sparse import coo_matrix, csr_matrix +from scipy.sparse import coo_matrix, csr_matrix, issparse from scipy.special import xlogy from ..exceptions import UndefinedMetricWarning @@ -28,9 +28,15 @@ ) from ..utils._array_api import ( _average, + _bincount, _count_nonzero, + _find_matching_floating_dtype, _is_numpy_namespace, + _searchsorted, + _setdiff1d, + _tolist, _union1d, + device, get_namespace, get_namespace_and_device, ) @@ -152,16 +158,10 @@ def _check_targets(y_true, y_pred): "y_pred": ["array-like", "sparse matrix"], "normalize": ["boolean"], "sample_weight": ["array-like", None], - "zero_division": [ - Options(Real, {0.0, 1.0, np.nan}), - StrOptions({"warn"}), - ], }, prefer_skip_nested_validation=True, ) -def accuracy_score( - y_true, y_pred, *, normalize=True, sample_weight=None, zero_division="warn" -): +def accuracy_score(y_true, y_pred, *, normalize=True, sample_weight=None): """Accuracy classification score. In multilabel classification, this function computes subset accuracy: @@ -185,13 +185,6 @@ def accuracy_score( sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" - Sets the value to return when there is a zero division, - e.g. when `y_true` and `y_pred` are empty. - If set to "warn", returns 0.0 input, but a warning is also raised. - - versionadded:: 1.6 - Returns ------- score : float or int @@ -234,15 +227,6 @@ def accuracy_score( y_type, y_true, y_pred = _check_targets(y_true, y_pred) check_consistent_length(y_true, y_pred, sample_weight) - if _num_samples(y_true) == 0: - if zero_division == "warn": - msg = ( - "accuracy() is ill-defined and set to 0.0. Use the `zero_division` " - "param to control this behavior." - ) - warnings.warn(msg, UndefinedMetricWarning) - return _check_zero_division(zero_division) - if y_type.startswith("multilabel"): if _is_numpy_namespace(xp): differing_labels = count_nonzero(y_true - y_pred, axis=1) @@ -543,9 +527,11 @@ def multilabel_confusion_matrix( [1, 2]]]) """ y_true, y_pred = attach_unique(y_true, y_pred) + xp, _ = get_namespace(y_true, y_pred) + device_ = device(y_true, y_pred) y_type, y_true, y_pred = _check_targets(y_true, y_pred) if sample_weight is not None: - sample_weight = column_or_1d(sample_weight) + sample_weight = column_or_1d(sample_weight, device=device_) check_consistent_length(y_true, y_pred, sample_weight) if y_type not in ("binary", "multiclass", "multilabel-indicator"): @@ -556,9 +542,11 @@ def multilabel_confusion_matrix( labels = present_labels n_labels = None else: - n_labels = len(labels) - labels = np.hstack( - [labels, np.setdiff1d(present_labels, labels, assume_unique=True)] + labels = xp.asarray(labels, device=device_) + n_labels = labels.shape[0] + labels = xp.concat( + [labels, _setdiff1d(present_labels, labels, assume_unique=True, xp=xp)], + axis=-1, ) if y_true.ndim == 1: @@ -578,108 +566,102 @@ def multilabel_confusion_matrix( tp = y_true == y_pred tp_bins = y_true[tp] if sample_weight is not None: - tp_bins_weights = np.asarray(sample_weight)[tp] + tp_bins_weights = sample_weight[tp] else: tp_bins_weights = None - if len(tp_bins): - tp_sum = np.bincount( - tp_bins, weights=tp_bins_weights, minlength=len(labels) + if tp_bins.shape[0]: + tp_sum = _bincount( + tp_bins, weights=tp_bins_weights, minlength=labels.shape[0], xp=xp ) else: # Pathological case - true_sum = pred_sum = tp_sum = np.zeros(len(labels)) - if len(y_pred): - pred_sum = np.bincount(y_pred, weights=sample_weight, minlength=len(labels)) - if len(y_true): - true_sum = np.bincount(y_true, weights=sample_weight, minlength=len(labels)) + true_sum = pred_sum = tp_sum = xp.zeros(labels.shape[0]) + if y_pred.shape[0]: + pred_sum = _bincount( + y_pred, weights=sample_weight, minlength=labels.shape[0], xp=xp + ) + if y_true.shape[0]: + true_sum = _bincount( + y_true, weights=sample_weight, minlength=labels.shape[0], xp=xp + ) # Retain only selected labels - indices = np.searchsorted(sorted_labels, labels[:n_labels]) - tp_sum = tp_sum[indices] - true_sum = true_sum[indices] - pred_sum = pred_sum[indices] + indices = _searchsorted(sorted_labels, labels[:n_labels], xp=xp) + tp_sum = xp.take(tp_sum, indices, axis=0) + true_sum = xp.take(true_sum, indices, axis=0) + pred_sum = xp.take(pred_sum, indices, axis=0) else: sum_axis = 1 if samplewise else 0 # All labels are index integers for multilabel. # Select labels: - if not np.array_equal(labels, present_labels): - if np.max(labels) > np.max(present_labels): + if labels.shape != present_labels.shape or xp.any( + xp.not_equal(labels, present_labels) + ): + if xp.max(labels) > xp.max(present_labels): raise ValueError( "All labels must be in [0, n labels) for " "multilabel targets. " - "Got %d > %d" % (np.max(labels), np.max(present_labels)) + "Got %d > %d" % (xp.max(labels), xp.max(present_labels)) ) - if np.min(labels) < 0: + if xp.min(labels) < 0: raise ValueError( "All labels must be in [0, n labels) for " "multilabel targets. " - "Got %d < 0" % np.min(labels) + "Got %d < 0" % xp.min(labels) ) if n_labels is not None: y_true = y_true[:, labels[:n_labels]] y_pred = y_pred[:, labels[:n_labels]] + if issparse(y_true) or issparse(y_pred): + true_and_pred = y_true.multiply(y_pred) + else: + true_and_pred = xp.multiply(y_true, y_pred) + # calculate weighted counts - true_and_pred = y_true.multiply(y_pred) - tp_sum = count_nonzero( - true_and_pred, axis=sum_axis, sample_weight=sample_weight + tp_sum = _count_nonzero( + true_and_pred, + axis=sum_axis, + sample_weight=sample_weight, + xp=xp, + device=device_, + ) + pred_sum = _count_nonzero( + y_pred, + axis=sum_axis, + sample_weight=sample_weight, + xp=xp, + device=device_, + ) + true_sum = _count_nonzero( + y_true, + axis=sum_axis, + sample_weight=sample_weight, + xp=xp, + device=device_, ) - pred_sum = count_nonzero(y_pred, axis=sum_axis, sample_weight=sample_weight) - true_sum = count_nonzero(y_true, axis=sum_axis, sample_weight=sample_weight) fp = pred_sum - tp_sum fn = true_sum - tp_sum tp = tp_sum if sample_weight is not None and samplewise: - sample_weight = np.array(sample_weight) - tp = np.array(tp) - fp = np.array(fp) - fn = np.array(fn) + tp = xp.asarray(tp) + fp = xp.asarray(fp) + fn = xp.asarray(fn) tn = sample_weight * y_true.shape[1] - tp - fp - fn elif sample_weight is not None: - tn = sum(sample_weight) - tp - fp - fn + tn = xp.sum(sample_weight) - tp - fp - fn elif samplewise: tn = y_true.shape[1] - tp - fp - fn else: tn = y_true.shape[0] - tp - fp - fn - return np.array([tn, fp, fn, tp]).T.reshape(-1, 2, 2) - - -def _metric_handle_division(*, numerator, denominator, metric, zero_division): - """Helper to handle zero-division. - - Parameters - ---------- - numerator : numbers.Real - The numerator of the division. - denominator : numbers.Real - The denominator of the division. - metric : str - Name of the caller metric function. - zero_division : {0.0, 1.0, "warn"} - The strategy to use when encountering 0-denominator. - - Returns - ------- - result : numbers.Real - The resulting of the division - is_zero_division : bool - Whether or not we encountered a zero division. This value could be - required to early return `result` in the "caller" function. - """ - if np.isclose(denominator, 0): - if zero_division == "warn": - msg = f"{metric} is ill-defined and set to 0.0. Use the `zero_division` " - "param to control this behavior." - warnings.warn(msg, UndefinedMetricWarning, stacklevel=2) - return _check_zero_division(zero_division), True - return numerator / denominator, False + return xp.reshape(xp.stack([tn, fp, fn, tp]).T, (-1, 2, 2)) @validate_params( @@ -689,16 +671,10 @@ def _metric_handle_division(*, numerator, denominator, metric, zero_division): "labels": ["array-like", None], "weights": [StrOptions({"linear", "quadratic"}), None], "sample_weight": ["array-like", None], - "zero_division": [ - StrOptions({"warn"}), - Options(Real, {0.0, 1.0, np.nan}), - ], }, prefer_skip_nested_validation=True, ) -def cohen_kappa_score( - y1, y2, *, labels=None, weights=None, sample_weight=None, zero_division="warn" -): +def cohen_kappa_score(y1, y2, *, labels=None, weights=None, sample_weight=None): r"""Compute Cohen's kappa: a statistic that measures inter-annotator agreement. This function computes Cohen's kappa [1]_, a score that expresses the level @@ -737,14 +713,6 @@ class labels [2]_. sample_weight : array-like of shape (n_samples,), default=None Sample weights. - zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" - Sets the return value when there is a zero division. This is the case when both - labelings `y1` and `y2` both exclusively contain the 0 class (e. g. - `[0, 0, 0, 0]`) (or if both are empty). If set to "warn", returns `0.0`, but a - warning is also raised. - - .. versionadded:: 1.6 - Returns ------- kappa : float @@ -774,18 +742,7 @@ class labels [2]_. n_classes = confusion.shape[0] sum0 = np.sum(confusion, axis=0) sum1 = np.sum(confusion, axis=1) - - numerator = np.outer(sum0, sum1) - denominator = np.sum(sum0) - expected, is_zero_division = _metric_handle_division( - numerator=numerator, - denominator=denominator, - metric="cohen_kappa_score()", - zero_division=zero_division, - ) - - if is_zero_division: - return expected + expected = np.outer(sum0, sum1) / np.sum(sum0) if weights is None: w_mat = np.ones([n_classes, n_classes], dtype=int) @@ -798,18 +755,8 @@ class labels [2]_. else: w_mat = (w_mat - w_mat.T) ** 2 - numerator = np.sum(w_mat * confusion) - denominator = np.sum(w_mat * expected) - score, is_zero_division = _metric_handle_division( - numerator=numerator, - denominator=denominator, - metric="cohen_kappa_score()", - zero_division=zero_division, - ) - - if is_zero_division: - return score - return 1 - score + k = np.sum(w_mat * confusion) / np.sum(w_mat * expected) + return 1 - k @validate_params( @@ -911,6 +858,8 @@ def jaccard_score( there are no negative values in predictions and labels. If set to "warn", this acts like 0, but a warning is also raised. + .. versionadded:: 0.24 + Returns ------- score : float or ndarray of shape (n_unique_labels,), dtype=np.float64 @@ -1015,15 +964,10 @@ def jaccard_score( "y_true": ["array-like"], "y_pred": ["array-like"], "sample_weight": ["array-like", None], - "zero_division": [ - Options(Real, {0.0, 1.0}), - "nan", - StrOptions({"warn"}), - ], }, prefer_skip_nested_validation=True, ) -def matthews_corrcoef(y_true, y_pred, *, sample_weight=None, zero_division="warn"): +def matthews_corrcoef(y_true, y_pred, *, sample_weight=None): """Compute the Matthews correlation coefficient (MCC). The Matthews correlation coefficient is used in machine learning as a @@ -1054,13 +998,6 @@ def matthews_corrcoef(y_true, y_pred, *, sample_weight=None, zero_division="warn .. versionadded:: 0.18 - zero_division : {"warn", 0.0, 1.0, np.nan}, default="warn" - Sets the value to return when there is a zero division, i.e. when all - predictions and labels are negative. If set to "warn", this acts like 0, - but a warning is also raised. - - .. versionadded:: 1.6 - Returns ------- mcc : float @@ -1114,13 +1051,7 @@ def matthews_corrcoef(y_true, y_pred, *, sample_weight=None, zero_division="warn cov_ytyt = n_samples**2 - np.dot(t_sum, t_sum) if cov_ypyp * cov_ytyt == 0: - if zero_division == "warn": - msg = ( - "Matthews correlation coefficient is ill-defined and being set to 0.0. " - "Use `zero_division` to control this behaviour." - ) - warnings.warn(msg, UndefinedMetricWarning, stacklevel=2) - return _check_zero_division(zero_division) + return 0.0 else: return cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp) @@ -1295,7 +1226,7 @@ def f1_score( average : {'micro', 'macro', 'samples', 'weighted', 'binary'} or None, \ default='binary' This parameter is required for multiclass/multilabel targets. - If ``None``, the scores for each class are returned. Otherwise, this + If ``None``, the metrics for each class are returned. Otherwise, this determines the type of averaging performed on the data: ``'binary'``: @@ -1366,11 +1297,11 @@ def f1_score( >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] >>> f1_score(y_true, y_pred, average='macro') - np.float64(0.26...) + 0.26... >>> f1_score(y_true, y_pred, average='micro') - np.float64(0.33...) + 0.33... >>> f1_score(y_true, y_pred, average='weighted') - np.float64(0.26...) + 0.26... >>> f1_score(y_true, y_pred, average=None) array([0.8, 0. , 0. ]) @@ -1378,9 +1309,9 @@ def f1_score( >>> y_true_empty = [0, 0, 0, 0, 0, 0] >>> y_pred_empty = [0, 0, 0, 0, 0, 0] >>> f1_score(y_true_empty, y_pred_empty) - np.float64(0.0...) + 0.0... >>> f1_score(y_true_empty, y_pred_empty, zero_division=1.0) - np.float64(1.0...) + 1.0... >>> f1_score(y_true_empty, y_pred_empty, zero_division=np.nan) nan... @@ -1498,7 +1429,7 @@ def fbeta_score( average : {'micro', 'macro', 'samples', 'weighted', 'binary'} or None, \ default='binary' This parameter is required for multiclass/multilabel targets. - If ``None``, the scores for each class are returned. Otherwise, this + If ``None``, the metrics for each class are returned. Otherwise, this determines the type of averaging performed on the data: ``'binary'``: @@ -1570,17 +1501,17 @@ def fbeta_score( >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] >>> fbeta_score(y_true, y_pred, average='macro', beta=0.5) - np.float64(0.23...) + 0.23... >>> fbeta_score(y_true, y_pred, average='micro', beta=0.5) - np.float64(0.33...) + 0.33... >>> fbeta_score(y_true, y_pred, average='weighted', beta=0.5) - np.float64(0.23...) + 0.23... >>> fbeta_score(y_true, y_pred, average=None, beta=0.5) array([0.71..., 0. , 0. ]) >>> y_pred_empty = [0, 0, 0, 0, 0, 0] >>> fbeta_score(y_true, y_pred_empty, ... average="macro", zero_division=np.nan, beta=0.5) - np.float64(0.12...) + 0.12... """ _, _, f, _ = precision_recall_fscore_support( @@ -1609,12 +1540,14 @@ def _prf_divide( The metric, modifier and average arguments are used only for determining an appropriate warning. """ - mask = denominator == 0.0 - denominator = denominator.copy() + xp, _ = get_namespace(numerator, denominator) + dtype_float = _find_matching_floating_dtype(numerator, denominator, xp=xp) + mask = denominator == 0 + denominator = xp.asarray(denominator, copy=True, dtype=dtype_float) denominator[mask] = 1 # avoid infs/nans - result = numerator / denominator + result = xp.asarray(numerator, dtype=dtype_float) / denominator - if not np.any(mask): + if not xp.any(mask): return result # set those with 0 denominator to `zero_division`, and 0 when "warn" @@ -1663,7 +1596,7 @@ def _check_set_wise_labels(y_true, y_pred, average, labels, pos_label): y_type, y_true, y_pred = _check_targets(y_true, y_pred) # Convert to Python primitive type to avoid NumPy type / Python str # comparison. See https://github.com/numpy/numpy/issues/6784 - present_labels = unique_labels(y_true, y_pred).tolist() + present_labels = _tolist(unique_labels(y_true, y_pred)) if average == "binary": if y_type == "binary": if pos_label not in present_labels: @@ -1878,11 +1811,11 @@ def precision_recall_fscore_support( >>> y_true = np.array(['cat', 'dog', 'pig', 'cat', 'dog', 'pig']) >>> y_pred = np.array(['cat', 'pig', 'dog', 'cat', 'cat', 'dog']) >>> precision_recall_fscore_support(y_true, y_pred, average='macro') - (np.float64(0.22...), np.float64(0.33...), np.float64(0.26...), None) + (0.22..., 0.33..., 0.26..., None) >>> precision_recall_fscore_support(y_true, y_pred, average='micro') - (np.float64(0.33...), np.float64(0.33...), np.float64(0.33...), None) + (0.33..., 0.33..., 0.33..., None) >>> precision_recall_fscore_support(y_true, y_pred, average='weighted') - (np.float64(0.22...), np.float64(0.33...), np.float64(0.26...), None) + (0.22..., 0.33..., 0.26..., None) It is possible to compute per-label precisions, recalls, F1-scores and supports instead of averaging: @@ -1909,10 +1842,11 @@ def precision_recall_fscore_support( pred_sum = tp_sum + MCM[:, 0, 1] true_sum = tp_sum + MCM[:, 1, 0] + xp, _ = get_namespace(y_true, y_pred) if average == "micro": - tp_sum = np.array([tp_sum.sum()]) - pred_sum = np.array([pred_sum.sum()]) - true_sum = np.array([true_sum.sum()]) + tp_sum = xp.reshape(xp.sum(tp_sum), (1,)) + pred_sum = xp.reshape(xp.sum(pred_sum), (1,)) + true_sum = xp.reshape(xp.sum(true_sum), (1,)) # Finally, we have all our sufficient statistics. Divide! # beta2 = beta**2 @@ -1955,10 +1889,10 @@ def precision_recall_fscore_support( weights = None if average is not None: - assert average != "binary" or len(precision) == 1 - precision = _nanaverage(precision, weights=weights) - recall = _nanaverage(recall, weights=weights) - f_score = _nanaverage(f_score, weights=weights) + assert average != "binary" or precision.shape[0] == 1 + precision = float(_nanaverage(precision, weights=weights)) + recall = float(_nanaverage(recall, weights=weights)) + f_score = float(_nanaverage(f_score, weights=weights)) true_sum = None # return no support return precision, recall, f_score, true_sum @@ -2220,7 +2154,7 @@ def precision_score( average : {'micro', 'macro', 'samples', 'weighted', 'binary'} or None, \ default='binary' This parameter is required for multiclass/multilabel targets. - If ``None``, the scores for each class are returned. Otherwise, this + If ``None``, the metrics for each class are returned. Otherwise, this determines the type of averaging performed on the data: ``'binary'``: @@ -2289,11 +2223,11 @@ def precision_score( >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] >>> precision_score(y_true, y_pred, average='macro') - np.float64(0.22...) + 0.22... >>> precision_score(y_true, y_pred, average='micro') - np.float64(0.33...) + 0.33... >>> precision_score(y_true, y_pred, average='weighted') - np.float64(0.22...) + 0.22... >>> precision_score(y_true, y_pred, average=None) array([0.66..., 0. , 0. ]) >>> y_pred = [0, 0, 0, 0, 0, 0] @@ -2399,7 +2333,7 @@ def recall_score( average : {'micro', 'macro', 'samples', 'weighted', 'binary'} or None, \ default='binary' This parameter is required for multiclass/multilabel targets. - If ``None``, the scores for each class are returned. Otherwise, this + If ``None``, the metrics for each class are returned. Otherwise, this determines the type of averaging performed on the data: ``'binary'``: @@ -2471,11 +2405,11 @@ def recall_score( >>> y_true = [0, 1, 2, 0, 1, 2] >>> y_pred = [0, 2, 1, 0, 0, 1] >>> recall_score(y_true, y_pred, average='macro') - np.float64(0.33...) + 0.33... >>> recall_score(y_true, y_pred, average='micro') - np.float64(0.33...) + 0.33... >>> recall_score(y_true, y_pred, average='weighted') - np.float64(0.33...) + 0.33... >>> recall_score(y_true, y_pred, average=None) array([1., 0., 0.]) >>> y_true = [0, 0, 0, 0, 0, 0] diff --git a/sklearn/metrics/_ranking.py b/sklearn/metrics/_ranking.py index 958ab3be9cc0d..0303eece69573 100644 --- a/sklearn/metrics/_ranking.py +++ b/sklearn/metrics/_ranking.py @@ -145,6 +145,8 @@ def average_precision_score( Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by :term:`decision_function` on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. average : {'micro', 'samples', 'weighted', 'macro'} or None, \ default='macro' @@ -293,6 +295,8 @@ def det_curve(y_true, y_score, pos_label=None, sample_weight=None): Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. pos_label : int, float, bool or str, default=None The label of the positive class. @@ -914,6 +918,8 @@ def precision_recall_curve( Target scores, can either be probability estimates of the positive class, or non-thresholded measure of decisions (as returned by `decision_function` on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. pos_label : int, float, bool or str, default=None The label of the positive class. @@ -1066,6 +1072,8 @@ def roc_curve( Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. pos_label : int, float, bool or str, default=None The label of the positive class. @@ -1220,6 +1228,8 @@ def label_ranking_average_precision_score(y_true, y_score, *, sample_weight=None Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. sample_weight : array-like of shape (n_samples,), default=None Sample weights. @@ -1320,6 +1330,8 @@ def coverage_error(y_true, y_score, *, sample_weight=None): Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. sample_weight : array-like of shape (n_samples,), default=None Sample weights. @@ -1395,6 +1407,8 @@ def label_ranking_loss(y_true, y_score, *, sample_weight=None): Target scores, can either be probability estimates of the positive class, confidence values, or non-thresholded measure of decisions (as returned by "decision_function" on some classifiers). + For :term:`decision_function` scores, values greater than or equal to + zero should indicate the positive class. sample_weight : array-like of shape (n_samples,), default=None Sample weights. diff --git a/sklearn/metrics/_regression.py b/sklearn/metrics/_regression.py index 62251f9b96188..c5ebe67e34a2e 100644 --- a/sklearn/metrics/_regression.py +++ b/sklearn/metrics/_regression.py @@ -58,11 +58,16 @@ def _check_reg_targets(y_true, y_pred, multioutput, dtype="numeric", xp=None): """Check that y_true and y_pred belong to the same regression task. + To reduce redundancy when calling `_find_matching_floating_dtype`, + please use `_check_reg_targets_with_floating_dtype` instead. + Parameters ---------- - y_true : array-like + y_true : array-like of shape (n_samples,) or (n_samples, n_outputs) + Ground truth (correct) target values. - y_pred : array-like + y_pred : array-like of shape (n_samples,) or (n_samples, n_outputs) + Estimated target values. multioutput : array-like or string in ['raw_values', uniform_average', 'variance_weighted'] or None @@ -137,6 +142,71 @@ def _check_reg_targets(y_true, y_pred, multioutput, dtype="numeric", xp=None): return y_type, y_true, y_pred, multioutput +def _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=None +): + """Ensures that y_true, y_pred, and sample_weight correspond to the same + regression task. + + Extends `_check_reg_targets` by automatically selecting a suitable floating-point + data type for inputs using `_find_matching_floating_dtype`. + + Use this private method only when converting inputs to array API-compatibles. + + Parameters + ---------- + y_true : array-like of shape (n_samples,) or (n_samples, n_outputs) + Ground truth (correct) target values. + + y_pred : array-like of shape (n_samples,) or (n_samples, n_outputs) + Estimated target values. + + sample_weight : array-like of shape (n_samples,) + + multioutput : array-like or string in ['raw_values', 'uniform_average', \ + 'variance_weighted'] or None + None is accepted due to backward compatibility of r2_score(). + + xp : module, default=None + Precomputed array namespace module. When passed, typically from a caller + that has already performed inspection of its own inputs, skips array + namespace inspection. + + Returns + ------- + type_true : one of {'continuous', 'continuous-multioutput'} + The type of the true target data, as output by + 'utils.multiclass.type_of_target'. + + y_true : array-like of shape (n_samples, n_outputs) + Ground truth (correct) target values. + + y_pred : array-like of shape (n_samples, n_outputs) + Estimated target values. + + sample_weight : array-like of shape (n_samples,), default=None + Sample weights. + + multioutput : array-like of shape (n_outputs) or string in ['raw_values', \ + 'uniform_average', 'variance_weighted'] or None + Custom output weights if ``multioutput`` is array-like or + just the corresponding argument if ``multioutput`` is a + correct keyword. + """ + dtype_name = _find_matching_floating_dtype(y_true, y_pred, sample_weight, xp=xp) + + y_type, y_true, y_pred, multioutput = _check_reg_targets( + y_true, y_pred, multioutput, dtype=dtype_name, xp=xp + ) + + # _check_reg_targets does not accept sample_weight as input. + # Convert sample_weight's data type separately to match dtype_name. + if sample_weight is not None: + sample_weight = xp.asarray(sample_weight, dtype=dtype_name) + + return y_type, y_true, y_pred, sample_weight, multioutput + + @validate_params( { "y_true": ["array-like"], @@ -201,14 +271,14 @@ def mean_absolute_error( >>> mean_absolute_error(y_true, y_pred, multioutput=[0.3, 0.7]) 0.85... """ - input_arrays = [y_true, y_pred, sample_weight, multioutput] - xp, _ = get_namespace(*input_arrays) - - dtype = _find_matching_floating_dtype(y_true, y_pred, sample_weight, xp=xp) + xp, _ = get_namespace(y_true, y_pred, sample_weight, multioutput) - _, y_true, y_pred, multioutput = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + _, y_true, y_pred, sample_weight, multioutput = ( + _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp + ) ) + check_consistent_length(y_true, y_pred, sample_weight) output_errors = _average( @@ -398,19 +468,16 @@ def mean_absolute_percentage_error( >>> mean_absolute_percentage_error(y_true, y_pred) 112589990684262.48 """ - input_arrays = [y_true, y_pred, sample_weight, multioutput] - xp, _ = get_namespace(*input_arrays) - dtype = _find_matching_floating_dtype(y_true, y_pred, sample_weight, xp=xp) - - y_type, y_true, y_pred, multioutput = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + xp, _ = get_namespace(y_true, y_pred, sample_weight, multioutput) + _, y_true, y_pred, sample_weight, multioutput = ( + _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp + ) ) check_consistent_length(y_true, y_pred, sample_weight) - epsilon = xp.asarray(xp.finfo(xp.float64).eps, dtype=dtype) - y_true_abs = xp.asarray(xp.abs(y_true), dtype=dtype) - mape = xp.asarray(xp.abs(y_pred - y_true), dtype=dtype) / xp.maximum( - y_true_abs, epsilon - ) + epsilon = xp.asarray(xp.finfo(xp.float64).eps, dtype=y_true.dtype) + y_true_abs = xp.abs(y_true) + mape = xp.abs(y_pred - y_true) / xp.maximum(y_true_abs, epsilon) output_errors = _average(mape, weights=sample_weight, axis=0) if isinstance(multioutput, str): if multioutput == "raw_values": @@ -494,10 +561,10 @@ def mean_squared_error( 0.825... """ xp, _ = get_namespace(y_true, y_pred, sample_weight, multioutput) - dtype = _find_matching_floating_dtype(y_true, y_pred, xp=xp) - - _, y_true, y_pred, multioutput = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + _, y_true, y_pred, sample_weight, multioutput = ( + _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp + ) ) check_consistent_length(y_true, y_pred, sample_weight) output_errors = _average((y_true - y_pred) ** 2, axis=0, weights=sample_weight) @@ -670,10 +737,9 @@ def mean_squared_log_error( 0.060... """ xp, _ = get_namespace(y_true, y_pred) - dtype = _find_matching_floating_dtype(y_true, y_pred, xp=xp) - _, y_true, y_pred, _ = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + _, y_true, y_pred, _, _ = _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp ) if xp.any(y_true <= -1) or xp.any(y_pred <= -1): @@ -747,10 +813,9 @@ def root_mean_squared_log_error( 0.199... """ xp, _ = get_namespace(y_true, y_pred) - dtype = _find_matching_floating_dtype(y_true, y_pred, xp=xp) - _, y_true, y_pred, multioutput = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + _, y_true, y_pred, _, _ = _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp ) if xp.any(y_true <= -1) or xp.any(y_pred <= -1): @@ -1188,11 +1253,12 @@ def r2_score( y_true, y_pred, sample_weight, multioutput ) - dtype = _find_matching_floating_dtype(y_true, y_pred, sample_weight, xp=xp) - - _, y_true, y_pred, multioutput = _check_reg_targets( - y_true, y_pred, multioutput, dtype=dtype, xp=xp + _, y_true, y_pred, sample_weight, multioutput = ( + _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput, xp=xp + ) ) + check_consistent_length(y_true, y_pred, sample_weight) if _num_samples(y_pred) < 2: @@ -1201,7 +1267,7 @@ def r2_score( return float("nan") if sample_weight is not None: - sample_weight = column_or_1d(sample_weight, dtype=dtype) + sample_weight = column_or_1d(sample_weight) weight = sample_weight[:, None] else: weight = 1.0 @@ -1356,8 +1422,8 @@ def mean_tweedie_deviance(y_true, y_pred, *, sample_weight=None, power=0): 1.4260... """ xp, _ = get_namespace(y_true, y_pred) - y_type, y_true, y_pred, _ = _check_reg_targets( - y_true, y_pred, None, dtype=[xp.float64, xp.float32], xp=xp + y_type, y_true, y_pred, sample_weight, _ = _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput=None, xp=xp ) if y_type == "continuous-multioutput": raise ValueError("Multioutput not supported in mean_tweedie_deviance") @@ -1570,8 +1636,8 @@ def d2_tweedie_score(y_true, y_pred, *, sample_weight=None, power=0): """ xp, _ = get_namespace(y_true, y_pred) - y_type, y_true, y_pred, _ = _check_reg_targets( - y_true, y_pred, None, dtype=[xp.float64, xp.float32], xp=xp + y_type, y_true, y_pred, sample_weight, _ = _check_reg_targets_with_floating_dtype( + y_true, y_pred, sample_weight, multioutput=None, xp=xp ) if y_type == "continuous-multioutput": raise ValueError("Multioutput not supported in d2_tweedie_score") diff --git a/sklearn/metrics/_scorer.py b/sklearn/metrics/_scorer.py index bc8c3a09a320c..fb173cd096a43 100644 --- a/sklearn/metrics/_scorer.py +++ b/sklearn/metrics/_scorer.py @@ -640,7 +640,7 @@ def make_scorer( The parameter `response_method` allows to specify which method of the estimator should be used to feed the scoring/loss function. - Read more in the :ref:`User Guide `. + Read more in the :ref:`User Guide `. Parameters ---------- @@ -933,7 +933,7 @@ def check_scoring(estimator=None, scoring=None, *, allow_none=False, raise_exc=T Scorer to use. If `scoring` represents a single score, one can use: - a single string (see :ref:`scoring_parameter`); - - a callable (see :ref:`scoring`) that returns a single value. + - a callable (see :ref:`scoring_callable`) that returns a single value. If `scoring` represents multiple scores, one can use: diff --git a/sklearn/metrics/tests/test_classification.py b/sklearn/metrics/tests/test_classification.py index d0e9f3d9a08b0..0e69719da1445 100644 --- a/sklearn/metrics/tests/test_classification.py +++ b/sklearn/metrics/tests/test_classification.py @@ -795,26 +795,8 @@ def test_cohen_kappa(): ) -@pytest.mark.parametrize("zero_division", ["warn", 0, 1, np.nan]) -@pytest.mark.parametrize("y_true, y_pred", [([0], [1]), ([0, 0], [0, 1])]) -def test_matthews_corrcoef_zero_division(zero_division, y_true, y_pred): - """Check the behaviour of `zero_division` in `matthews_corrcoef`.""" - expected_result = 0.0 if zero_division == "warn" else zero_division - - if zero_division == "warn": - with pytest.warns(UndefinedMetricWarning): - result = matthews_corrcoef(y_true, y_pred, zero_division=zero_division) - else: - result = matthews_corrcoef(y_true, y_pred, zero_division=zero_division) - - if np.isnan(expected_result): - assert np.isnan(result) - else: - assert result == expected_result - - @pytest.mark.parametrize("zero_division", [0, 1, np.nan]) -@pytest.mark.parametrize("y_true, y_pred", [([0], [0]), ([], [])]) +@pytest.mark.parametrize("y_true, y_pred", [([0], [0])]) @pytest.mark.parametrize( "metric", [ @@ -822,19 +804,12 @@ def test_matthews_corrcoef_zero_division(zero_division, y_true, y_pred): partial(fbeta_score, beta=1), precision_score, recall_score, - accuracy_score, - partial(cohen_kappa_score, labels=[0, 1]), ], ) def test_zero_division_nan_no_warning(metric, y_true, y_pred, zero_division): """Check the behaviour of `zero_division` when setting to 0, 1 or np.nan. No warnings should be raised. """ - if metric is accuracy_score and len(y_true): - pytest.skip( - reason="zero_division is only used with empty y_true/y_pred for accuracy" - ) - with warnings.catch_warnings(): warnings.simplefilter("error") result = metric(y_true, y_pred, zero_division=zero_division) @@ -845,7 +820,7 @@ def test_zero_division_nan_no_warning(metric, y_true, y_pred, zero_division): assert result == zero_division -@pytest.mark.parametrize("y_true, y_pred", [([0], [0]), ([], [])]) +@pytest.mark.parametrize("y_true, y_pred", [([0], [0])]) @pytest.mark.parametrize( "metric", [ @@ -853,19 +828,12 @@ def test_zero_division_nan_no_warning(metric, y_true, y_pred, zero_division): partial(fbeta_score, beta=1), precision_score, recall_score, - accuracy_score, - cohen_kappa_score, ], ) def test_zero_division_nan_warning(metric, y_true, y_pred): """Check the behaviour of `zero_division` when setting to "warn". A `UndefinedMetricWarning` should be raised. """ - if metric is accuracy_score and len(y_true): - pytest.skip( - reason="zero_division is only used with empty y_true/y_pred for accuracy" - ) - with pytest.warns(UndefinedMetricWarning): result = metric(y_true, y_pred, zero_division="warn") assert result == 0.0 @@ -937,19 +905,15 @@ def test_matthews_corrcoef(): # For the zero vector case, the corrcoef cannot be calculated and should # output 0 - assert_almost_equal( - matthews_corrcoef([0, 0, 0, 0], [0, 0, 0, 0], zero_division=0), 0.0 - ) + assert_almost_equal(matthews_corrcoef([0, 0, 0, 0], [0, 0, 0, 0]), 0.0) # And also for any other vector with 0 variance - assert_almost_equal( - matthews_corrcoef(y_true, ["a"] * len(y_true), zero_division=0), 0.0 - ) + assert_almost_equal(matthews_corrcoef(y_true, ["a"] * len(y_true)), 0.0) # These two vectors have 0 correlation and hence mcc should be 0 y_1 = [1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1] y_2 = [1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1] - assert_almost_equal(matthews_corrcoef(y_1, y_2, zero_division=0), 0.0) + assert_almost_equal(matthews_corrcoef(y_1, y_2), 0.0) # Check that sample weight is able to selectively exclude mask = [1] * 10 + [0] * 10 @@ -982,17 +946,17 @@ def test_matthews_corrcoef_multiclass(): # Zero variance will result in an mcc of zero y_true = [0, 1, 2] y_pred = [3, 3, 3] - assert_almost_equal(matthews_corrcoef(y_true, y_pred, zero_division=0), 0.0) + assert_almost_equal(matthews_corrcoef(y_true, y_pred), 0.0) # Also for ground truth with zero variance y_true = [3, 3, 3] y_pred = [0, 1, 2] - assert_almost_equal(matthews_corrcoef(y_true, y_pred, zero_division=0), 0.0) + assert_almost_equal(matthews_corrcoef(y_true, y_pred), 0.0) # These two vectors have 0 correlation and hence mcc should be 0 y_1 = [0, 1, 2, 0, 1, 2, 0, 1, 2] y_2 = [1, 1, 1, 2, 2, 2, 0, 0, 0] - assert_almost_equal(matthews_corrcoef(y_1, y_2, zero_division=0), 0.0) + assert_almost_equal(matthews_corrcoef(y_1, y_2), 0.0) # We can test that binary assumptions hold using the multiclass computation # by masking the weight of samples not in the first two classes @@ -1011,10 +975,7 @@ def test_matthews_corrcoef_multiclass(): y_pred = [0, 0, 1, 2] sample_weight = [1, 1, 0, 0] assert_almost_equal( - matthews_corrcoef( - y_true, y_pred, sample_weight=sample_weight, zero_division=0.0 - ), - 0.0, + matthews_corrcoef(y_true, y_pred, sample_weight=sample_weight), 0.0 ) diff --git a/sklearn/metrics/tests/test_common.py b/sklearn/metrics/tests/test_common.py index e6abc8c433013..feaefb4204973 100644 --- a/sklearn/metrics/tests/test_common.py +++ b/sklearn/metrics/tests/test_common.py @@ -583,8 +583,8 @@ def _require_positive_targets(y1, y2): def _require_log1p_targets(y1, y2): """Make targets strictly larger than -1""" offset = abs(min(y1.min(), y2.min())) - 0.99 - y1 = y1.astype(float) - y2 = y2.astype(float) + y1 = y1.astype(np.float64) + y2 = y2.astype(np.float64) y1 += offset y2 += offset return y1, y2 @@ -1817,6 +1817,40 @@ def check_array_api_metric( if isinstance(multioutput, np.ndarray): metric_kwargs["multioutput"] = xp.asarray(multioutput, device=device) + # When array API dispatch is disabled, and np.asarray works (for example PyTorch + # with CPU device), calling the metric function with such numpy compatible inputs + # should work (albeit by implicitly converting to numpy arrays instead of + # dispatching to the array library). + try: + np.asarray(a_xp) + np.asarray(b_xp) + numpy_as_array_works = True + except TypeError: + # PyTorch with CUDA device and CuPy raise TypeError consistently. + # Exception type may need to be updated in the future for other + # libraries. + numpy_as_array_works = False + + if numpy_as_array_works: + metric_xp = metric(a_xp, b_xp, **metric_kwargs) + assert_allclose( + metric_xp, + metric_np, + atol=_atol_for_type(dtype_name), + ) + metric_xp_mixed_1 = metric(a_np, b_xp, **metric_kwargs) + assert_allclose( + metric_xp_mixed_1, + metric_np, + atol=_atol_for_type(dtype_name), + ) + metric_xp_mixed_2 = metric(a_xp, b_np, **metric_kwargs) + assert_allclose( + metric_xp_mixed_2, + metric_np, + atol=_atol_for_type(dtype_name), + ) + with config_context(array_api_dispatch=True): metric_xp = metric(a_xp, b_xp, **metric_kwargs) @@ -1862,27 +1896,37 @@ def check_array_api_multiclass_classification_metric( y_true_np = np.array([0, 1, 2, 3]) y_pred_np = np.array([0, 1, 0, 2]) - check_array_api_metric( - metric, - array_namespace, - device, - dtype_name, - a_np=y_true_np, - b_np=y_pred_np, - sample_weight=None, + additional_params = { + "average": ("micro", "macro", "weighted"), + } + metric_kwargs_combinations = _get_metric_kwargs_for_array_api_testing( + metric=metric, + params=additional_params, ) + for metric_kwargs in metric_kwargs_combinations: + check_array_api_metric( + metric, + array_namespace, + device, + dtype_name, + a_np=y_true_np, + b_np=y_pred_np, + sample_weight=None, + **metric_kwargs, + ) - sample_weight = np.array([0.0, 0.1, 2.0, 1.0], dtype=dtype_name) + sample_weight = np.array([0.0, 0.1, 2.0, 1.0], dtype=dtype_name) - check_array_api_metric( - metric, - array_namespace, - device, - dtype_name, - a_np=y_true_np, - b_np=y_pred_np, - sample_weight=sample_weight, - ) + check_array_api_metric( + metric, + array_namespace, + device, + dtype_name, + a_np=y_true_np, + b_np=y_pred_np, + sample_weight=sample_weight, + **metric_kwargs, + ) def check_array_api_multilabel_classification_metric( @@ -1891,27 +1935,37 @@ def check_array_api_multilabel_classification_metric( y_true_np = np.array([[1, 1], [0, 1], [0, 0]], dtype=dtype_name) y_pred_np = np.array([[1, 1], [1, 1], [1, 1]], dtype=dtype_name) - check_array_api_metric( - metric, - array_namespace, - device, - dtype_name, - a_np=y_true_np, - b_np=y_pred_np, - sample_weight=None, + additional_params = { + "average": ("micro", "macro", "weighted"), + } + metric_kwargs_combinations = _get_metric_kwargs_for_array_api_testing( + metric=metric, + params=additional_params, ) + for metric_kwargs in metric_kwargs_combinations: + check_array_api_metric( + metric, + array_namespace, + device, + dtype_name, + a_np=y_true_np, + b_np=y_pred_np, + sample_weight=None, + **metric_kwargs, + ) - sample_weight = np.array([0.0, 0.1, 2.0], dtype=dtype_name) + sample_weight = np.array([0.0, 0.1, 2.0], dtype=dtype_name) - check_array_api_metric( - metric, - array_namespace, - device, - dtype_name, - a_np=y_true_np, - b_np=y_pred_np, - sample_weight=sample_weight, - ) + check_array_api_metric( + metric, + array_namespace, + device, + dtype_name, + a_np=y_true_np, + b_np=y_pred_np, + sample_weight=sample_weight, + **metric_kwargs, + ) def check_array_api_regression_metric(metric, array_namespace, device, dtype_name): @@ -2041,6 +2095,16 @@ def check_array_api_metric_pairwise(metric, array_namespace, device, dtype_name) check_array_api_multiclass_classification_metric, check_array_api_multilabel_classification_metric, ], + f1_score: [ + check_array_api_binary_classification_metric, + check_array_api_multiclass_classification_metric, + check_array_api_multilabel_classification_metric, + ], + multilabel_confusion_matrix: [ + check_array_api_binary_classification_metric, + check_array_api_multiclass_classification_metric, + check_array_api_multilabel_classification_metric, + ], zero_one_loss: [ check_array_api_binary_classification_metric, check_array_api_multiclass_classification_metric, @@ -2126,3 +2190,24 @@ def test_metrics_dataframe_series(metric_name, df_lib_name): pytest.skip(f"{metric_name} can not deal with 1d inputs") assert_allclose(metric(y_pred, y_true), expected_metric) + + +def _get_metric_kwargs_for_array_api_testing(metric, params): + """Helper function to enable specifying a variety of additional params and + their corresponding values, so that they can be passed to a metric function + when testing for array api compliance.""" + metric_kwargs_combinations = [{}] + for param, values in params.items(): + if param not in signature(metric).parameters: + continue + + new_combinations = [] + for kwargs in metric_kwargs_combinations: + for value in values: + new_kwargs = kwargs.copy() + new_kwargs[param] = value + new_combinations.append(new_kwargs) + + metric_kwargs_combinations = new_combinations + + return metric_kwargs_combinations diff --git a/sklearn/model_selection/_classification_threshold.py b/sklearn/model_selection/_classification_threshold.py index 8ac7a67a03433..ff1a82d584606 100644 --- a/sklearn/model_selection/_classification_threshold.py +++ b/sklearn/model_selection/_classification_threshold.py @@ -22,7 +22,7 @@ _CurveScorer, _threshold_scores_to_class_labels, ) -from ..utils import _safe_indexing +from ..utils import _safe_indexing, get_tags from ..utils._param_validation import HasMethods, Interval, RealNotInt, StrOptions from ..utils._response import _get_response_values_binary from ..utils.metadata_routing import ( @@ -206,14 +206,7 @@ def decision_function(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.classifier_tags.multi_class = False - tags._xfail_checks = { - "check_classifiers_train": "Threshold at probability 0.5 does not hold", - "check_sample_weight_equivalence": ( - "Due to the cross-validation and sample ordering, removing a sample" - " is not strictly equal to putting is weight to zero. Specific unit" - " tests are added for TunedThresholdClassifierCV specifically." - ), - } + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags diff --git a/sklearn/model_selection/_plot.py b/sklearn/model_selection/_plot.py index b16e0f4c1019a..8cae3dc97d2c5 100644 --- a/sklearn/model_selection/_plot.py +++ b/sklearn/model_selection/_plot.py @@ -369,7 +369,7 @@ def from_estimator( scoring : str or callable, default=None A string (see :ref:`scoring_parameter`) or a scorer callable object / function with signature - `scorer(estimator, X, y)` (see :ref:`scoring`). + `scorer(estimator, X, y)` (see :ref:`scoring_callable`). exploit_incremental_learning : bool, default=False If the estimator supports incremental learning, this will be @@ -752,7 +752,7 @@ def from_estimator( scoring : str or callable, default=None A string (see :ref:`scoring_parameter`) or a scorer callable object / function with signature - `scorer(estimator, X, y)` (see :ref:`scoring`). + `scorer(estimator, X, y)` (see :ref:`scoring_callable`). n_jobs : int, default=None Number of jobs to run in parallel. Training the estimator and diff --git a/sklearn/model_selection/_search.py b/sklearn/model_selection/_search.py index a8431b74259b4..46b9a4d4b912c 100644 --- a/sklearn/model_selection/_search.py +++ b/sklearn/model_selection/_search.py @@ -489,10 +489,7 @@ def __sklearn_tags__(self): tags.regressor_tags = deepcopy(sub_estimator_tags.regressor_tags) # allows cross-validation to see 'precomputed' metrics tags.input_tags.pairwise = sub_estimator_tags.input_tags.pairwise - tags._xfail_checks = { - "check_supervised_y_2d": "DataConversionWarning not caught", - "check_requires_y_none": "Doesn't fail gracefully", - } + tags.input_tags.sparse = sub_estimator_tags.input_tags.sparse tags.array_api_support = sub_estimator_tags.array_api_support return tags @@ -1251,14 +1248,14 @@ class GridSearchCV(BaseSearchCV): If `scoring` represents a single score, one can use: - a single string (see :ref:`scoring_parameter`); - - a callable (see :ref:`scoring`) that returns a single value. + - a callable (see :ref:`scoring_callable`) that returns a single value. If `scoring` represents multiple scores, one can use: - a list or tuple of unique strings; - a callable returning a dictionary where the keys are the metric names and the values are the metric scores; - - a dictionary with metric names as keys and callables a values. + - a dictionary with metric names as keys and callables as values. See :ref:`multimetric_grid_search` for an example. @@ -1627,14 +1624,14 @@ class RandomizedSearchCV(BaseSearchCV): If `scoring` represents a single score, one can use: - a single string (see :ref:`scoring_parameter`); - - a callable (see :ref:`scoring`) that returns a single value. + - a callable (see :ref:`scoring_callable`) that returns a single value. If `scoring` represents multiple scores, one can use: - a list or tuple of unique strings; - a callable returning a dictionary where the keys are the metric names and the values are the metric scores; - - a dictionary with metric names as keys and callables a values. + - a dictionary with metric names as keys and callables as values. See :ref:`multimetric_grid_search` for an example. @@ -1659,7 +1656,7 @@ class RandomizedSearchCV(BaseSearchCV): Where there are considerations other than maximum score in choosing a best estimator, ``refit`` can be set to a function which - returns the selected ``best_index_`` given the ``cv_results``. In that + returns the selected ``best_index_`` given the ``cv_results_``. In that case, the ``best_estimator_`` and ``best_params_`` will be set according to the returned ``best_index_`` while the ``best_score_`` attribute will not be available. diff --git a/sklearn/model_selection/_search_successive_halving.py b/sklearn/model_selection/_search_successive_halving.py index 67a1fde6cef0a..55073df14bfc1 100644 --- a/sklearn/model_selection/_search_successive_halving.py +++ b/sklearn/model_selection/_search_successive_halving.py @@ -370,21 +370,6 @@ def _run_search(self, evaluate_candidates): def _generate_candidate_params(self): pass - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks.update( - { - "check_fit2d_1sample": ( - "Fail during parameter check since min/max resources requires" - " more samples" - ), - "check_estimators_nan_inf": "FIXME", - "check_classifiers_one_label_sample_weights": "FIXME", - "check_fit2d_1feature": "FIXME", - } - ) - return tags - class HalvingGridSearchCV(BaseSuccessiveHalving): """Search over specified parameter values with successive halving. @@ -495,7 +480,7 @@ class HalvingGridSearchCV(BaseSuccessiveHalving): scoring : str, callable, or None, default=None A single string (see :ref:`scoring_parameter`) or a callable - (see :ref:`scoring`) to evaluate the predictions on the test set. + (see :ref:`scoring_callable`) to evaluate the predictions on the test set. If None, the estimator's score method is used. refit : bool, default=True @@ -836,7 +821,7 @@ class HalvingRandomSearchCV(BaseSuccessiveHalving): scoring : str, callable, or None, default=None A single string (see :ref:`scoring_parameter`) or a callable - (see :ref:`scoring`) to evaluate the predictions on the test set. + (see :ref:`scoring_callable`) to evaluate the predictions on the test set. If None, the estimator's score method is used. refit : bool, default=True diff --git a/sklearn/model_selection/_validation.py b/sklearn/model_selection/_validation.py index 63252e818c3a6..d5984d2454a4c 100644 --- a/sklearn/model_selection/_validation.py +++ b/sklearn/model_selection/_validation.py @@ -169,12 +169,14 @@ def cross_validate( scoring : str, callable, list, tuple, or dict, default=None Strategy to evaluate the performance of the cross-validated model on - the test set. + the test set. If `None`, the + :ref:`default evaluation criterion ` of the estimator + is used. If `scoring` represents a single score, one can use: - a single string (see :ref:`scoring_parameter`); - - a callable (see :ref:`scoring`) that returns a single value. + - a callable (see :ref:`scoring_callable`) that returns a single value. If `scoring` represents multiple scores, one can use: @@ -341,7 +343,7 @@ def cross_validate( _check_groups_routing_disabled(groups) X, y = indexable(X, y) - + params = {} if params is None else params cv = check_cv(cv, y, classifier=is_classifier(estimator)) scorers = check_scoring( @@ -1170,6 +1172,7 @@ def cross_val_predict( """ _check_groups_routing_disabled(groups) X, y = indexable(X, y) + params = {} if params is None else params if _routing_enabled(): # For estimators, a MetadataRouter is created in get_metadata_routing @@ -1561,7 +1564,7 @@ def permutation_test_score( scoring : str or callable, default=None A single str (see :ref:`scoring_parameter`) or a callable - (see :ref:`scoring`) to evaluate the predictions on the test set. + (see :ref:`scoring_callable`) to evaluate the predictions on the test set. If `None` the estimator's score method is used. diff --git a/sklearn/model_selection/tests/test_validation.py b/sklearn/model_selection/tests/test_validation.py index 2d579772b1fbe..73156c2a25337 100644 --- a/sklearn/model_selection/tests/test_validation.py +++ b/sklearn/model_selection/tests/test_validation.py @@ -2539,6 +2539,27 @@ def test_groups_with_routing_validation(func, extra_args): ) +@pytest.mark.parametrize( + "func, extra_args", + [ + (cross_validate, {}), + (cross_val_score, {}), + (cross_val_predict, {}), + (learning_curve, {}), + (permutation_test_score, {}), + (validation_curve, {"param_name": "alpha", "param_range": np.array([1])}), + ], +) +@config_context(enable_metadata_routing=True) +def test_cross_validate_params_none(func, extra_args): + """Test that no errors are raised when passing `params=None`, which is the + default value. + Non-regression test for: https://github.com/scikit-learn/scikit-learn/issues/30447 + """ + X, y = make_classification(n_samples=100, n_classes=2, random_state=0) + func(estimator=ConsumingClassifier(), X=X, y=y, **extra_args) + + @pytest.mark.parametrize( "func, extra_args", [ diff --git a/sklearn/multiclass.py b/sklearn/multiclass.py index dca055ecbfb4a..1ddb36ca4fa8f 100644 --- a/sklearn/multiclass.py +++ b/sklearn/multiclass.py @@ -601,6 +601,7 @@ def __sklearn_tags__(self): """Indicate if wrapped estimator is using a precomputed Gram matrix""" tags = super().__sklearn_tags__() tags.input_tags.pairwise = get_tags(self.estimator).input_tags.pairwise + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags def get_metadata_routing(self): @@ -1004,6 +1005,7 @@ def __sklearn_tags__(self): """Indicate if wrapped estimator is using a precomputed Gram matrix""" tags = super().__sklearn_tags__() tags.input_tags.pairwise = get_tags(self.estimator).input_tags.pairwise + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags def get_metadata_routing(self): @@ -1276,3 +1278,8 @@ def get_metadata_routing(self): method_mapping=MethodMapping().add(caller="fit", callee="fit"), ) return router + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse + return tags diff --git a/sklearn/multioutput.py b/sklearn/multioutput.py index ebcd73e95d881..38b6eb4a7e0ec 100644 --- a/sklearn/multioutput.py +++ b/sklearn/multioutput.py @@ -25,7 +25,7 @@ is_classifier, ) from .model_selection import cross_val_predict -from .utils import Bunch, check_random_state +from .utils import Bunch, check_random_state, get_tags from .utils._param_validation import HasMethods, StrOptions from .utils._response import _get_response_values from .utils._user_interface import _print_elapsed_time @@ -311,6 +311,7 @@ def predict(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse tags.target_tags.single_output = False tags.target_tags.multi_output = True return tags @@ -829,6 +830,11 @@ def predict(self, X): """ return self._get_predictions(X, output_method="predict") + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = get_tags(self.base_estimator).input_tags.sparse + return tags + class ClassifierChain(MetaEstimatorMixin, ClassifierMixin, _BaseChain): """A multi-label model that arranges binary classifiers into a chain. diff --git a/sklearn/naive_bayes.py b/sklearn/naive_bayes.py index fa99448f9d347..0bb2daab25d0b 100644 --- a/sklearn/naive_bayes.py +++ b/sklearn/naive_bayes.py @@ -771,6 +771,7 @@ def _init_counters(self, n_classes, n_features): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.classifier_tags.poor_score = True return tags @@ -1432,13 +1433,8 @@ def partial_fit(self, X, y, classes=None, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = False tags.input_tags.positive_only = True - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } return tags def _check_X(self, X): diff --git a/sklearn/neighbors/_base.py b/sklearn/neighbors/_base.py index cdcd8929da6ca..72d27f444000e 100644 --- a/sklearn/neighbors/_base.py +++ b/sklearn/neighbors/_base.py @@ -707,8 +707,11 @@ def _fit(self, X, y=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True # For cross-validation routines to split data correctly tags.input_tags.pairwise = self.metric == "precomputed" + # when input is precomputed metric values, all those values need to be positive + tags.input_tags.positive_only = tags.input_tags.pairwise tags.input_tags.allow_nan = self.metric == "nan_euclidean" return tags diff --git a/sklearn/neighbors/_classification.py b/sklearn/neighbors/_classification.py index 5f44a0ecca603..cc20af7432914 100644 --- a/sklearn/neighbors/_classification.py +++ b/sklearn/neighbors/_classification.py @@ -449,13 +449,6 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.classifier_tags.multi_label = True tags.input_tags.pairwise = self.metric == "precomputed" - if tags.input_tags.pairwise: - tags._xfail_checks.update( - { - "check_n_features_in_after_fitting": "FIXME", - "check_dataframe_column_names_consistency": "FIXME", - } - ) return tags diff --git a/sklearn/neighbors/_graph.py b/sklearn/neighbors/_graph.py index 9a774c1dee514..ad4afc0a81a66 100644 --- a/sklearn/neighbors/_graph.py +++ b/sklearn/neighbors/_graph.py @@ -480,13 +480,6 @@ def fit_transform(self, X, y=None): """ return self.fit(X).transform(X) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_methods_sample_order_invariance": "check is not applicable." - } - return tags - class RadiusNeighborsTransformer( ClassNamePrefixFeaturesOutMixin, @@ -709,10 +702,3 @@ def fit_transform(self, X, y=None): The matrix is of CSR format. """ return self.fit(X).transform(X) - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_methods_sample_order_invariance": "check is not applicable." - } - return tags diff --git a/sklearn/neighbors/_kde.py b/sklearn/neighbors/_kde.py index b094cdd5d2ee8..7661308db2e01 100644 --- a/sklearn/neighbors/_kde.py +++ b/sklearn/neighbors/_kde.py @@ -357,10 +357,3 @@ def sample(self, n_samples=1, random_state=None): / np.sqrt(s_sq) ) return data[i] + X * correction[:, np.newaxis] - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_sample_weight_equivalence": "sample_weight must have positive values" - } - return tags diff --git a/sklearn/neighbors/_nearest_centroid.py b/sklearn/neighbors/_nearest_centroid.py index b30dc309b2dd7..a780c27587792 100644 --- a/sklearn/neighbors/_nearest_centroid.py +++ b/sklearn/neighbors/_nearest_centroid.py @@ -355,4 +355,5 @@ def _check_euclidean_metric(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = self.metric == "nan_euclidean" + tags.input_tags.sparse = True return tags diff --git a/sklearn/neighbors/_regression.py b/sklearn/neighbors/_regression.py index f324d3fb7e2f2..0ee0a340b8153 100644 --- a/sklearn/neighbors/_regression.py +++ b/sklearn/neighbors/_regression.py @@ -195,13 +195,6 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() # For cross-validation routines to split data correctly tags.input_tags.pairwise = self.metric == "precomputed" - if tags.input_tags.pairwise: - tags._xfail_checks.update( - { - "check_n_features_in_after_fitting": "FIXME", - "check_dataframe_column_names_consistency": "FIXME", - } - ) return tags @_fit_context( diff --git a/sklearn/neural_network/_multilayer_perceptron.py b/sklearn/neural_network/_multilayer_perceptron.py index 196203ce46763..47805857b5154 100644 --- a/sklearn/neural_network/_multilayer_perceptron.py +++ b/sklearn/neural_network/_multilayer_perceptron.py @@ -771,6 +771,11 @@ def _score_with_function(self, X, y, score_function): return score_function(y, y_pred) + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class MLPClassifier(ClassifierMixin, BaseMultilayerPerceptron): """Multi-layer Perceptron classifier. diff --git a/sklearn/neural_network/_rbm.py b/sklearn/neural_network/_rbm.py index 49848e9f982cc..1e1d3c2e11b7c 100644 --- a/sklearn/neural_network/_rbm.py +++ b/sklearn/neural_network/_rbm.py @@ -440,13 +440,6 @@ def fit(self, X, y=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_methods_subset_invariance": ( - "fails for the decision_function method" - ), - "check_methods_sample_order_invariance": ( - "fails for the score_samples method" - ), - } + tags.input_tags.sparse = True tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags diff --git a/sklearn/pipeline.py b/sklearn/pipeline.py index 54fc572e12672..fc5be7e3c51f7 100644 --- a/sklearn/pipeline.py +++ b/sklearn/pipeline.py @@ -31,6 +31,7 @@ MethodMapping, _raise_for_params, _routing_enabled, + get_routing_for_object, process_routing, ) from .utils.metaestimators import _BaseComposition, available_if @@ -80,6 +81,46 @@ def check(self): return check +def _cached_transform( + sub_pipeline, *, cache, param_name, param_value, transform_params +): + """Transform a parameter value using a sub-pipeline and cache the result. + + Parameters + ---------- + sub_pipeline : Pipeline + The sub-pipeline to be used for transformation. + cache : dict + The cache dictionary to store the transformed values. + param_name : str + The name of the parameter to be transformed. + param_value : object + The value of the parameter to be transformed. + transform_params : dict + The metadata to be used for transformation. This passed to the + `transform` method of the sub-pipeline. + + Returns + ------- + transformed_value : object + The transformed value of the parameter. + """ + if param_name not in cache: + # If the parameter is a tuple, transform each element of the + # tuple. This is needed to support the pattern present in + # `lightgbm` and `xgboost` where users can pass multiple + # validation sets. + if isinstance(param_value, tuple): + cache[param_name] = tuple( + sub_pipeline.transform(element, **transform_params) + for element in param_value + ) + else: + cache[param_name] = sub_pipeline.transform(param_value, **transform_params) + + return cache[param_name] + + class Pipeline(_BaseComposition): """ A sequence of data transformers with an optional final predictor. @@ -88,7 +129,7 @@ class Pipeline(_BaseComposition): preprocess the data and, if desired, conclude the sequence with a final :term:`predictor` for predictive modeling. - Intermediate steps of the pipeline must be 'transforms', that is, they + Intermediate steps of the pipeline must be transformers, that is, they must implement `fit` and `transform` methods. The final :term:`estimator` only needs to implement `fit`. The transformers in the pipeline can be cached using ``memory`` argument. @@ -119,6 +160,20 @@ class Pipeline(_BaseComposition): must define `fit`. All non-last steps must also define `transform`. See :ref:`Combining Estimators ` for more details. + transform_input : list of str, default=None + The names of the :term:`metadata` parameters that should be transformed by the + pipeline before passing it to the step consuming it. + + This enables transforming some input arguments to ``fit`` (other than ``X``) + to be transformed by the steps of the pipeline up to the step which requires + them. Requirement is defined via :ref:`metadata routing `. + For instance, this can be used to pass a validation set through the pipeline. + + You can only set this if metadata routing is enabled, which you + can enable using ``sklearn.set_config(enable_metadata_routing=True)``. + + .. versionadded:: 1.6 + memory : str or object with the joblib.Memory interface, default=None Used to cache the fitted transformers of the pipeline. The last step will never be cached, even if it is a transformer. By default, no @@ -127,7 +182,9 @@ class Pipeline(_BaseComposition): before fitting. Therefore, the transformer instance given to the pipeline cannot be inspected directly. Use the attribute ``named_steps`` or ``steps`` to inspect estimators within the pipeline. Caching the - transformers is advantageous when fitting is time consuming. + transformers is advantageous when fitting is time consuming. See + :ref:`sphx_glr_auto_examples_neighbors_plot_caching_nearest_neighbors.py` + for an example on how to enable caching. verbose : bool, default=False If True, the time elapsed while fitting each step will be printed as it @@ -184,12 +241,14 @@ class Pipeline(_BaseComposition): # BaseEstimator interface _parameter_constraints: dict = { "steps": [list, Hidden(tuple)], + "transform_input": [list, None], "memory": [None, str, HasMethods(["cache"])], "verbose": ["boolean"], } - def __init__(self, steps, *, memory=None, verbose=False): + def __init__(self, steps, *, transform_input=None, memory=None, verbose=False): self.steps = steps + self.transform_input = transform_input self.memory = memory self.verbose = verbose @@ -348,6 +407,11 @@ def __getitem__(self, ind): # TODO(1.8): Remove this property @property def _estimator_type(self): + """Return the estimator type of the last step in the pipeline.""" + + if not self.steps: + return None + return self.steps[-1][1]._estimator_type @property @@ -407,9 +471,92 @@ def _check_method_params(self, method, props, **kwargs): fit_params_steps[step]["fit_predict"][param] = pval return fit_params_steps + def _get_metadata_for_step(self, *, step_idx, step_params, all_params): + """Get params (metadata) for step `name`. + + This transforms the metadata up to this step if required, which is + indicated by the `transform_input` parameter. + + If a param in `step_params` is included in the `transform_input` list, + it will be transformed. + + Parameters + ---------- + step_idx : int + Index of the step in the pipeline. + + step_params : dict + Parameters specific to the step. These are routed parameters, e.g. + `routed_params[name]`. If a parameter name here is included in the + `pipeline.transform_input`, then it will be transformed. Note that + these parameters are *after* routing, so the aliases are already + resolved. + + all_params : dict + All parameters passed by the user. Here this is used to call + `transform` on the slice of the pipeline itself. + + Returns + ------- + dict + Parameters to be passed to the step. The ones which should be + transformed are transformed. + """ + if ( + self.transform_input is None + or not all_params + or not step_params + or step_idx == 0 + ): + # we only need to process step_params if transform_input is set + # and metadata is given by the user. + return step_params + + sub_pipeline = self[:step_idx] + sub_metadata_routing = get_routing_for_object(sub_pipeline) + # here we get the metadata required by sub_pipeline.transform + transform_params = { + key: value + for key, value in all_params.items() + if key + in sub_metadata_routing.consumes( + method="transform", params=all_params.keys() + ) + } + transformed_params = dict() # this is to be returned + transformed_cache = dict() # used to transform each param once + # `step_params` is the output of `process_routing`, so it has a dict for each + # method (e.g. fit, transform, predict), which are the args to be passed to + # those methods. We need to transform the parameters which are in the + # `transform_input`, before returning these dicts. + for method, method_params in step_params.items(): + transformed_params[method] = Bunch() + for param_name, param_value in method_params.items(): + # An example of `(param_name, param_value)` is + # `('sample_weight', array([0.5, 0.5, ...]))` + if param_name in self.transform_input: + # This parameter now needs to be transformed by the sub_pipeline, to + # this step. We cache these computations to avoid repeating them. + transformed_params[method][param_name] = _cached_transform( + sub_pipeline, + cache=transformed_cache, + param_name=param_name, + param_value=param_value, + transform_params=transform_params, + ) + else: + transformed_params[method][param_name] = param_value + return transformed_params + # Estimator interface - def _fit(self, X, y=None, routed_params=None): + def _fit(self, X, y=None, routed_params=None, raw_params=None): + """Fit the pipeline except the last step. + + routed_params is the output of `process_routing` + raw_params is the parameters passed by the user, used when `transform_input` + is set by the user, to transform metadata using a sub-pipeline. + """ # shallow copy of steps - this should really be steps_ self.steps = list(self.steps) self._validate_steps() @@ -432,14 +579,20 @@ def _fit(self, X, y=None, routed_params=None): else: cloned_transformer = clone(transformer) # Fit or load from cache the current transformer + step_params = self._get_metadata_for_step( + step_idx=step_idx, + step_params=routed_params[name], + all_params=raw_params, + ) + X, fitted_transformer = fit_transform_one_cached( cloned_transformer, X, y, - None, + weight=None, message_clsname="Pipeline", message=self._log_message(step_idx), - params=routed_params[name], + params=step_params, ) # Replace the transformer of the step with the fitted # transformer. This is necessary when loading the transformer @@ -490,11 +643,22 @@ def fit(self, X, y=None, **params): self : object Pipeline with fitted steps. """ + if not _routing_enabled() and self.transform_input is not None: + raise ValueError( + "The `transform_input` parameter can only be set if metadata " + "routing is enabled. You can enable metadata routing using " + "`sklearn.set_config(enable_metadata_routing=True)`." + ) + routed_params = self._check_method_params(method="fit", props=params) - Xt = self._fit(X, y, routed_params) + Xt = self._fit(X, y, routed_params, raw_params=params) with _print_elapsed_time("Pipeline", self._log_message(len(self.steps) - 1)): if self._final_estimator != "passthrough": - last_step_params = routed_params[self.steps[-1][0]] + last_step_params = self._get_metadata_for_step( + step_idx=len(self) - 1, + step_params=routed_params[self.steps[-1][0]], + all_params=params, + ) self._final_estimator.fit(Xt, y, **last_step_params["fit"]) return self @@ -557,7 +721,11 @@ def fit_transform(self, X, y=None, **params): with _print_elapsed_time("Pipeline", self._log_message(len(self.steps) - 1)): if last_step == "passthrough": return Xt - last_step_params = routed_params[self.steps[-1][0]] + last_step_params = self._get_metadata_for_step( + step_idx=len(self) - 1, + step_params=routed_params[self.steps[-1][0]], + all_params=params, + ) if hasattr(last_step, "fit_transform"): return last_step.fit_transform( Xt, y, **last_step_params["fit_transform"] @@ -1049,22 +1217,24 @@ def classes_(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_dont_overwrite_parameters": ( - "Pipeline changes the `steps` parameter, which it shouldn't." - "Therefore this test is x-fail until we fix this." - ), - "check_estimators_overwrite_params": ( - "Pipeline changes the `steps` parameter, which it shouldn't." - "Therefore this test is x-fail until we fix this." - ), - } + + if not self.steps: + return tags try: if self.steps[0][1] is not None and self.steps[0][1] != "passthrough": tags.input_tags.pairwise = get_tags( self.steps[0][1] ).input_tags.pairwise + # WARNING: the sparse tag can be incorrect. + # Some Pipelines accepting sparse data are wrongly tagged sparse=False. + # For example Pipeline([PCA(), estimator]) accepts sparse data + # even if the estimator doesn't as PCA outputs a dense array. + tags.input_tags.sparse = all( + get_tags(step).input_tags.sparse + for name, step in self.steps + if step != "passthrough" + ) except (ValueError, AttributeError, TypeError): # This happens when the `steps` is not a list of (name, estimator) # tuples and `fit` is not called yet to validate the steps. @@ -1272,7 +1442,7 @@ def _name_estimators(estimators): return list(zip(names, estimators)) -def make_pipeline(*steps, memory=None, verbose=False): +def make_pipeline(*steps, memory=None, transform_input=None, verbose=False): """Construct a :class:`Pipeline` from the given estimators. This is a shorthand for the :class:`Pipeline` constructor; it does not @@ -1294,6 +1464,17 @@ def make_pipeline(*steps, memory=None, verbose=False): or ``steps`` to inspect estimators within the pipeline. Caching the transformers is advantageous when fitting is time consuming. + transform_input : list of str, default=None + This enables transforming some input arguments to ``fit`` (other than ``X``) + to be transformed by the steps of the pipeline up to the step which requires + them. Requirement is defined via :ref:`metadata routing `. + This can be used to pass a validation set through the pipeline for instance. + + You can only set this if metadata routing is enabled, which you + can enable using ``sklearn.set_config(enable_metadata_routing=True)``. + + .. versionadded:: 1.6 + verbose : bool, default=False If True, the time elapsed while fitting each step will be printed as it is completed. @@ -1317,7 +1498,12 @@ def make_pipeline(*steps, memory=None, verbose=False): Pipeline(steps=[('standardscaler', StandardScaler()), ('gaussiannb', GaussianNB())]) """ - return Pipeline(_name_estimators(steps), memory=memory, verbose=verbose) + return Pipeline( + _name_estimators(steps), + transform_input=transform_input, + memory=memory, + verbose=verbose, + ) def _transform_one(transformer, X, y, weight, params=None): @@ -1940,11 +2126,17 @@ def get_metadata_routing(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_estimators_overwrite_params": "FIXME", - "check_estimators_nan_inf": "FIXME", - "check_dont_overwrite_parameters": "FIXME", - } + try: + tags.input_tags.sparse = all( + get_tags(trans).input_tags.sparse + for name, trans in self.transformer_list + if trans not in {"passthrough", "drop"} + ) + except Exception: + # If `transformer_list` does not comply with our API (list of tuples) + # then it will fail. In this case, we assume that `sparse` is False + # but the parameter validation will raise an error during `fit`. + pass # pragma: no cover return tags diff --git a/sklearn/preprocessing/_data.py b/sklearn/preprocessing/_data.py index 74ea7431a5d72..f0d1defe61ca9 100644 --- a/sklearn/preprocessing/_data.py +++ b/sklearn/preprocessing/_data.py @@ -1130,6 +1130,7 @@ def inverse_transform(self, X, copy=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = True + tags.input_tags.sparse = not self.with_mean tags.transformer_tags.preserves_dtype = ["float64", "float32"] return tags @@ -1363,6 +1364,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.allow_nan = True + tags.input_tags.sparse = True return tags @@ -1737,6 +1739,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = not self.with_centering tags.input_tags.allow_nan = True return tags @@ -2136,6 +2139,7 @@ def transform(self, X, copy=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.requires_fit = False tags.array_api_support = True return tags @@ -2343,6 +2347,7 @@ def transform(self, X, copy=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.requires_fit = False + tags.input_tags.sparse = True return tags @@ -3009,6 +3014,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() + tags.input_tags.sparse = True tags.input_tags.allow_nan = True return tags diff --git a/sklearn/preprocessing/_discretization.py b/sklearn/preprocessing/_discretization.py index 8b5dea5c4f6c3..6a6a739c469fa 100644 --- a/sklearn/preprocessing/_discretization.py +++ b/sklearn/preprocessing/_discretization.py @@ -462,13 +462,3 @@ def get_feature_names_out(self, input_features=None): # ordinal encoding return input_features - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags diff --git a/sklearn/preprocessing/_function_transformer.py b/sklearn/preprocessing/_function_transformer.py index 02379273e302e..3fc33c59e76bd 100644 --- a/sklearn/preprocessing/_function_transformer.py +++ b/sklearn/preprocessing/_function_transformer.py @@ -394,6 +394,7 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.no_validation = not self.validate tags.requires_fit = False + tags.input_tags.sparse = not self.validate or self.accept_sparse return tags def set_output(self, *, transform=None): diff --git a/sklearn/preprocessing/_polynomial.py b/sklearn/preprocessing/_polynomial.py index 5a3239f113024..de0308cda3b06 100644 --- a/sklearn/preprocessing/_polynomial.py +++ b/sklearn/preprocessing/_polynomial.py @@ -392,7 +392,7 @@ def fit(self, X, y=None): ) raise ValueError(msg) # We also record the number of output features for - # _max_degree = 0 + # _min_degree = 0 self._n_out_full = self._num_combinations( n_features=n_features, min_degree=0, @@ -585,6 +585,11 @@ def transform(self, X): XP = Xout return XP + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class SplineTransformer(TransformerMixin, BaseEstimator): """Generate univariate B-spline bases for features. @@ -1171,13 +1176,3 @@ def transform(self, X): # We chose the last one. indices = [j for j in range(XBS.shape[1]) if (j + 1) % n_splines != 0] return XBS[:, indices] - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_estimators_pickle": ( - "Current Scipy implementation of _bsplines does not" - "support const memory views." - ), - } - return tags diff --git a/sklearn/preprocessing/tests/test_polynomial.py b/sklearn/preprocessing/tests/test_polynomial.py index b97500d43ef73..9a98ba25e9d8b 100644 --- a/sklearn/preprocessing/tests/test_polynomial.py +++ b/sklearn/preprocessing/tests/test_polynomial.py @@ -1050,8 +1050,10 @@ def test_csr_polynomial_expansion_index_overflow( `scipy.sparse.hstack`. """ data = [1.0] - row = [0] - col = [n_features - 1] + # Use int32 indices as much as we can + indices_dtype = np.int32 if n_features - 1 <= np.iinfo(np.int32).max else np.int64 + row = np.array([0], dtype=indices_dtype) + col = np.array([n_features - 1], dtype=indices_dtype) # First degree index expected_indices = [ diff --git a/sklearn/random_projection.py b/sklearn/random_projection.py index ca328f84733f8..74741585f7761 100644 --- a/sklearn/random_projection.py +++ b/sklearn/random_projection.py @@ -463,6 +463,7 @@ def inverse_transform(self, X): def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.transformer_tags.preserves_dtype = ["float64", "float32"] + tags.input_tags.sparse = True return tags diff --git a/sklearn/semi_supervised/_label_propagation.py b/sklearn/semi_supervised/_label_propagation.py index a2e25277cf450..559a17a13d6ae 100644 --- a/sklearn/semi_supervised/_label_propagation.py +++ b/sklearn/semi_supervised/_label_propagation.py @@ -336,6 +336,11 @@ def fit(self, X, y): self.transduction_ = transduction.ravel() return self + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + class LabelPropagation(BaseLabelPropagation): """Label Propagation classifier. @@ -359,7 +364,7 @@ class LabelPropagation(BaseLabelPropagation): max_iter : int, default=1000 Change maximum number of iterations allowed. - tol : float, 1e-3 + tol : float, default=1e-3 Convergence tolerance: threshold to consider the system at steady state. diff --git a/sklearn/semi_supervised/_self_training.py b/sklearn/semi_supervised/_self_training.py index d56ebf887828c..4b469a2e9f8d8 100644 --- a/sklearn/semi_supervised/_self_training.py +++ b/sklearn/semi_supervised/_self_training.py @@ -4,10 +4,14 @@ import numpy as np -from sklearn.base import ClassifierMixin - -from ..base import BaseEstimator, MetaEstimatorMixin, _fit_context, clone -from ..utils import Bunch, safe_mask +from ..base import ( + BaseEstimator, + ClassifierMixin, + MetaEstimatorMixin, + _fit_context, + clone, +) +from ..utils import Bunch, get_tags, safe_mask from ..utils._param_validation import HasMethods, Hidden, Interval, StrOptions from ..utils.metadata_routing import ( MetadataRouter, @@ -616,7 +620,7 @@ def get_metadata_routing(self): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - tags._xfail_checks.update( - {"check_non_transformer_estimators_n_iter": "n_iter_ can be 0."} - ) + # TODO(1.8): remove the condition check together with base_estimator + if self.estimator is not None: + tags.input_tags.sparse = get_tags(self.estimator).input_tags.sparse return tags diff --git a/sklearn/svm/_base.py b/sklearn/svm/_base.py index 3e5024364df5c..f5b35f39a7daf 100644 --- a/sklearn/svm/_base.py +++ b/sklearn/svm/_base.py @@ -147,6 +147,7 @@ def __sklearn_tags__(self): tags = super().__sklearn_tags__() # Used by cross_val_score. tags.input_tags.pairwise = self.kernel == "precomputed" + tags.input_tags.sparse = self.kernel != "precomputed" return tags @_fit_context(prefer_skip_nested_validation=True) @@ -999,6 +1000,11 @@ def probB_(self): """ return self._probB + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = self.kernel != "precomputed" + return tags + def _get_liblinear_solver_type(multi_class, penalty, loss, dual): """Find the liblinear magic number for the solver. diff --git a/sklearn/svm/_classes.py b/sklearn/svm/_classes.py index f4e4aa118c069..0eb49a8c0832c 100644 --- a/sklearn/svm/_classes.py +++ b/sklearn/svm/_classes.py @@ -351,15 +351,7 @@ def fit(self, X, y, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test when _dual=True, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - "check_non_transformer_estimators_n_iter": ( - "n_iter_ cannot be easily accessed." - ), - } + tags.input_tags.sparse = True return tags @@ -615,12 +607,7 @@ def fit(self, X, y, sample_weight=None): def __sklearn_tags__(self): tags = super().__sklearn_tags__() - # TODO: replace by a statistical test, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } + tags.input_tags.sparse = True return tags @@ -900,18 +887,6 @@ def __init__( random_state=random_state, ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - # TODO: fix sample_weight handling of this estimator when probability=False - # TODO: replace by a statistical test when probability=True - # see meta-issue #16298 - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class NuSVC(BaseSVC): """Nu-Support Vector Classification. @@ -1175,25 +1150,6 @@ def __init__( random_state=random_state, ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - tags._xfail_checks = { - "check_methods_subset_invariance": ( - "fails for the decision_function method" - ), - "check_class_weight_classifiers": "class_weight is ignored.", - # TODO: fix sample_weight handling of this estimator when probability=False - # TODO: replace by a statistical test when probability=True - # see meta-issue #16298 - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - "check_classifiers_one_label_sample_weights": ( - "specified nu is infeasible for the fit." - ), - } - return tags - class SVR(RegressorMixin, BaseLibSVM): """Epsilon-Support Vector Regression. @@ -1217,6 +1173,8 @@ class SVR(RegressorMixin, BaseLibSVM): Specifies the kernel type to be used in the algorithm. If none is given, 'rbf' will be used. If a callable is given it is used to precompute the kernel matrix. + For an intuitive visualization of different kernel types + see :ref:`sphx_glr_auto_examples_svm_plot_svm_regression.py` degree : int, default=3 Degree of the polynomial kernel function ('poly'). @@ -1386,16 +1344,6 @@ def __init__( random_state=None, ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class NuSVR(RegressorMixin, BaseLibSVM): """Nu Support Vector Regression. @@ -1425,6 +1373,8 @@ class NuSVR(RegressorMixin, BaseLibSVM): Specifies the kernel type to be used in the algorithm. If none is given, 'rbf' will be used. If a callable is given it is used to precompute the kernel matrix. + For an intuitive visualization of different kernel types see + See :ref:`sphx_glr_auto_examples_svm_plot_svm_regression.py` degree : int, default=3 Degree of the polynomial kernel function ('poly'). @@ -1581,16 +1531,6 @@ def __init__( random_state=None, ) - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags - class OneClassSVM(OutlierMixin, BaseLibSVM): """Unsupervised Outlier Detection. @@ -1847,13 +1787,3 @@ def predict(self, X): """ y = super().predict(X) return np.asarray(y, dtype=np.intp) - - def __sklearn_tags__(self): - tags = super().__sklearn_tags__() - # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 - tags._xfail_checks = { - "check_sample_weight_equivalence": ( - "sample_weight is not equivalent to removing/repeating samples." - ), - } - return tags diff --git a/sklearn/tests/metadata_routing_common.py b/sklearn/tests/metadata_routing_common.py index 174164daada8c..98503652df6f0 100644 --- a/sklearn/tests/metadata_routing_common.py +++ b/sklearn/tests/metadata_routing_common.py @@ -347,6 +347,7 @@ def fit(self, X, y=None, sample_weight="default", metadata="default"): record_metadata_not_default( self, sample_weight=sample_weight, metadata=metadata ) + self.fitted_ = True return self def transform(self, X, sample_weight="default", metadata="default"): diff --git a/sklearn/tests/test_common.py b/sklearn/tests/test_common.py index 455234adfad5b..59b45b93a7e24 100644 --- a/sklearn/tests/test_common.py +++ b/sklearn/tests/test_common.py @@ -19,6 +19,7 @@ import sklearn from sklearn.base import BaseEstimator from sklearn.compose import ColumnTransformer +from sklearn.datasets import make_classification from sklearn.exceptions import ConvergenceWarning # make it possible to discover experimental estimators when calling `all_estimators` @@ -35,16 +36,9 @@ StandardScaler, ) from sklearn.utils import all_estimators -from sklearn.utils._tags import ( - ClassifierTags, - InputTags, - RegressorTags, - TargetTags, - TransformerTags, - get_tags, -) from sklearn.utils._test_common.instance_generator import ( _get_check_estimator_ids, + _get_expected_failed_checks, _tested_estimators, ) from sklearn.utils._testing import ( @@ -118,7 +112,9 @@ def test_get_check_estimator_ids(val, expected): assert _get_check_estimator_ids(val) == expected -@parametrize_with_checks(list(_tested_estimators())) +@parametrize_with_checks( + list(_tested_estimators()), expected_failed_checks=_get_expected_failed_checks +) def test_estimators(estimator, check, request): # Common tests for estimator instances with ignore_warnings( @@ -127,8 +123,14 @@ def test_estimators(estimator, check, request): check(estimator) -def test_check_estimator_generate_only(): - all_instance_gen_checks = check_estimator(LogisticRegression(), generate_only=True) +# TODO(1.8): remove test when generate_only is removed +def test_check_estimator_generate_only_deprecation(): + """Check that check_estimator with generate_only=True raises a deprecation + warning.""" + with pytest.warns(FutureWarning, match="`generate_only` is deprecated in 1.6"): + all_instance_gen_checks = check_estimator( + LogisticRegression(), generate_only=True + ) assert isgenerator(all_instance_gen_checks) @@ -219,56 +221,6 @@ def test_class_support_removed(): parametrize_with_checks([LogisticRegression]) -@pytest.mark.parametrize( - "estimator", _tested_estimators(), ids=_get_check_estimator_ids -) -def test_valid_tag_types(estimator): - """Check that estimator tags are valid.""" - tags = get_tags(estimator) - assert isinstance(tags.estimator_type, (str, type(None))) - assert isinstance(tags.target_tags, TargetTags) - assert isinstance(tags.classifier_tags, (ClassifierTags, type(None))) - assert isinstance(tags.regressor_tags, (RegressorTags, type(None))) - assert isinstance(tags.transformer_tags, (TransformerTags, type(None))) - assert isinstance(tags.input_tags, InputTags) - assert isinstance(tags.array_api_support, bool) - assert isinstance(tags.no_validation, bool) - assert isinstance(tags.non_deterministic, bool) - assert isinstance(tags.requires_fit, bool) - assert isinstance(tags._skip_test, bool) - assert isinstance(tags._xfail_checks, dict) - - assert isinstance(tags.target_tags.required, bool) - assert isinstance(tags.target_tags.one_d_labels, bool) - assert isinstance(tags.target_tags.two_d_labels, bool) - assert isinstance(tags.target_tags.positive_only, bool) - assert isinstance(tags.target_tags.multi_output, bool) - assert isinstance(tags.target_tags.single_output, bool) - - assert isinstance(tags.input_tags.pairwise, bool) - assert isinstance(tags.input_tags.allow_nan, bool) - assert isinstance(tags.input_tags.sparse, bool) - assert isinstance(tags.input_tags.categorical, bool) - assert isinstance(tags.input_tags.string, bool) - assert isinstance(tags.input_tags.dict, bool) - assert isinstance(tags.input_tags.one_d_array, bool) - assert isinstance(tags.input_tags.two_d_array, bool) - assert isinstance(tags.input_tags.three_d_array, bool) - assert isinstance(tags.input_tags.positive_only, bool) - - if tags.classifier_tags is not None: - assert isinstance(tags.classifier_tags.poor_score, bool) - assert isinstance(tags.classifier_tags.multi_class, bool) - assert isinstance(tags.classifier_tags.multi_label, bool) - - if tags.regressor_tags is not None: - assert isinstance(tags.regressor_tags.poor_score, bool) - assert isinstance(tags.regressor_tags.multi_label, bool) - - if tags.transformer_tags is not None: - assert isinstance(tags.transformer_tags.preserves_dtype, list) - - def _estimators_that_predict_in_fit(): for estimator in _tested_estimators(): est_params = set(estimator.get_params()) @@ -305,8 +257,9 @@ def _estimators_that_predict_in_fit(): def test_pandas_column_name_consistency(estimator): if isinstance(estimator, ColumnTransformer): pytest.skip("ColumnTransformer is not tested here") - tags = get_tags(estimator) - if "check_dataframe_column_names_consistency" in tags._xfail_checks: + if "check_dataframe_column_names_consistency" in _get_expected_failed_checks( + estimator + ): pytest.skip( "Estimator does not support check_dataframe_column_names_consistency" ) @@ -451,3 +404,37 @@ def test_check_inplace_ensure_writeable(estimator): estimator.set_params(kernel="precomputed") check_inplace_ensure_writeable(name, estimator) + + +# TODO(1.7): Remove this test when the deprecation cycle is over +def test_transition_public_api_deprecations(): + """This test checks that we raised deprecation warning explaining how to transition + to the new developer public API from 1.5 to 1.6. + """ + + class OldEstimator(BaseEstimator): + def fit(self, X, y=None): + X = self._validate_data(X) + self._check_n_features(X, reset=True) + self._check_feature_names(X, reset=True) + return self + + def transform(self, X): + return X # pragma: no cover + + X, y = make_classification(n_samples=10, n_features=5, random_state=0) + + old_estimator = OldEstimator() + with pytest.warns(FutureWarning) as warning_list: + old_estimator.fit(X) + + assert len(warning_list) == 3 + assert str(warning_list[0].message).startswith( + "`BaseEstimator._validate_data` is deprecated" + ) + assert str(warning_list[1].message).startswith( + "`BaseEstimator._check_n_features` is deprecated" + ) + assert str(warning_list[2].message).startswith( + "`BaseEstimator._check_feature_names` is deprecated" + ) diff --git a/sklearn/tests/test_docstring_parameters.py b/sklearn/tests/test_docstring_parameters.py index f3a6ba999f7f6..4fc7d0f3d7009 100644 --- a/sklearn/tests/test_docstring_parameters.py +++ b/sklearn/tests/test_docstring_parameters.py @@ -327,21 +327,50 @@ def _get_all_fitted_attributes(estimator): @skip_if_no_numpydoc def test_precision_recall_f_score_docstring_consistency(): """Check docstrings parameters of related metrics are consistent.""" + metrics_to_check = [ + metrics.precision_recall_fscore_support, + metrics.f1_score, + metrics.fbeta_score, + metrics.precision_score, + metrics.recall_score, + ] assert_docstring_consistency( - [ - metrics.precision_recall_fscore_support, - metrics.f1_score, - metrics.fbeta_score, - metrics.precision_score, - metrics.recall_score, - ], + metrics_to_check, include_params=True, - # "average" - in `recall_score` we have an additional line: 'Weighted recall - # is equal to accuracy.'. # "zero_division" - the reason for zero division differs between f scores, - # precison and recall. + # precision and recall. exclude_params=["average", "zero_division"], ) + description_regex = ( + r"""This parameter is required for multiclass/multilabel targets\. + If ``None``, the metrics for each class are returned\. Otherwise, this + determines the type of averaging performed on the data: + ``'binary'``: + Only report results for the class specified by ``pos_label``\. + This is applicable only if targets \(``y_\{true,pred\}``\) are binary\. + ``'micro'``: + Calculate metrics globally by counting the total true positives, + false negatives and false positives\. + ``'macro'``: + Calculate metrics for each label, and find their unweighted + mean\. This does not take label imbalance into account\. + ``'weighted'``: + Calculate metrics for each label, and find their average weighted + by support \(the number of true instances for each label\)\. This + alters 'macro' to account for label imbalance; it can result in an + F-score that is not between precision and recall\.""" + + r"[\s\w]*\.*" # optionally match additonal sentence + + r""" + ``'samples'``: + Calculate metrics for each instance, and find their average \(only + meaningful for multilabel classification where this differs from + :func:`accuracy_score`\)\.""" + ) + assert_docstring_consistency( + metrics_to_check, + include_params=["average"], + descr_regex_pattern=" ".join(description_regex.split()), + ) @skip_if_no_numpydoc diff --git a/sklearn/tests/test_pipeline.py b/sklearn/tests/test_pipeline.py index d425c00f114a2..d7a201f3abf6f 100644 --- a/sklearn/tests/test_pipeline.py +++ b/sklearn/tests/test_pipeline.py @@ -14,7 +14,14 @@ import pytest from sklearn import config_context -from sklearn.base import BaseEstimator, TransformerMixin, clone, is_classifier +from sklearn.base import ( + BaseEstimator, + ClassifierMixin, + TransformerMixin, + clone, + is_classifier, + is_regressor, +) from sklearn.cluster import KMeans from sklearn.datasets import load_iris from sklearn.decomposition import PCA, TruncatedSVD @@ -41,6 +48,7 @@ _Registry, check_recorded_metadata, ) +from sklearn.utils import get_tags from sklearn.utils._metadata_requests import COMPOSITE_METHODS, METHODS from sklearn.utils._testing import ( MinimalClassifier, @@ -350,7 +358,7 @@ def test_pipeline_raise_set_params_error(): error_msg = re.escape( "Invalid parameter 'fake' for estimator Pipeline(steps=[('cls'," " LinearRegression())]). Valid parameters are: ['memory', 'steps'," - " 'verbose']." + " 'transform_input', 'verbose']." ) with pytest.raises(ValueError, match=error_msg): pipe.set_params(fake="nope") @@ -775,6 +783,7 @@ def make(): "memory": None, "m2__mult": 2, "last__mult": 5, + "transform_input": None, "verbose": False, } @@ -867,6 +876,42 @@ def test_make_pipeline(): assert pipe.steps[2][0] == "fitparamt" +@pytest.mark.parametrize( + "pipeline, check_estimator_type", + [ + (make_pipeline(StandardScaler(), LogisticRegression()), is_classifier), + (make_pipeline(StandardScaler(), LinearRegression()), is_regressor), + ( + make_pipeline(StandardScaler()), + lambda est: get_tags(est).estimator_type is None, + ), + (Pipeline([]), lambda est: est._estimator_type is None), + ], +) +def test_pipeline_estimator_type(pipeline, check_estimator_type): + """Check that the estimator type returned by the pipeline is correct. + + Non-regression test as part of: + https://github.com/scikit-learn/scikit-learn/issues/30197 + """ + # Smoke test the repr + repr(pipeline) + assert check_estimator_type(pipeline) + + +def test_sklearn_tags_with_empty_pipeline(): + """Check that we propagate properly the tags in a Pipeline. + + Non-regression test as part of: + https://github.com/scikit-learn/scikit-learn/issues/30197 + """ + empty_pipeline = Pipeline(steps=[]) + be = BaseEstimator() + + expected_tags = be.__sklearn_tags__() + assert empty_pipeline.__sklearn_tags__() == expected_tags + + def test_feature_union_weights(): # test feature union with transformer weights X = iris.data @@ -1828,6 +1873,176 @@ def test_pipeline_inverse_transform_Xt_deprecation(): pipe.inverse_transform(Xt=X) +# transform_input tests +# ===================== + + +@config_context(enable_metadata_routing=True) +@pytest.mark.parametrize("method", ["fit", "fit_transform"]) +def test_transform_input_pipeline(method): + """Test that with transform_input, data is correctly transformed for each step.""" + + def get_transformer(registry, sample_weight, metadata): + """Get a transformer with requests set.""" + return ( + ConsumingTransformer(registry=registry) + .set_fit_request(sample_weight=sample_weight, metadata=metadata) + .set_transform_request(sample_weight=sample_weight, metadata=metadata) + ) + + def get_pipeline(): + """Get a pipeline and corresponding registries. + + The pipeline has 4 steps, with different request values set to test different + cases. One is aliased. + """ + registry_1, registry_2, registry_3, registry_4 = ( + _Registry(), + _Registry(), + _Registry(), + _Registry(), + ) + pipe = make_pipeline( + get_transformer(registry_1, sample_weight=True, metadata=True), + get_transformer(registry_2, sample_weight=False, metadata=False), + get_transformer(registry_3, sample_weight=True, metadata=True), + get_transformer(registry_4, sample_weight="other_weights", metadata=True), + transform_input=["sample_weight"], + ) + return pipe, registry_1, registry_2, registry_3, registry_4 + + def check_metadata(registry, methods, **metadata): + """Check that the right metadata was recorded for the given methods.""" + assert registry + for estimator in registry: + for method in methods: + check_recorded_metadata( + estimator, + method=method, + parent=method, + **metadata, + ) + + X = np.array([[1, 2], [3, 4]]) + y = np.array([0, 1]) + sample_weight = np.array([[1, 2]]) + other_weights = np.array([[30, 40]]) + metadata = np.array([[100, 200]]) + + pipe, registry_1, registry_2, registry_3, registry_4 = get_pipeline() + pipe.fit( + X, + y, + sample_weight=sample_weight, + other_weights=other_weights, + metadata=metadata, + ) + + check_metadata( + registry_1, ["fit", "transform"], sample_weight=sample_weight, metadata=metadata + ) + check_metadata(registry_2, ["fit", "transform"]) + check_metadata( + registry_3, + ["fit", "transform"], + sample_weight=sample_weight + 2, + metadata=metadata, + ) + check_metadata( + registry_4, + method.split("_"), # ["fit", "transform"] if "fit_transform", ["fit"] otherwise + sample_weight=other_weights + 3, + metadata=metadata, + ) + + +@config_context(enable_metadata_routing=True) +def test_transform_input_explicit_value_check(): + """Test that the right transformed values are passed to `fit`.""" + + class Transformer(TransformerMixin, BaseEstimator): + def fit(self, X, y): + self.fitted_ = True + return self + + def transform(self, X): + return X + 1 + + class Estimator(ClassifierMixin, BaseEstimator): + def fit(self, X, y, X_val=None, y_val=None): + assert_array_equal(X, np.array([[1, 2]])) + assert_array_equal(y, np.array([0, 1])) + assert_array_equal(X_val, np.array([[2, 3]])) + assert_array_equal(y_val, np.array([0, 1])) + return self + + X = np.array([[0, 1]]) + y = np.array([0, 1]) + X_val = np.array([[1, 2]]) + y_val = np.array([0, 1]) + pipe = Pipeline( + [ + ("transformer", Transformer()), + ("estimator", Estimator().set_fit_request(X_val=True, y_val=True)), + ], + transform_input=["X_val"], + ) + pipe.fit(X, y, X_val=X_val, y_val=y_val) + + +def test_transform_input_no_slep6(): + """Make sure the right error is raised if slep6 is not enabled.""" + X = np.array([[1, 2], [3, 4]]) + y = np.array([0, 1]) + msg = "The `transform_input` parameter can only be set if metadata" + with pytest.raises(ValueError, match=msg): + make_pipeline(DummyTransf(), transform_input=["blah"]).fit(X, y) + + +@config_context(enable_metadata_routing=True) +def test_transform_tuple_input(): + """Test that if metadata is a tuple of arrays, both arrays are transformed.""" + + class Estimator(ClassifierMixin, BaseEstimator): + def fit(self, X, y, X_val=None, y_val=None): + assert isinstance(X_val, tuple) + assert isinstance(y_val, tuple) + # Here we make sure that each X_val is transformed by the transformer + assert_array_equal(X_val[0], np.array([[2, 3]])) + assert_array_equal(y_val[0], np.array([0, 1])) + assert_array_equal(X_val[1], np.array([[11, 12]])) + assert_array_equal(y_val[1], np.array([1, 2])) + self.fitted_ = True + return self + + class Transformer(TransformerMixin, BaseEstimator): + def fit(self, X, y): + self.fitted_ = True + return self + + def transform(self, X): + return X + 1 + + X = np.array([[1, 2]]) + y = np.array([0, 1]) + X_val0 = np.array([[1, 2]]) + y_val0 = np.array([0, 1]) + X_val1 = np.array([[10, 11]]) + y_val1 = np.array([1, 2]) + pipe = Pipeline( + [ + ("transformer", Transformer()), + ("estimator", Estimator().set_fit_request(X_val=True, y_val=True)), + ], + transform_input=["X_val"], + ) + pipe.fit(X, y, X_val=(X_val0, X_val1), y_val=(y_val0, y_val1)) + + +# end of transform_input tests +# ============================= + + # TODO(1.8): change warning to checking for NotFittedError @pytest.mark.parametrize( "method", diff --git a/sklearn/tree/_classes.py b/sklearn/tree/_classes.py index 93246a1376e85..646aa7fb034c4 100644 --- a/sklearn/tree/_classes.py +++ b/sklearn/tree/_classes.py @@ -690,6 +690,11 @@ def feature_importances_(self): return self.tree_.compute_feature_importances() + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = True + return tags + # ============================================================================= # Public estimators diff --git a/sklearn/tree/_partitioner.pyx b/sklearn/tree/_partitioner.pyx index 57801c3f279ed..575a9413e09ca 100644 --- a/sklearn/tree/_partitioner.pyx +++ b/sklearn/tree/_partitioner.pyx @@ -11,7 +11,7 @@ and sparse data stored in a Compressed Sparse Column (CSC) format. # SPDX-License-Identifier: BSD-3-Clause from cython cimport final -from libc.math cimport isnan, log +from libc.math cimport isnan, log2 from libc.stdlib cimport qsort from libc.string cimport memcpy @@ -194,7 +194,7 @@ cdef class DensePartitioner: """Partition samples for feature_values at the current_threshold.""" cdef: intp_t p = self.start - intp_t partition_end = self.end + intp_t partition_end = self.end - self.n_missing intp_t[::1] samples = self.samples float32_t[::1] feature_values = self.feature_values @@ -503,8 +503,8 @@ cdef class SparsePartitioner: # O(n_samples * log(n_indices)) is the running time of binary # search and O(n_indices) is the running time of index_to_samples # approach. - if ((1 - self.is_samples_sorted) * n_samples * log(n_samples) + - n_samples * log(n_indices) < EXTRACT_NNZ_SWITCH * n_indices): + if ((1 - self.is_samples_sorted) * n_samples * log2(n_samples) + + n_samples * log2(n_indices) < EXTRACT_NNZ_SWITCH * n_indices): extract_nnz_binary_search(X_indices, X_data, indptr_start, indptr_end, samples, self.start, self.end, @@ -702,12 +702,17 @@ cdef inline void shift_missing_values_to_left_if_required( best.pos += best.n_missing +def _py_sort(float32_t[::1] feature_values, intp_t[::1] samples, intp_t n): + """Used for testing sort.""" + sort(&feature_values[0], &samples[0], n) + + # Sort n-element arrays pointed to by feature_values and samples, simultaneously, # by the values in feature_values. Algorithm: Introsort (Musser, SP&E, 1997). cdef inline void sort(float32_t* feature_values, intp_t* samples, intp_t n) noexcept nogil: if n == 0: return - cdef intp_t maxd = 2 * log(n) + cdef intp_t maxd = 2 * log2(n) introsort(feature_values, samples, n, maxd) diff --git a/sklearn/tree/tests/test_tree.py b/sklearn/tree/tests/test_tree.py index fb5af073fc8c6..dc36bd6dc6a3e 100644 --- a/sklearn/tree/tests/test_tree.py +++ b/sklearn/tree/tests/test_tree.py @@ -6,6 +6,7 @@ import copyreg import io import pickle +import re import struct from itertools import chain, product @@ -35,6 +36,7 @@ DENSE_SPLITTERS, SPARSE_SPLITTERS, ) +from sklearn.tree._partitioner import _py_sort from sklearn.tree._tree import ( NODE_DTYPE, TREE_LEAF, @@ -1137,7 +1139,13 @@ def test_sample_weight_invalid(): clf.fit(X, y, sample_weight=sample_weight) sample_weight = np.array(0) - expected_err = r"Singleton.* cannot be considered a valid collection" + + expected_err = re.escape( + ( + "Input should have at least 1 dimension i.e. satisfy " + "`len(x.shape) > 0`, got scalar `array(0.)` instead." + ) + ) with pytest.raises(TypeError, match=expected_err): clf.fit(X, y, sample_weight=sample_weight) @@ -2689,10 +2697,8 @@ def test_regression_tree_missing_values_toy(Tree, X, criterion): impurity = tree.tree_.impurity assert all(impurity >= 0), impurity.min() # MSE should always be positive - # Note: the impurity matches after the first split only on greedy trees - if Tree is DecisionTreeRegressor: - # Check the impurity match after the first split - assert_allclose(tree.tree_.impurity[:2], tree_ref.tree_.impurity[:2]) + # Check the impurity match after the first split + assert_allclose(tree.tree_.impurity[:2], tree_ref.tree_.impurity[:2]) # Find the leaves with a single sample where the MSE should be 0 leaves_idx = np.flatnonzero( @@ -2701,6 +2707,20 @@ def test_regression_tree_missing_values_toy(Tree, X, criterion): assert_allclose(tree.tree_.impurity[leaves_idx], 0.0) +def test_regression_extra_tree_missing_values_toy(global_random_seed): + rng = np.random.RandomState(global_random_seed) + n_samples = 100 + X = np.arange(n_samples, dtype=np.float64).reshape(-1, 1) + X[-20:, :] = np.nan + rng.shuffle(X) + y = np.arange(n_samples) + + tree = ExtraTreeRegressor(random_state=global_random_seed, max_depth=5).fit(X, y) + + impurity = tree.tree_.impurity + assert all(impurity >= 0), impurity # MSE should always be positive + + def test_classification_tree_missing_values_toy(): """Check that we properly handle missing values in clasification trees using a toy dataset. @@ -2795,3 +2815,25 @@ def test_build_pruned_tree_infinite_loop(): ValueError, match="Node has reached a leaf in the original tree" ): _build_pruned_tree_py(pruned_tree, tree.tree_, leave_in_subtree) + + +def test_sort_log2_build(): + """Non-regression test for gh-30554. + + Using log2 and log in sort correctly sorts feature_values, but the tie breaking is + different which can results in placing samples in a different order. + """ + rng = np.random.default_rng(75) + some = rng.normal(loc=0.0, scale=10.0, size=10).astype(np.float32) + feature_values = np.concatenate([some] * 5) + samples = np.arange(50) + _py_sort(feature_values, samples, 50) + # fmt: off + # no black reformatting for this specific array + expected_samples = [ + 0, 40, 30, 20, 10, 29, 39, 19, 49, 9, 45, 15, 35, 5, 25, 11, 31, + 41, 1, 21, 22, 12, 2, 42, 32, 23, 13, 43, 3, 33, 6, 36, 46, 16, + 26, 4, 14, 24, 34, 44, 27, 47, 7, 37, 17, 8, 38, 48, 28, 18 + ] + # fmt: on + assert_array_equal(samples, expected_samples) diff --git a/sklearn/utils/_array_api.py b/sklearn/utils/_array_api.py index 98140361d055e..e8e0aa3db1fc0 100644 --- a/sklearn/utils/_array_api.py +++ b/sklearn/utils/_array_api.py @@ -130,10 +130,17 @@ def _check_array_api_dispatch(array_api_dispatch): def _single_array_device(array): """Hardware device where the array data resides on.""" - if isinstance(array, (numpy.ndarray, numpy.generic)) or not hasattr( - array, "device" + if ( + isinstance(array, (numpy.ndarray, numpy.generic)) + or not hasattr(array, "device") + # When array API dispatch is disabled, we expect the scikit-learn code + # to use np.asarray so that the resulting NumPy array will implicitly use the + # CPU. In this case, scikit-learn should stay as device neutral as possible, + # hence the use of `device=None` which is accepted by all libraries, before + # and after the expected conversion to NumPy via np.asarray. + or not get_config()["array_api_dispatch"] ): - return "cpu" + return None else: return array.device @@ -795,6 +802,19 @@ def _nanmax(X, axis=None, xp=None): return X +def _nanmean(X, axis=None, xp=None): + # TODO: refactor once nan-aware reductions are standardized: + # https://github.com/data-apis/array-api/issues/621 + xp, _ = get_namespace(X, xp=xp) + if _is_numpy_namespace(xp): + return xp.asarray(numpy.nanmean(X, axis=axis)) + else: + mask = xp.isnan(X) + total = xp.sum(xp.where(mask, xp.asarray(0.0, device=device(X)), X), axis=axis) + count = xp.sum(xp.astype(xp.logical_not(mask), X.dtype), axis=axis) + return total / count + + def _asarray_with_order( array, dtype=None, order=None, copy=None, *, xp=None, device=None ): @@ -914,11 +934,12 @@ def indexing_dtype(xp): return xp.asarray(0).dtype -def _searchsorted(xp, a, v, *, side="left", sorter=None): +def _searchsorted(a, v, *, side="left", sorter=None, xp=None): # Temporary workaround needed as long as searchsorted is not widely # adopted by implementers of the Array API spec. This is a quite # recent addition to the spec: # https://data-apis.org/array-api/latest/API_specification/generated/array_api.searchsorted.html # noqa + xp, _ = get_namespace(a, v, xp=xp) if hasattr(xp, "searchsorted"): return xp.searchsorted(a, v, side=side, sorter=sorter) @@ -1032,11 +1053,18 @@ def _in1d(ar1, ar2, xp, assume_unique=False, invert=False): return xp.take(ret, rev_idx, axis=0) -def _count_nonzero(X, xp, device, axis=None, sample_weight=None): +def _count_nonzero(X, axis=None, sample_weight=None, xp=None, device=None): """A variant of `sklearn.utils.sparsefuncs.count_nonzero` for the Array API. - It only supports 2D arrays. + If the array `X` is sparse, and we are using the numpy namespace then we + simply call the original function. This function only supports 2D arrays. """ + from .sparsefuncs import count_nonzero + + xp, _ = get_namespace(X, sample_weight, xp=xp) + if _is_numpy_namespace(xp) and sp.issparse(X): + return count_nonzero(X, axis=axis, sample_weight=sample_weight) + assert X.ndim == 2 weights = xp.ones_like(X, device=device) @@ -1055,3 +1083,27 @@ def _modify_in_place_if_numpy(xp, func, *args, out=None, **kwargs): else: out = func(*args, **kwargs) return out + + +def _bincount(array, weights=None, minlength=None, xp=None): + # TODO: update if bincount is ever adopted in a future version of the standard: + # https://github.com/data-apis/array-api/issues/812 + xp, _ = get_namespace(array, xp=xp) + if hasattr(xp, "bincount"): + return xp.bincount(array, weights=weights, minlength=minlength) + + array_np = _convert_to_numpy(array, xp=xp) + if weights is not None: + weights_np = _convert_to_numpy(weights, xp=xp) + else: + weights_np = None + bin_out = numpy.bincount(array_np, weights=weights_np, minlength=minlength) + return xp.asarray(bin_out, device=device(array)) + + +def _tolist(array, xp=None): + xp, _ = get_namespace(array, xp=xp) + if _is_numpy_namespace(xp): + return array.tolist() + array_np = _convert_to_numpy(array, xp=xp) + return [element.item() for element in array_np] diff --git a/sklearn/utils/_encode.py b/sklearn/utils/_encode.py index 479b11e0f59a2..045ce3e11919a 100644 --- a/sklearn/utils/_encode.py +++ b/sklearn/utils/_encode.py @@ -77,7 +77,7 @@ def _unique_np(values, return_inverse=False, return_counts=False): # np.unique will have duplicate missing values at the end of `uniques` # here we clip the nans and remove it from uniques if uniques.size and is_scalar_nan(uniques[-1]): - nan_idx = _searchsorted(xp, uniques, xp.nan) + nan_idx = _searchsorted(uniques, xp.nan, xp=xp) uniques = uniques[: nan_idx + 1] if return_inverse: inverse[inverse > nan_idx] = nan_idx @@ -240,7 +240,7 @@ def _encode(values, *, uniques, check_unknown=True): diff = _check_unknown(values, uniques) if diff: raise ValueError(f"y contains previously unseen labels: {str(diff)}") - return _searchsorted(xp, uniques, values) + return _searchsorted(uniques, values, xp=xp) def _check_unknown(values, known_values, return_mask=False): diff --git a/sklearn/utils/_response.py b/sklearn/utils/_response.py index 86c430dbd23f2..12cbff2230b17 100644 --- a/sklearn/utils/_response.py +++ b/sklearn/utils/_response.py @@ -84,7 +84,7 @@ def _process_decision_function(*, y_pred, target_type, classes, pos_label): Parameters ---------- y_pred : ndarray - Output of `estimator.predict_proba`. The shape depends on the target type: + Output of `estimator.decision_function`. The shape depends on the target type: - for binary classification, it is a 1d array of shape `(n_samples,)` where the sign is assuming that `classes[1]` is the positive class; diff --git a/sklearn/utils/_tags.py b/sklearn/utils/_tags.py index de756901d98ef..ffb654c83637b 100644 --- a/sklearn/utils/_tags.py +++ b/sklearn/utils/_tags.py @@ -1,7 +1,9 @@ from __future__ import annotations import warnings +from collections import OrderedDict from dataclasses import dataclass, field +from itertools import chain from .fixes import _dataclass_args @@ -56,6 +58,10 @@ class InputTags: Specifically, this tag is used by `sklearn.utils.metaestimators._safe_split` to slice rows and columns. + + Note that if setting this tag to ``True`` means the estimator can take only + positive values, the `positive_only` tag must reflect it and also be set to + ``True``. """ one_d_array: bool = False @@ -96,6 +102,8 @@ class TargetTags: Whether a regressor supports multi-target outputs or a classifier supports multi-class multi-output. + See :term:`multi-output` in the glossary. + single_output : bool, default=True Whether the target can be single-output. This can be ``False`` if the estimator supports only multi-output cases. @@ -148,8 +156,13 @@ class ClassifierTags: classification. Therefore this flag indicates whether the classifier is a binary-classifier-only or not. + See :term:`multi-class` in the glossary. + multi_label : bool, default=False - Whether the classifier supports multi-label output. + Whether the classifier supports multi-label output: a data point can + be predicted to belong to a variable number of classes. + + See :term:`multi-label` in the glossary. """ poor_score: bool = False @@ -170,13 +183,9 @@ class RegressorTags: n_informative=1, bias=5.0, noise=20, random_state=42)``. The dataset and values are based on current estimators in scikit-learn and might be replaced by something more systematic. - - multi_label : bool, default=False - Whether the regressor supports multilabel output. """ poor_score: bool = False - multi_label: bool = False @dataclass(**_dataclass_args()) @@ -226,33 +235,20 @@ class Tags: Whether to skip common tests entirely. Don't use this unless you have a *very good* reason. - _xfail_checks : dict[str, str], default={} - Dictionary ``{check_name: reason}`` of common checks that will - be marked as `XFAIL` for pytest, when using - :func:`~sklearn.utils.estimator_checks.parametrize_with_checks`. These - checks will be simply ignored and not run by - :func:`~sklearn.utils.estimator_checks.check_estimator`, but a - `SkipTestWarning` will be raised. Don't use this unless there - is a *very good* reason for your estimator not to pass the - check. Also note that the usage of this tag is highly subject - to change because we are trying to make it more flexible: be - prepared for breaking changes in the future. - input_tags : :class:`InputTags` The input data(X) tags. """ estimator_type: str | None target_tags: TargetTags - transformer_tags: TransformerTags | None - classifier_tags: ClassifierTags | None - regressor_tags: RegressorTags | None + transformer_tags: TransformerTags | None = None + classifier_tags: ClassifierTags | None = None + regressor_tags: RegressorTags | None = None array_api_support: bool = False no_validation: bool = False non_deterministic: bool = False requires_fit: bool = True _skip_test: bool = False - _xfail_checks: dict[str, str] = field(default_factory=dict) input_tags: InputTags = field(default_factory=InputTags) @@ -303,6 +299,71 @@ def default_tags(estimator) -> Tags: ) +# TODO(1.7): Remove this function +def _find_tags_provider(estimator, warn=True): + """Find the tags provider for an estimator. + + Parameters + ---------- + estimator : estimator object + The estimator to find the tags provider for. + + warn : bool, default=True + Whether to warn if the tags provider is not found. + + Returns + ------- + tag_provider : str + The tags provider for the estimator. Can be one of: + - "_get_tags": to use the old tags infrastructure + - "__sklearn_tags__": to use the new tags infrastructure + """ + mro_model = type(estimator).mro() + tags_mro = OrderedDict() + for klass in mro_model: + tags_provider = [] + if "_more_tags" in vars(klass): + tags_provider.append("_more_tags") + if "_get_tags" in vars(klass): + tags_provider.append("_get_tags") + if "__sklearn_tags__" in vars(klass): + tags_provider.append("__sklearn_tags__") + tags_mro[klass.__name__] = tags_provider + + all_providers = set(chain.from_iterable(tags_mro.values())) + if "__sklearn_tags__" not in all_providers: + # default on the old tags infrastructure + return "_get_tags" + + tag_provider = "__sklearn_tags__" + for klass in tags_mro: + has_get_or_more_tags = any( + provider in tags_mro[klass] for provider in ("_get_tags", "_more_tags") + ) + has_sklearn_tags = "__sklearn_tags__" in tags_mro[klass] + + if tags_mro[klass] and tag_provider == "__sklearn_tags__": # is it empty + if has_get_or_more_tags and not has_sklearn_tags: + # Case where a class does not implement __sklearn_tags__ and we fallback + # to _get_tags. We should therefore warn for implementing + # __sklearn_tags__. + tag_provider = "_get_tags" + break + + if warn and tag_provider == "_get_tags": + warnings.warn( + f"The {estimator.__class__.__name__} or classes from which it inherits " + "use `_get_tags` and `_more_tags`. Please define the " + "`__sklearn_tags__` method, or inherit from `sklearn.base.BaseEstimator` " + "and/or other appropriate mixins such as `sklearn.base.TransformerMixin`, " + "`sklearn.base.ClassifierMixin`, `sklearn.base.RegressorMixin`, and " + "`sklearn.base.OutlierMixin`. From scikit-learn 1.7, not defining " + "`__sklearn_tags__` will raise an error.", + category=DeprecationWarning, + ) + return tag_provider + + def get_tags(estimator) -> Tags: """Get estimator tags. @@ -316,6 +377,8 @@ def get_tags(estimator) -> Tags: `get_tags(self.estimator)` where `self` is a meta-estimator, or in the common checks. + .. versionadded:: 1.6 + Parameters ---------- estimator : estimator object @@ -326,19 +389,224 @@ def get_tags(estimator) -> Tags: tags : :class:`~.sklearn.utils.Tags` The estimator tags. """ - if hasattr(estimator, "__sklearn_tags__"): - tags = estimator.__sklearn_tags__() + + tag_provider = _find_tags_provider(estimator) + + if tag_provider == "__sklearn_tags__": + # TODO(1.7): turn the warning into an error + try: + tags = estimator.__sklearn_tags__() + except AttributeError as exc: + if str(exc) == "'super' object has no attribute '__sklearn_tags__'": + # workaround the regression reported in + # https://github.com/scikit-learn/scikit-learn/issues/30479 + # `__sklearn_tags__` is implemented by calling + # `super().__sklearn_tags__()` but there is no `__sklearn_tags__` + # method in the base class. + warnings.warn( + f"The following error was raised: {str(exc)}. It seems that " + "there are no classes that implement `__sklearn_tags__` " + "in the MRO and/or all classes in the MRO call " + "`super().__sklearn_tags__()`. Make sure to inherit from " + "`BaseEstimator` which implements `__sklearn_tags__` (or " + "alternatively define `__sklearn_tags__` but we don't recommend " + "this approach). Note that `BaseEstimator` needs to be on the " + "right side of other Mixins in the inheritance order. The " + "default are now used instead since retrieving tags failed. " + "This warning will be replaced by an error in 1.7.", + category=DeprecationWarning, + ) + tags = default_tags(estimator) + else: + raise else: - warnings.warn( - f"Estimator {estimator} has no __sklearn_tags__ attribute, which is " - "defined in `sklearn.base.BaseEstimator`. This will raise an error in " - "scikit-learn 1.8. Please define the __sklearn_tags__ method, or inherit " - "from `sklearn.base.BaseEstimator` and other appropriate mixins such as " - "`sklearn.base.TransformerMixin`, `sklearn.base.ClassifierMixin`, " - "`sklearn.base.RegressorMixin`, and `sklearn.base.ClusterMixin`, and " - "`sklearn.base.OutlierMixin`.", - category=FutureWarning, + # TODO(1.7): Remove this branch of the code + # Let's go through the MRO and patch each class implementing _more_tags + sklearn_tags_provider = {} + more_tags_provider = {} + class_order = [] + for klass in reversed(type(estimator).mro()): + if "__sklearn_tags__" in vars(klass): + sklearn_tags_provider[klass] = klass.__sklearn_tags__(estimator) # type: ignore[attr-defined] + class_order.append(klass) + elif "_more_tags" in vars(klass): + more_tags_provider[klass] = klass._more_tags(estimator) # type: ignore[attr-defined] + class_order.append(klass) + + # Find differences between consecutive in the case of __sklearn_tags__ + # inheritance + sklearn_tags_diff = {} + items = list(sklearn_tags_provider.items()) + for current_item, next_item in zip(items[:-1], items[1:]): + current_name, current_tags = current_item + next_name, next_tags = next_item + current_tags = _to_old_tags(current_tags) + next_tags = _to_old_tags(next_tags) + + # Compare tags and store differences + diff = {} + for key in current_tags: + if current_tags[key] != next_tags[key]: + diff[key] = next_tags[key] + + sklearn_tags_diff[next_name] = diff + + tags = {} + for klass in class_order: + if klass in sklearn_tags_diff: + tags.update(sklearn_tags_diff[klass]) + elif klass in more_tags_provider: + tags.update(more_tags_provider[klass]) + + tags = _to_new_tags( + {**_to_old_tags(default_tags(estimator)), **tags}, estimator + ) + + return tags + + +# TODO(1.7): Remove this function +def _safe_tags(estimator, key=None): + warnings.warn( + "The `_safe_tags` function is deprecated in 1.6 and will be removed in " + "1.7. Use the public `get_tags` function instead and make sure to implement " + "the `__sklearn_tags__` method.", + category=DeprecationWarning, + ) + tags = _to_old_tags(get_tags(estimator)) + + if key is not None: + if key not in tags: + raise ValueError( + f"The key {key} is not defined for the class " + f"{estimator.__class__.__name__}." + ) + return tags[key] + return tags + + +# TODO(1.7): Remove this function +def _to_new_tags(old_tags, estimator=None): + """Utility function convert old tags (dictionary) to new tags (dataclass).""" + input_tags = InputTags( + one_d_array="1darray" in old_tags["X_types"], + two_d_array="2darray" in old_tags["X_types"], + three_d_array="3darray" in old_tags["X_types"], + sparse="sparse" in old_tags["X_types"], + categorical="categorical" in old_tags["X_types"], + string="string" in old_tags["X_types"], + dict="dict" in old_tags["X_types"], + positive_only=old_tags["requires_positive_X"], + allow_nan=old_tags["allow_nan"], + pairwise=old_tags["pairwise"], + ) + target_tags = TargetTags( + required=old_tags["requires_y"], + one_d_labels="1dlabels" in old_tags["X_types"], + two_d_labels="2dlabels" in old_tags["X_types"], + positive_only=old_tags["requires_positive_y"], + multi_output=old_tags["multioutput"] or old_tags["multioutput_only"], + single_output=not old_tags["multioutput_only"], + ) + if estimator is not None and ( + hasattr(estimator, "transform") or hasattr(estimator, "fit_transform") + ): + transformer_tags = TransformerTags( + preserves_dtype=old_tags["preserves_dtype"], + ) + else: + transformer_tags = None + estimator_type = getattr(estimator, "_estimator_type", None) + if estimator_type == "classifier": + classifier_tags = ClassifierTags( + poor_score=old_tags["poor_score"], + multi_class=not old_tags["binary_only"], + multi_label=old_tags["multilabel"], + ) + else: + classifier_tags = None + if estimator_type == "regressor": + regressor_tags = RegressorTags( + poor_score=old_tags["poor_score"], ) - tags = default_tags(estimator) + else: + regressor_tags = None + return Tags( + estimator_type=estimator_type, + target_tags=target_tags, + transformer_tags=transformer_tags, + classifier_tags=classifier_tags, + regressor_tags=regressor_tags, + input_tags=input_tags, + array_api_support=old_tags["array_api_support"], + no_validation=old_tags["no_validation"], + non_deterministic=old_tags["non_deterministic"], + requires_fit=old_tags["requires_fit"], + _skip_test=old_tags["_skip_test"], + ) + +# TODO(1.7): Remove this function +def _to_old_tags(new_tags): + """Utility function convert old tags (dictionary) to new tags (dataclass).""" + if new_tags.classifier_tags: + binary_only = not new_tags.classifier_tags.multi_class + multilabel = new_tags.classifier_tags.multi_label + poor_score_clf = new_tags.classifier_tags.poor_score + else: + binary_only = False + multilabel = False + poor_score_clf = False + + if new_tags.regressor_tags: + poor_score_reg = new_tags.regressor_tags.poor_score + else: + poor_score_reg = False + + if new_tags.transformer_tags: + preserves_dtype = new_tags.transformer_tags.preserves_dtype + else: + preserves_dtype = ["float64"] + + tags = { + "allow_nan": new_tags.input_tags.allow_nan, + "array_api_support": new_tags.array_api_support, + "binary_only": binary_only, + "multilabel": multilabel, + "multioutput": new_tags.target_tags.multi_output, + "multioutput_only": ( + not new_tags.target_tags.single_output and new_tags.target_tags.multi_output + ), + "no_validation": new_tags.no_validation, + "non_deterministic": new_tags.non_deterministic, + "pairwise": new_tags.input_tags.pairwise, + "preserves_dtype": preserves_dtype, + "poor_score": poor_score_clf or poor_score_reg, + "requires_fit": new_tags.requires_fit, + "requires_positive_X": new_tags.input_tags.positive_only, + "requires_y": new_tags.target_tags.required, + "requires_positive_y": new_tags.target_tags.positive_only, + "_skip_test": new_tags._skip_test, + "stateless": new_tags.requires_fit, + } + X_types = [] + if new_tags.input_tags.one_d_array: + X_types.append("1darray") + if new_tags.input_tags.two_d_array: + X_types.append("2darray") + if new_tags.input_tags.three_d_array: + X_types.append("3darray") + if new_tags.input_tags.sparse: + X_types.append("sparse") + if new_tags.input_tags.categorical: + X_types.append("categorical") + if new_tags.input_tags.string: + X_types.append("string") + if new_tags.input_tags.dict: + X_types.append("dict") + if new_tags.target_tags.one_d_labels: + X_types.append("1dlabels") + if new_tags.target_tags.two_d_labels: + X_types.append("2dlabels") + tags["X_types"] = X_types return tags diff --git a/sklearn/utils/_test_common/instance_generator.py b/sklearn/utils/_test_common/instance_generator.py index 7fe6724aaff9a..2f6a64a9d0364 100644 --- a/sklearn/utils/_test_common/instance_generator.py +++ b/sklearn/utils/_test_common/instance_generator.py @@ -111,6 +111,7 @@ RANSACRegressor, Ridge, RidgeClassifier, + RidgeCV, SGDClassifier, SGDOneClassSVM, SGDRegressor, @@ -144,14 +145,24 @@ MultiOutputRegressor, RegressorChain, ) +from sklearn.naive_bayes import CategoricalNB from sklearn.neighbors import ( + KernelDensity, KNeighborsClassifier, KNeighborsRegressor, + KNeighborsTransformer, NeighborhoodComponentsAnalysis, + RadiusNeighborsTransformer, ) from sklearn.neural_network import BernoulliRBM, MLPClassifier, MLPRegressor from sklearn.pipeline import FeatureUnion, Pipeline -from sklearn.preprocessing import OneHotEncoder, StandardScaler, TargetEncoder +from sklearn.preprocessing import ( + KBinsDiscretizer, + OneHotEncoder, + SplineTransformer, + StandardScaler, + TargetEncoder, +) from sklearn.random_projection import ( GaussianRandomProjection, SparseRandomProjection, @@ -164,6 +175,7 @@ from sklearn.svm import SVC, SVR, LinearSVC, LinearSVR, NuSVC, NuSVR, OneClassSVM from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor from sklearn.utils import all_estimators +from sklearn.utils._tags import get_tags from sklearn.utils._testing import SkipTest CROSS_DECOMPOSITION = ["PLSCanonical", "PLSRegression", "CCA", "PLSSVD"] @@ -487,7 +499,6 @@ # TODO(devtools): allow third-party developers to pass test specific params to checks PER_ESTIMATOR_CHECK_PARAMS: dict = { # TODO(devtools): check that function names here exist in checks for the estimator - # TODO(devtools): write a test for the same thing with tags._xfail_checks AgglomerativeClustering: {"check_dict_unchanged": dict(n_clusters=1)}, BayesianGaussianMixture: {"check_dict_unchanged": dict(max_iter=5, n_init=2)}, BernoulliRBM: {"check_dict_unchanged": dict(n_components=1, n_iter=5)}, @@ -495,19 +506,30 @@ BisectingKMeans: {"check_dict_unchanged": dict(max_iter=5, n_clusters=1, n_init=2)}, CCA: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, DecisionTreeRegressor: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(criterion="squared_error"), dict(criterion="absolute_error"), dict(criterion="friedman_mse"), dict(criterion="poisson"), - ] + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(criterion="squared_error"), + dict(criterion="absolute_error"), + dict(criterion="friedman_mse"), + dict(criterion="poisson"), + ], }, DecisionTreeClassifier: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(criterion="gini"), dict(criterion="log_loss"), dict(criterion="entropy"), - ] + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(criterion="gini"), + dict(criterion="log_loss"), + dict(criterion="entropy"), + ], }, DictionaryLearning: { "check_dict_unchanged": dict( @@ -517,11 +539,23 @@ FactorAnalysis: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, FastICA: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, FeatureAgglomeration: {"check_dict_unchanged": dict(n_clusters=1)}, + FeatureUnion: { + "check_estimator_sparse_tag": [ + dict(transformer_list=[("trans1", StandardScaler())]), + dict( + transformer_list=[ + ("trans1", StandardScaler(with_mean=False)), + ("trans2", "drop"), + ("trans3", "passthrough"), + ] + ), + ] + }, GammaRegressor: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="newton-cholesky"), dict(solver="lbfgs"), - ] + ], }, GaussianMixture: {"check_dict_unchanged": dict(max_iter=5, n_init=2)}, GaussianRandomProjection: {"check_dict_unchanged": dict(n_components=1)}, @@ -534,14 +568,24 @@ "check_dict_unchanged": dict(batch_size=10, max_iter=5, n_components=1) }, LinearDiscriminantAnalysis: {"check_dict_unchanged": dict(n_components=1)}, + LinearRegression: { + "check_estimator_sparse_tag": [dict(positive=False), dict(positive=True)], + "check_sample_weight_equivalence_on_dense_data": [ + dict(positive=False), + dict(positive=True), + ], + }, LocallyLinearEmbedding: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, LogisticRegression: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="lbfgs"), dict(solver="liblinear"), dict(solver="newton-cg"), dict(solver="newton-cholesky"), - ] + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(solver="liblinear"), + ], }, MDS: {"check_dict_unchanged": dict(max_iter=5, n_components=1, n_init=2)}, MiniBatchDictionaryLearning: { @@ -568,38 +612,45 @@ PLSRegression: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, PLSSVD: {"check_dict_unchanged": dict(n_components=1)}, PoissonRegressor: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="newton-cholesky"), dict(solver="lbfgs"), - ] + ], }, PolynomialCountSketch: {"check_dict_unchanged": dict(n_components=1)}, QuantileRegressor: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(quantile=0.5), dict(quantile=0.75), dict(solver="highs-ds"), dict(solver="highs-ipm"), - ] + ], }, RBFSampler: {"check_dict_unchanged": dict(n_components=1)}, Ridge: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="svd"), dict(solver="cholesky"), dict(solver="sparse_cg"), dict(solver="lsqr"), dict(solver="lbfgs", positive=True), - ] + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(solver="sparse_cg"), + dict(solver="lsqr"), + ], }, RidgeClassifier: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="svd"), dict(solver="cholesky"), dict(solver="sparse_cg"), dict(solver="lsqr"), - dict(solver="lbfgs", positive=True), - ] + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(solver="sparse_cg"), + dict(solver="lsqr"), + ], }, SkewedChi2Sampler: {"check_dict_unchanged": dict(n_components=1)}, SparsePCA: {"check_dict_unchanged": dict(max_iter=5, n_components=1)}, @@ -612,13 +663,22 @@ }, SpectralCoclustering: {"check_dict_unchanged": dict(n_clusters=1, n_init=2)}, SpectralEmbedding: {"check_dict_unchanged": dict(eigen_tol=1e-05, n_components=1)}, + StandardScaler: { + "check_sample_weight_equivalence_on_dense_data": [ + dict(with_mean=True), + dict(with_mean=False), + ], + "check_sample_weight_equivalence_on_sparse_data": [ + dict(with_mean=False), + ], + }, TSNE: {"check_dict_unchanged": dict(n_components=1, perplexity=2)}, TruncatedSVD: {"check_dict_unchanged": dict(n_components=1)}, TweedieRegressor: { - "check_sample_weight_equivalence": [ + "check_sample_weight_equivalence_on_dense_data": [ dict(solver="newton-cholesky"), dict(solver="lbfgs"), - ] + ], }, } @@ -725,3 +785,480 @@ def _yield_instances_for_check(check, estimator_orig): estimator = clone(estimator_orig) estimator.set_params(**params) yield estimator + + +PER_ESTIMATOR_XFAIL_CHECKS = { + AdaBoostClassifier: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + AdaBoostRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + BaggingClassifier: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + BaggingRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + BayesianRidge: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + BernoulliRBM: { + "check_methods_subset_invariance": ("fails for the decision_function method"), + "check_methods_sample_order_invariance": ("fails for the score_samples method"), + }, + BisectingKMeans: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + CategoricalNB: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + ColumnTransformer: { + "check_estimators_empty_data_messages": "FIXME", + "check_estimators_nan_inf": "FIXME", + "check_estimator_sparse_array": "FIXME", + "check_estimator_sparse_matrix": "FIXME", + "check_fit1d": "FIXME", + "check_fit2d_predict1d": "FIXME", + "check_complex_data": "FIXME", + "check_fit2d_1feature": "FIXME", + }, + DummyClassifier: { + "check_methods_subset_invariance": "fails for the predict method", + "check_methods_sample_order_invariance": "fails for the predict method", + }, + FeatureUnion: { + "check_estimators_overwrite_params": "FIXME", + "check_estimators_nan_inf": "FIXME", + "check_dont_overwrite_parameters": "FIXME", + }, + FixedThresholdClassifier: { + "check_classifiers_train": "Threshold at probability 0.5 does not hold", + "check_sample_weight_equivalence_on_dense_data": ( + "Due to the cross-validation and sample ordering, removing a sample" + " is not strictly equal to putting is weight to zero. Specific unit" + " tests are added for TunedThresholdClassifierCV specifically." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + GradientBoostingClassifier: { + # TODO: investigate failure see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + GradientBoostingRegressor: { + # TODO: investigate failure see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + GridSearchCV: { + "check_supervised_y_2d": "DataConversionWarning not caught", + "check_requires_y_none": "Doesn't fail gracefully", + }, + HalvingGridSearchCV: { + "check_fit2d_1sample": ( + "Fail during parameter check since min/max resources requires" + " more samples" + ), + "check_estimators_nan_inf": "FIXME", + "check_classifiers_one_label_sample_weights": "FIXME", + "check_fit2d_1feature": "FIXME", + "check_supervised_y_2d": "DataConversionWarning not caught", + "check_requires_y_none": "Doesn't fail gracefully", + }, + HalvingRandomSearchCV: { + "check_fit2d_1sample": ( + "Fail during parameter check since min/max resources requires" + " more samples" + ), + "check_estimators_nan_inf": "FIXME", + "check_classifiers_one_label_sample_weights": "FIXME", + "check_fit2d_1feature": "FIXME", + "check_supervised_y_2d": "DataConversionWarning not caught", + "check_requires_y_none": "Doesn't fail gracefully", + }, + HistGradientBoostingClassifier: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + HistGradientBoostingRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + IsolationForest: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + KBinsDiscretizer: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + KernelDensity: { + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight must have positive values" + ), + }, + KMeans: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + KNeighborsTransformer: { + "check_methods_sample_order_invariance": "check is not applicable." + }, + LinearRegression: { + # TODO: investigate failure see meta-issue #16298 + # + # Note: this model should converge to the minimum norm solution of the + # least squares problem and as result be numerically stable enough when + # running the equivalence check even if n_features > n_samples. Maybe + # this is is not the case and a different choice of solver could fix + # this problem. + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + LinearSVC: { + # TODO: replace by a statistical test when _dual=True, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_non_transformer_estimators_n_iter": ( + "n_iter_ cannot be easily accessed." + ), + }, + LinearSVR: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + LogisticRegression: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + MiniBatchKMeans: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + NuSVC: { + "check_class_weight_classifiers": "class_weight is ignored.", + # TODO: fix sample_weight handling of this estimator when probability=False + # TODO: replace by a statistical test when probability=True + # see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_classifiers_one_label_sample_weights": ( + "specified nu is infeasible for the fit." + ), + }, + NuSVR: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + Nystroem: { + "check_transformer_preserves_dtypes": ( + "dtypes are preserved but not at a close enough precision" + ) + }, + OneClassSVM: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + Perceptron: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + Pipeline: { + "check_dont_overwrite_parameters": ( + "Pipeline changes the `steps` parameter, which it shouldn't." + "Therefore this test is x-fail until we fix this." + ), + "check_estimators_overwrite_params": ( + "Pipeline changes the `steps` parameter, which it shouldn't." + "Therefore this test is x-fail until we fix this." + ), + }, + RadiusNeighborsTransformer: { + "check_methods_sample_order_invariance": "check is not applicable." + }, + RandomForestClassifier: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + RandomForestRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + RandomizedSearchCV: { + "check_supervised_y_2d": "DataConversionWarning not caught", + "check_requires_y_none": "Doesn't fail gracefully", + }, + RandomTreesEmbedding: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + RANSACRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + Ridge: { + "check_non_transformer_estimators_n_iter": ( + "n_iter_ cannot be easily accessed." + ) + }, + RidgeClassifier: { + "check_non_transformer_estimators_n_iter": ( + "n_iter_ cannot be easily accessed." + ) + }, + RidgeCV: { + "check_sample_weight_equivalence_on_dense_data": ( + "GridSearchCV does not forward the weights to the scorer by default." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + SelfTrainingClassifier: { + "check_non_transformer_estimators_n_iter": "n_iter_ can be 0." + }, + SGDClassifier: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + SGDOneClassSVM: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + SGDRegressor: { + # TODO: replace by a statistical test, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + SpectralCoclustering: { + "check_estimators_dtypes": "raises nan error", + "check_fit2d_1sample": "_scale_normalize fails", + "check_fit2d_1feature": "raises apply_along_axis error", + "check_estimator_sparse_matrix": "does not fail gracefully", + "check_estimator_sparse_array": "does not fail gracefully", + "check_methods_subset_invariance": "empty array passed inside", + "check_dont_overwrite_parameters": "empty array passed inside", + "check_fit2d_predict1d": "empty array passed inside", + # ValueError: Found array with 0 feature(s) (shape=(23, 0)) + # while a minimum of 1 is required. + "check_dict_unchanged": "FIXME", + }, + SpectralBiclustering: { + "check_estimators_dtypes": "raises nan error", + "check_fit2d_1sample": "_scale_normalize fails", + "check_fit2d_1feature": "raises apply_along_axis error", + "check_estimator_sparse_matrix": "does not fail gracefully", + "check_estimator_sparse_array": "does not fail gracefully", + "check_methods_subset_invariance": "empty array passed inside", + "check_dont_overwrite_parameters": "empty array passed inside", + "check_fit2d_predict1d": "empty array passed inside", + }, + SplineTransformer: { + "check_estimators_pickle": ( + "Current Scipy implementation of _bsplines does not" + "support const memory views." + ), + }, + SVC: { + # TODO: fix sample_weight handling of this estimator when probability=False + # TODO: replace by a statistical test when probability=True + # see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + SVR: { + # TODO: fix sample_weight handling of this estimator, see meta-issue #16298 + "check_sample_weight_equivalence_on_dense_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + "check_sample_weight_equivalence_on_sparse_data": ( + "sample_weight is not equivalent to removing/repeating samples." + ), + }, + TunedThresholdClassifierCV: { + "check_classifiers_train": "Threshold at probability 0.5 does not hold", + "check_sample_weight_equivalence_on_dense_data": ( + "Due to the cross-validation and sample ordering, removing a sample" + " is not strictly equal to putting is weight to zero. Specific unit" + " tests are added for TunedThresholdClassifierCV specifically." + ), + }, +} + + +def _get_expected_failed_checks(estimator): + """Get the expected failed checks for all estimators in scikit-learn.""" + failed_checks = PER_ESTIMATOR_XFAIL_CHECKS.get(type(estimator), {}) + + tags = get_tags(estimator) + + # all xfail marks that depend on the instance, come here. As of now, we have only + # these two cases. + if type(estimator) in [KNeighborsClassifier, KNeighborsRegressor]: + if tags.input_tags.pairwise: + failed_checks.update( + { + "check_n_features_in_after_fitting": "FIXME", + "check_dataframe_column_names_consistency": "FIXME", + } + ) + + return failed_checks diff --git a/sklearn/utils/_testing.py b/sklearn/utils/_testing.py index 91efe88eeb354..ba8901e4b9050 100644 --- a/sklearn/utils/_testing.py +++ b/sklearn/utils/_testing.py @@ -687,17 +687,32 @@ def _get_diff_msg(docstrings_grouped): return msg_diff -def _check_consistency_items(items_docs, type_or_desc, section, n_objects): +def _check_consistency_items( + items_docs, type_or_desc, section, n_objects, descr_regex_pattern="" +): """Helper to check docstring consistency of all `items_docs`. If item is not present in all objects, checking is skipped and warning raised. + If `regex` provided, match descriptions to all descriptions. """ skipped = [] for item_name, docstrings_grouped in items_docs.items(): # If item not found in all objects, skip if sum([len(objs) for objs in docstrings_grouped.values()]) < n_objects: skipped.append(item_name) - # If more than one key, docstrings not consistent between objects + # If regex provided, match to all descriptions + elif type_or_desc == "description" and descr_regex_pattern: + not_matched = [] + for docstring, group in docstrings_grouped.items(): + if not re.search(descr_regex_pattern, docstring): + not_matched.extend(group) + if not_matched: + msg = textwrap.fill( + f"The description of {section[:-1]} '{item_name}' in {not_matched}" + f" does not match 'descr_regex_pattern': {descr_regex_pattern} " + ) + raise AssertionError(msg) + # Otherwise, if more than one key, docstrings not consistent between objects elif len(docstrings_grouped.keys()) > 1: msg_diff = _get_diff_msg(docstrings_grouped) obj_groups = " and ".join( @@ -724,8 +739,9 @@ def assert_docstring_consistency( exclude_attrs=None, include_returns=False, exclude_returns=None, + descr_regex_pattern=None, ): - """Check consistency between docstring parameters/attributes/returns of objects. + r"""Check consistency between docstring parameters/attributes/returns of objects. Checks if parameters/attributes/returns have the same type specification and description (ignoring whitespace) across `objects`. Intended to be used for @@ -767,18 +783,27 @@ def assert_docstring_consistency( List of returns to be excluded. If None, no returns are excluded. Can only be set if `include_returns` is True. + descr_regex_pattern : str, default=None + Regular expression to match to all descriptions of included + parameters/attributes/returns. If None, will revert to default behavior + of comparing descriptions between objects. + Examples -------- - >>> from sklearn.metrics import (mean_absolute_error, mean_squared_error, - ... median_absolute_error) - >>> from sklearn.utils.testing import assert_docstring_consistency + >>> from sklearn.metrics import (accuracy_score, classification_report, + ... mean_absolute_error, mean_squared_error, median_absolute_error) + >>> from sklearn.utils._testing import assert_docstring_consistency ... # doctest: +SKIP >>> assert_docstring_consistency([mean_absolute_error, mean_squared_error], ... include_params=['y_true', 'y_pred', 'sample_weight']) # doctest: +SKIP >>> assert_docstring_consistency([median_absolute_error, mean_squared_error], ... include_params=True) # doctest: +SKIP + >>> assert_docstring_consistency([accuracy_score, classification_report], + ... include_params=["y_true"], + ... descr_regex_pattern=r"Ground truth \(correct\) (labels|target values)") + ... # doctest: +SKIP """ - from numpydoc import docscrape + from numpydoc.docscrape import NumpyDocString Args = namedtuple("args", ["include", "exclude", "arg_name"]) @@ -805,7 +830,7 @@ def _create_args(include, exclude, arg_name, section_name): or inspect.isfunction(obj) or inspect.isclass(obj) ): - objects_doc[obj.__name__] = docscrape.NumpyDocString(inspect.getdoc(obj)) + objects_doc[obj.__name__] = NumpyDocString(inspect.getdoc(obj)) else: raise TypeError( "All 'objects' must be one of: function, class or descriptor, " @@ -827,7 +852,13 @@ def _create_args(include, exclude, arg_name, section_name): desc_items[item_name][desc].append(obj_name) _check_consistency_items(type_items, "type specification", section, n_objects) - _check_consistency_items(desc_items, "description", section, n_objects) + _check_consistency_items( + desc_items, + "description", + section, + n_objects, + descr_regex_pattern=descr_regex_pattern, + ) def assert_run_python_script_without_output(source_code, pattern=".+", timeout=60): diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index 54e291ee82460..0de7b21a468ff 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -2,6 +2,7 @@ # Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations import pickle import re @@ -12,6 +13,7 @@ from functools import partial, wraps from inspect import signature from numbers import Integral, Real +from typing import Callable, Literal import joblib import numpy as np @@ -47,7 +49,12 @@ make_multilabel_classification, make_regression, ) -from ..exceptions import DataConversionWarning, NotFittedError, SkipTestWarning +from ..exceptions import ( + DataConversionWarning, + EstimatorCheckFailedWarning, + NotFittedError, + SkipTestWarning, +) from ..linear_model._base import LinearClassifierMixin from ..metrics import accuracy_score, adjusted_rand_score, f1_score from ..metrics.pairwise import linear_kernel, pairwise_distances, rbf_kernel @@ -70,8 +77,15 @@ ) from . import shuffle from ._missing import is_scalar_nan -from ._param_validation import Interval -from ._tags import Tags, get_tags +from ._param_validation import Interval, StrOptions, validate_params +from ._tags import ( + ClassifierTags, + InputTags, + RegressorTags, + TargetTags, + TransformerTags, + get_tags, +) from ._test_common.instance_generator import ( CROSS_DECOMPOSITION, _get_check_estimator_ids, @@ -97,9 +111,31 @@ REGRESSION_DATASET = None +def _raise_for_missing_tags(estimator, tag_name, Mixin): + tags = get_tags(estimator) + estimator_type = Mixin.__name__.replace("Mixin", "") + if getattr(tags, tag_name) is None: + raise RuntimeError( + f"Estimator {estimator.__class__.__name__} seems to be a {estimator_type}," + f" but the `{tag_name}` tag is not set. Either set the tag manually" + f" or inherit from the {Mixin.__name__}. Note that the order of inheritance" + f" matters, the {Mixin.__name__} should come before BaseEstimator." + ) + + def _yield_api_checks(estimator): + if not isinstance(estimator, BaseEstimator): + warnings.warn( + f"Estimator {estimator.__class__.__name__} does not inherit from" + " `sklearn.base.BaseEstimator`. This might lead to unexpected behavior, or" + " even errors when collecting tests.", + category=UserWarning, + ) + tags = get_tags(estimator) yield check_estimator_cloneable + yield check_estimator_tags_renamed + yield check_valid_tag_types yield check_estimator_repr yield check_no_attributes_set_in_init yield check_fit_score_takes_y @@ -112,6 +148,7 @@ def _yield_api_checks(estimator): yield check_do_not_raise_errors_in_init_or_set_params yield check_n_features_in_after_fitting yield check_mixin_order + yield check_positive_only_tag_during_fit def _yield_checks(estimator): @@ -127,7 +164,11 @@ def _yield_checks(estimator): # We skip pairwise because the data is not pairwise yield check_sample_weights_shape yield check_sample_weights_not_overwritten - yield check_sample_weight_equivalence + yield check_sample_weight_equivalence_on_dense_data + # FIXME: filter on tags.input_tags.sparse + # (estimator accepts sparse arrays) + # once issue #30139 is fixed. + yield check_sample_weight_equivalence_on_sparse_data # Check that all estimator yield informative messages when # trained on empty datasets @@ -151,6 +192,7 @@ def _yield_checks(estimator): if hasattr(estimator, "sparsify"): yield check_sparsify_coefficients + yield check_estimator_sparse_tag yield check_estimator_sparse_array yield check_estimator_sparse_matrix @@ -159,9 +201,6 @@ def _yield_checks(estimator): yield check_estimators_pickle yield partial(check_estimators_pickle, readonly_memmap=True) - yield check_estimator_get_tags_default_keys - yield check_estimator_tags_renamed - if tags.array_api_support: for check in _yield_array_api_checks(estimator): yield check @@ -170,6 +209,7 @@ def _yield_checks(estimator): def _yield_classifier_checks(classifier): + _raise_for_missing_tags(classifier, "classifier_tags", ClassifierMixin) tags = get_tags(classifier) # test classifiers can handle non-array data and pandas objects @@ -215,42 +255,8 @@ def _yield_classifier_checks(classifier): yield check_classifier_not_supporting_multiclass -@ignore_warnings(category=FutureWarning) -def check_supervised_y_no_nan(name, estimator_orig): - # Checks that the Estimator targets are not NaN. - estimator = clone(estimator_orig) - rng = np.random.RandomState(888) - X = rng.standard_normal(size=(10, 5)) - - for value in [np.nan, np.inf]: - y = np.full(10, value) - y = _enforce_estimator_tags_y(estimator, y) - - module_name = estimator.__module__ - if module_name.startswith("sklearn.") and not ( - "test_" in module_name or module_name.endswith("_testing") - ): - # In scikit-learn we want the error message to mention the input - # name and be specific about the kind of unexpected value. - if np.isinf(value): - match = ( - r"Input (y|Y) contains infinity or a value too large for" - r" dtype\('float64'\)." - ) - else: - match = r"Input (y|Y) contains NaN." - else: - # Do not impose a particular error message to third-party libraries. - match = None - err_msg = ( - f"Estimator {name} should have raised error on fitting array y with inf" - " value." - ) - with raises(ValueError, match=match, err_msg=err_msg): - estimator.fit(X, y) - - def _yield_regressor_checks(regressor): + _raise_for_missing_tags(regressor, "regressor_tags", RegressorMixin) tags = get_tags(regressor) # TODO: test with intercept # TODO: test with multiple responses @@ -274,6 +280,7 @@ def _yield_regressor_checks(regressor): def _yield_transformer_checks(transformer): + _raise_for_missing_tags(transformer, "transformer_tags", TransformerMixin) tags = get_tags(transformer) # All transformers should either deal with sparse data or raise an # exception with type TypeError and an intelligible error message @@ -410,57 +417,148 @@ def _yield_all_checks(estimator, legacy: bool): yield check_fit_non_negative -def _maybe_mark_xfail(estimator, check, pytest): - # Mark (estimator, check) pairs as XFAIL if needed (see conditions in - # _should_be_skipped_or_marked()) - # This is similar to _maybe_skip(), but this one is used by - # @parametrize_with_checks() instead of check_estimator() +def _check_name(check): + if hasattr(check, "__wrapped__"): + return _check_name(check.__wrapped__) + return check.func.__name__ if isinstance(check, partial) else check.__name__ - should_be_marked, reason = _should_be_skipped_or_marked(estimator, check) - if not should_be_marked: + +def _maybe_mark( + estimator, + check, + expected_failed_checks: dict[str, str] | None = None, + mark: Literal["xfail", "skip", None] = None, + pytest=None, +): + """Mark the test as xfail or skip if needed. + + Parameters + ---------- + estimator : estimator object + Estimator instance for which to generate checks. + check : partial or callable + Check to be marked. + expected_failed_checks : dict[str, str], default=None + Dictionary of the form {check_name: reason} for checks that are expected to + fail. + mark : "xfail" or "skip" or None + Whether to mark the check as xfail or skip. + pytest : pytest module, default=None + Pytest module to use to mark the check. This is only needed if ``mark`` is + `"xfail"`. Note that one can run `check_estimator` without having `pytest` + installed. This is used in combination with `parametrize_with_checks` only. + """ + should_be_marked, reason = _should_be_skipped_or_marked( + estimator, check, expected_failed_checks + ) + if not should_be_marked or mark is None: return estimator, check - else: + + estimator_name = estimator.__class__.__name__ + if mark == "xfail": return pytest.param(estimator, check, marks=pytest.mark.xfail(reason=reason)) + else: + @wraps(check) + def wrapped(*args, **kwargs): + raise SkipTest( + f"Skipping {_check_name(check)} for {estimator_name}: {reason}" + ) -def _maybe_skip(estimator, check): - # Wrap a check so that it's skipped if needed (see conditions in - # _should_be_skipped_or_marked()) - # This is similar to _maybe_mark_xfail(), but this one is used by - # check_estimator() instead of @parametrize_with_checks which requires - # pytest - should_be_skipped, reason = _should_be_skipped_or_marked(estimator, check) - if not should_be_skipped: - return check + return estimator, wrapped - check_name = check.func.__name__ if isinstance(check, partial) else check.__name__ - @wraps(check) - def wrapped(*args, **kwargs): - raise SkipTest( - f"Skipping {check_name} for {estimator.__class__.__name__}: {reason}" - ) +def _should_be_skipped_or_marked( + estimator, check, expected_failed_checks: dict[str, str] | None = None +) -> tuple[bool, str]: + """Check whether a check should be skipped or marked as xfail. - return wrapped + Parameters + ---------- + estimator : estimator object + Estimator instance for which to generate checks. + check : partial or callable + Check to be marked. + expected_failed_checks : dict[str, str], default=None + Dictionary of the form {check_name: reason} for checks that are expected to + fail. + + Returns + ------- + should_be_marked : bool + Whether the check should be marked as xfail or skipped. + reason : str + Reason for skipping the check. + """ + + expected_failed_checks = expected_failed_checks or {} + check_name = _check_name(check) + if check_name in expected_failed_checks: + return True, expected_failed_checks[check_name] -def _should_be_skipped_or_marked(estimator, check): - # Return whether a check should be skipped (when using check_estimator()) - # or marked as XFAIL (when using @parametrize_with_checks()), along with a - # reason. - # Currently, a check should be skipped or marked if - # the check is in the _xfail_checks tag of the estimator + return False, "Check is not expected to fail" - check_name = check.func.__name__ if isinstance(check, partial) else check.__name__ - xfail_checks = get_tags(estimator)._xfail_checks or {} - if check_name in xfail_checks: - return True, xfail_checks[check_name] +def estimator_checks_generator( + estimator, + *, + legacy: bool = True, + expected_failed_checks: dict[str, str] | None = None, + mark: Literal["xfail", "skip", None] = None, +): + """Iteratively yield all check callables for an estimator. + + .. versionadded:: 1.6 + + Parameters + ---------- + estimator : estimator object + Estimator instance for which to generate checks. + legacy : bool, default=True + Whether to include legacy checks. Over time we remove checks from this category + and move them into their specific category. + expected_failed_checks : dict[str, str], default=None + Dictionary of the form {check_name: reason} for checks that are expected to + fail. + mark : {"xfail", "skip"} or None, default=None + Whether to mark the checks that are expected to fail as + xfail(`pytest.mark.xfail`) or skip. Marking a test as "skip" is done via + wrapping the check in a function that raises a + :class:`~sklearn.exceptions.SkipTest` exception. + + Returns + ------- + estimator_checks_generator : generator + Generator that yields (estimator, check) tuples. + """ + if mark == "xfail": + import pytest + else: + pytest = None # type: ignore - return False, "placeholder reason that will never be used" + name = type(estimator).__name__ + # First check that the estimator is cloneable which is needed for the rest + # of the checks to run + yield estimator, partial(check_estimator_cloneable, name) + for check in _yield_all_checks(estimator, legacy=legacy): + check_with_name = partial(check, name) + for check_instance in _yield_instances_for_check(check, estimator): + yield _maybe_mark( + check_instance, + check_with_name, + expected_failed_checks=expected_failed_checks, + mark=mark, + pytest=pytest, + ) -def parametrize_with_checks(estimators, *, legacy: bool = True): +def parametrize_with_checks( + estimators, + *, + legacy: bool = True, + expected_failed_checks: Callable | None = None, +): """Pytest specific decorator for parametrizing estimator checks. Checks are categorised into the following groups: @@ -492,6 +590,20 @@ def parametrize_with_checks(estimators, *, legacy: bool = True): Whether to include legacy checks. Over time we remove checks from this category and move them into their specific category. + .. versionadded:: 1.6 + + expected_failed_checks : callable, default=None + A callable that takes an estimator as input and returns a dictionary of the + form:: + + { + "check_name": "my reason", + } + + Where `"check_name"` is the name of the check, and `"my reason"` is why + the check fails. These tests will be marked as xfail if the check fails. + + .. versionadded:: 1.6 Returns @@ -524,23 +636,41 @@ def parametrize_with_checks(estimators, *, legacy: bool = True): ) raise TypeError(msg) - def checks_generator(): + def _checks_generator(estimators, legacy, expected_failed_checks): for estimator in estimators: - # First check that the estimator is cloneable which is needed for the rest - # of the checks to run - name = type(estimator).__name__ - yield estimator, partial(check_estimator_cloneable, name) - for check in _yield_all_checks(estimator, legacy=legacy): - check_with_name = partial(check, name) - for check_instance in _yield_instances_for_check(check, estimator): - yield _maybe_mark_xfail(check_instance, check_with_name, pytest) + args = {"estimator": estimator, "legacy": legacy, "mark": "xfail"} + if callable(expected_failed_checks): + args["expected_failed_checks"] = expected_failed_checks(estimator) + yield from estimator_checks_generator(**args) return pytest.mark.parametrize( - "estimator, check", checks_generator(), ids=_get_check_estimator_ids + "estimator, check", + _checks_generator(estimators, legacy, expected_failed_checks), + ids=_get_check_estimator_ids, ) -def check_estimator(estimator=None, generate_only=False, *, legacy: bool = True): +@validate_params( + { + "generate_only": ["boolean"], + "legacy": ["boolean"], + "expected_failed_checks": [dict, None], + "on_skip": [StrOptions({"warn"}), None], + "on_fail": [StrOptions({"raise", "warn"}), None], + "callback": [callable, None], + }, + prefer_skip_nested_validation=False, +) +def check_estimator( + estimator=None, + generate_only=False, + *, + legacy: bool = True, + expected_failed_checks: dict[str, str] | None = None, + on_skip: Literal["warn"] | None = "warn", + on_fail: Literal["raise", "warn"] | None = "raise", + callback: Callable | None = None, +): """Check if estimator adheres to scikit-learn conventions. This function will run an extensive test-suite for input validation, @@ -550,12 +680,7 @@ def check_estimator(estimator=None, generate_only=False, *, legacy: bool = True) will be run if the Estimator class inherits from the corresponding mixin from sklearn.base. - Setting `generate_only=True` returns a generator that yields (estimator, - check) tuples where the check can be called independently from each - other, i.e. `check(estimator)`. This allows all checks to be run - independently and report the checks that are failing. - - scikit-learn provides a pytest specific decorator, + scikit-learn also provides a pytest specific decorator, :func:`~sklearn.utils.estimator_checks.parametrize_with_checks`, making it easier to test multiple estimators. @@ -571,10 +696,6 @@ def check_estimator(estimator=None, generate_only=False, *, legacy: bool = True) estimator : estimator object Estimator instance to check. - .. versionadded:: 1.1 - Passing a class was deprecated in version 0.23, and support for - classes was removed in 0.24. - generate_only : bool, default=False When `False`, checks are evaluated when `check_estimator` is called. When `True`, `check_estimator` returns a generator that yields @@ -583,29 +704,119 @@ def check_estimator(estimator=None, generate_only=False, *, legacy: bool = True) .. versionadded:: 0.22 + .. deprecated:: 1.6 + `generate_only` will be removed in 1.8. Use + :func:`~sklearn.utils.estimator_checks.estimator_checks_generator` instead. + legacy : bool, default=True Whether to include legacy checks. Over time we remove checks from this category and move them into their specific category. .. versionadded:: 1.6 + expected_failed_checks : dict, default=None + A dictionary of the form:: + + { + "check_name": "this check is expected to fail because ...", + } + + Where `"check_name"` is the name of the check, and `"my reason"` is why + the check fails. + + .. versionadded:: 1.6 + + on_skip : "warn", None, default="warn" + This parameter controls what happens when a check is skipped. + + - "warn": A :class:`~sklearn.exceptions.SkipTestWarning` is logged + and running tests continue. + - None: No warning is logged and running tests continue. + + .. versionadded:: 1.6 + + on_fail : {"raise", "warn"}, None, default="raise" + This parameter controls what happens when a check fails. + + - "raise": The exception raised by the first failing check is raised and + running tests are aborted. This does not included tests that are expected + to fail. + - "warn": A :class:`~sklearn.exceptions.EstimatorCheckFailedWarning` is logged + and running tests continue. + - None: No exception is raised and no warning is logged. + + Note that if ``on_fail != "raise"``, no exception is raised, even if the checks + fail. You'd need to inspect the return result of ``check_estimator`` to check + if any checks failed. + + .. versionadded:: 1.6 + + callback : callable, or None, default=None + This callback will be called with the estimator and the check name, + the exception (if any), the status of the check (xfail, failed, skipped, + passed), and the reason for the expected failure if the check is + expected to fail. The callable's signature needs to be:: + + def callback( + estimator, + check_name: str, + exception: Exception, + status: Literal["xfail", "failed", "skipped", "passed"], + expected_to_fail: bool, + expected_to_fail_reason: str, + ) + + ``callback`` cannot be provided together with ``on_fail="raise"``. + + .. versionadded:: 1.6 + Returns ------- - checks_generator : generator + test_results : list + List of dictionaries with the results of the failing tests, of the form:: + + { + "estimator": estimator, + "check_name": check_name, + "exception": exception, + "status": status (one of "xfail", "failed", "skipped", "passed"), + "expected_to_fail": expected_to_fail, + "expected_to_fail_reason": expected_to_fail_reason, + } + + estimator_checks_generator : generator Generator that yields (estimator, check) tuples. Returned when `generate_only=True`. + .. + TODO(1.8): remove return value + + .. deprecated:: 1.6 + ``generate_only`` will be removed in 1.8. Use + :func:`~sklearn.utils.estimator_checks.estimator_checks_generator` instead. + + Raises + ------ + Exception + If ``on_fail="raise"``, the exception raised by the first failing check is + raised and running tests are aborted. + + Note that if ``on_fail != "raise"``, no exception is raised, even if the checks + fail. You'd need to inspect the return result of ``check_estimator`` to check + if any checks failed. + See Also -------- parametrize_with_checks : Pytest specific decorator for parametrizing estimator checks. + estimator_checks_generator : Generator that yields (estimator, check) tuples. Examples -------- >>> from sklearn.utils.estimator_checks import check_estimator >>> from sklearn.linear_model import LogisticRegression - >>> check_estimator(LogisticRegression(), generate_only=True) - + >>> check_estimator(LogisticRegression()) + [...] """ if isinstance(estimator, type): msg = ( @@ -615,27 +826,93 @@ def check_estimator(estimator=None, generate_only=False, *, legacy: bool = True) ) raise TypeError(msg) - name = type(estimator).__name__ + if on_fail == "raise" and callback is not None: + raise ValueError("callback cannot be provided together with on_fail='raise'") - def checks_generator(): - # we first need to check if the estimator is cloneable for the rest of the tests - # to run - yield estimator, partial(check_estimator_cloneable, name) - for check in _yield_all_checks(estimator, legacy=legacy): - for check_instance in _yield_instances_for_check(check, estimator): - maybe_skipped_check = _maybe_skip(check_instance, check) - yield check_instance, partial(maybe_skipped_check, name) + name = type(estimator).__name__ + # TODO(1.8): remove generate_only if generate_only: - return checks_generator() + warnings.warn( + "`generate_only` is deprecated in 1.6 and will be removed in 1.8. " + "Use :func:`~sklearn.utils.estimator_checks.estimator_checks` instead.", + FutureWarning, + ) + return estimator_checks_generator( + estimator, legacy=legacy, expected_failed_checks=None, mark="skip" + ) + + test_results = [] - for estimator, check in checks_generator(): + for estimator, check in estimator_checks_generator( + estimator, + legacy=legacy, + expected_failed_checks=expected_failed_checks, + # Not marking tests to be skipped here, we run and simulate an xfail behavior + mark=None, + ): + test_can_fail, reason = _should_be_skipped_or_marked( + estimator, check, expected_failed_checks + ) try: check(estimator) - except SkipTest as exception: - # SkipTest is thrown when pandas can't be imported, or by checks - # that are in the xfail_checks tag - warnings.warn(str(exception), SkipTestWarning) + except SkipTest as e: + # We get here if the test raises SkipTest, which is expected in cases where + # the check cannot run for instance if a required dependency is not + # installed. + check_result = { + "estimator": estimator, + "check_name": _check_name(check), + "exception": e, + "status": "skipped", + "expected_to_fail": test_can_fail, + "expected_to_fail_reason": reason, + } + if on_skip == "warn": + warnings.warn( + f"Skipping check {_check_name(check)} for {name} because it raised " + f"{type(e).__name__}: {e}", + SkipTestWarning, + ) + except Exception as e: + if on_fail == "raise" and not test_can_fail: + raise + + check_result = { + "estimator": estimator, + "check_name": _check_name(check), + "exception": e, + "expected_to_fail": test_can_fail, + "expected_to_fail_reason": reason, + } + + if test_can_fail: + # This check failed, but could be expected to fail, therefore we mark it + # as xfail. + check_result["status"] = "xfail" + else: + failed = True + check_result["status"] = "failed" + + if on_fail == "warn": + warning = EstimatorCheckFailedWarning(**check_result) + warnings.warn(warning) + else: + check_result = { + "estimator": estimator, + "check_name": _check_name(check), + "exception": None, + "status": "passed", + "expected_to_fail": test_can_fail, + "expected_to_fail_reason": reason, + } + + test_results.append(check_result) + + if callback: + callback(**check_result) + + return test_results def _regression_dataset(): @@ -726,6 +1003,41 @@ def _generate_sparse_data(X_csr): yield sparse_format + "_64", X +@ignore_warnings(category=FutureWarning) +def check_supervised_y_no_nan(name, estimator_orig): + # Checks that the Estimator targets are not NaN. + estimator = clone(estimator_orig) + rng = np.random.RandomState(888) + X = rng.standard_normal(size=(10, 5)) + + for value in [np.nan, np.inf]: + y = np.full(10, value) + y = _enforce_estimator_tags_y(estimator, y) + + module_name = estimator.__module__ + if module_name.startswith("sklearn.") and not ( + "test_" in module_name or module_name.endswith("_testing") + ): + # In scikit-learn we want the error message to mention the input + # name and be specific about the kind of unexpected value. + if np.isinf(value): + match = ( + r"Input (y|Y) contains infinity or a value too large for" + r" dtype\('float64'\)." + ) + else: + match = r"Input (y|Y) contains NaN." + else: + # Do not impose a particular error message to third-party libraries. + match = None + err_msg = ( + f"Estimator {name} should have raised error on fitting array y with inf" + " value." + ) + with raises(ValueError, match=match, err_msg=err_msg): + estimator.fit(X, y) + + def check_array_api_input( name, estimator_orig, @@ -802,6 +1114,40 @@ def check_array_api_input( "transform", ) + try: + np.asarray(X_xp) + np.asarray(y_xp) + # TODO There are a few errors in SearchCV with array-api-strict because + # we end up doing X[train_indices] where X is an array-api-strict array + # and train_indices is a numpy array. array-api-strict insists + # train_indices should be an array-api-strict array. On the other hand, + # all the array API libraries (PyTorch, jax, CuPy) accept indexing with a + # numpy array. This is probably not worth doing anything about for + # now since array-api-strict seems a bit too strict ... + numpy_asarray_works = xp.__name__ != "array_api_strict" + + except TypeError: + # PyTorch with CUDA device and CuPy raise TypeError consistently. + # Exception type may need to be updated in the future for other + # libraries. + numpy_asarray_works = False + + if numpy_asarray_works: + # In this case, array_api_dispatch is disabled and we rely on np.asarray + # being called to convert the non-NumPy inputs to NumPy arrays when needed. + est_fitted_with_as_array = clone(est).fit(X_xp, y_xp) + # We only do a smoke test for now, in order to avoid complicating the + # test function even further. + for method_name in methods: + method = getattr(est_fitted_with_as_array, method_name, None) + if method is None: + continue + + if method_name == "score": + method(X_xp, y_xp) + else: + method(X_xp) + for method_name in methods: method = getattr(est, method_name, None) if method is None: @@ -886,6 +1232,62 @@ def check_array_api_input_and_values( ) +def check_estimator_sparse_tag(name, estimator_orig): + """Check that estimator tag related with accepting sparse data is properly set.""" + if SPARSE_ARRAY_PRESENT: + sparse_container = sparse.csr_array + else: + sparse_container = sparse.csr_matrix + estimator = clone(estimator_orig) + + rng = np.random.RandomState(0) + n_samples = 15 if name == "SpectralCoclustering" else 40 + X = rng.uniform(size=(n_samples, 3)) + X[X < 0.6] = 0 + y = rng.randint(0, 3, size=n_samples) + X = _enforce_estimator_tags_X(estimator, X) + y = _enforce_estimator_tags_y(estimator, y) + X = sparse_container(X) + + tags = get_tags(estimator) + if tags.input_tags.sparse: + try: + estimator.fit(X, y) # should pass + except Exception as e: + err_msg = ( + f"Estimator {name} raised an exception. " + f"The tag self.input_tags.sparse={tags.input_tags.sparse} " + "might not be consistent with the estimator's ability to " + "handle sparse data (i.e. controlled by the parameter `accept_sparse`" + " in `validate_data` or `check_array` functions)." + ) + raise AssertionError(err_msg) from e + else: + err_msg = ( + f"Estimator {name} raised an exception. " + "The estimator failed when fitted on sparse data in accordance " + f"with its tag self.input_tags.sparse={tags.input_tags.sparse} " + "but didn't raise the appropriate error: error message should " + "state explicitly that sparse input is not supported if this is " + "not the case, e.g. by using check_array(X, accept_sparse=False)." + ) + try: + estimator.fit(X, y) # should fail with appropriate error + except (ValueError, TypeError) as e: + if re.search("[Ss]parse", str(e)): + # Got the right error type and mentioning sparse issue + return + raise AssertionError(err_msg) from e + except Exception as e: + raise AssertionError(err_msg) from e + raise AssertionError( + f"Estimator {name} didn't fail when fitted on sparse data " + "but should have according to its tag " + f"self.input_tags.sparse={tags.input_tags.sparse}. " + f"The tag is inconsistent and must be fixed." + ) + + def _check_estimator_sparse_container(name, estimator_orig, sparse_type): rng = np.random.RandomState(0) X = rng.uniform(size=(40, 3)) @@ -1101,7 +1503,7 @@ def check_sample_weights_shape(name, estimator_orig): @ignore_warnings(category=FutureWarning) -def check_sample_weight_equivalence(name, estimator_orig): +def _check_sample_weight_equivalence(name, estimator_orig, sparse_container): # check that setting sample_weight to zero / integer is equivalent # to removing / repeating corresponding samples. estimator_weighted = clone(estimator_orig) @@ -1116,13 +1518,13 @@ def check_sample_weight_equivalence(name, estimator_orig): # Use random integers (including zero) as weights. sw = rng.randint(0, 5, size=n_samples) - X_weigthed = X + X_weighted = X y_weighted = y # repeat samples according to weights - X_repeated = X_weigthed.repeat(repeats=sw, axis=0) + X_repeated = X_weighted.repeat(repeats=sw, axis=0) y_repeated = y_weighted.repeat(repeats=sw) - X_weigthed, y_weighted, sw = shuffle(X_weigthed, y_weighted, sw, random_state=0) + X_weighted, y_weighted, sw = shuffle(X_weighted, y_weighted, sw, random_state=0) # when the estimator has an internal CV scheme # we only use weights / repetitions in a specific CV group (here group=0) @@ -1131,10 +1533,10 @@ def check_sample_weight_equivalence(name, estimator_orig): [np.full_like(y_weighted, 0), np.full_like(y, 1), np.full_like(y, 2)] ) sw = np.hstack([sw, np.ones_like(y), np.ones_like(y)]) - X_weigthed = np.vstack([X_weigthed, X, X]) + X_weighted = np.vstack([X_weighted, X, X]) y_weighted = np.hstack([y_weighted, y, y]) splits_weighted = list( - LeaveOneGroupOut().split(X_weigthed, groups=groups_weighted) + LeaveOneGroupOut().split(X_weighted, groups=groups_weighted) ) estimator_weighted.set_params(cv=splits_weighted) @@ -1151,8 +1553,13 @@ def check_sample_weight_equivalence(name, estimator_orig): y_weighted = _enforce_estimator_tags_y(estimator_weighted, y_weighted) y_repeated = _enforce_estimator_tags_y(estimator_repeated, y_repeated) + # convert to sparse X if needed + if sparse_container is not None: + X_weighted = sparse_container(X_weighted) + X_repeated = sparse_container(X_repeated) + estimator_repeated.fit(X_repeated, y=y_repeated, sample_weight=None) - estimator_weighted.fit(X_weigthed, y=y_weighted, sample_weight=sw) + estimator_weighted.fit(X_weighted, y=y_weighted, sample_weight=sw) for method in ["predict_proba", "decision_function", "predict", "transform"]: if hasattr(estimator_orig, method): @@ -1166,6 +1573,22 @@ def check_sample_weight_equivalence(name, estimator_orig): assert_allclose_dense_sparse(X_pred1, X_pred2, err_msg=err_msg) +def check_sample_weight_equivalence_on_dense_data(name, estimator_orig): + _check_sample_weight_equivalence(name, estimator_orig, sparse_container=None) + + +def check_sample_weight_equivalence_on_sparse_data(name, estimator_orig): + if SPARSE_ARRAY_PRESENT: + sparse_container = sparse.csr_array + else: + sparse_container = sparse.csr_matrix + # FIXME: remove the catch once issue #30139 is fixed. + try: + _check_sample_weight_equivalence(name, estimator_orig, sparse_container) + except TypeError: + return + + def check_sample_weights_not_overwritten(name, estimator_orig): # check that estimators don't override the passed sample_weight parameter estimator = clone(estimator_orig) @@ -2132,11 +2555,11 @@ def check_regressor_multioutput(name, estimator): assert y_pred.dtype == np.dtype("float64"), ( "Multioutput predictions by a regressor are expected to be" - " floating-point precision. Got {} instead".format(y_pred.dtype) + f" floating-point precision. Got {y_pred.dtype} instead" ) assert y_pred.shape == y.shape, ( "The shape of the prediction for multioutput data is incorrect." - " Expected {}, got {}." + f" Expected {y_pred.shape}, got {y.shape}." ) @@ -3568,6 +3991,39 @@ def _enforce_estimator_tags_X(estimator, X, X_test=None, kernel=linear_kernel): return X_res +@ignore_warnings(category=FutureWarning) +def check_positive_only_tag_during_fit(name, estimator_orig): + """Test that the estimator correctly sets the tags.input_tags.positive_only + + If the tag is False, the estimator should accept negative input regardless of the + tags.input_tags.pairwise flag. + """ + estimator = clone(estimator_orig) + tags = get_tags(estimator) + + X, y = load_iris(return_X_y=True) + y = _enforce_estimator_tags_y(estimator, y) + set_random_state(estimator, 0) + X = _enforce_estimator_tags_X(estimator, X) + X -= X.mean() + + if tags.input_tags.positive_only: + with raises(ValueError, match="Negative values in data"): + estimator.fit(X, y) + else: + # This should pass + try: + estimator.fit(X, y) + except Exception as e: + err_msg = ( + f"Estimator {repr(name)} raised {e.__class__.__name__} unexpectedly." + " This happens when passing negative input values as X." + " If negative values are not supported for this estimator instance," + " then the tags.input_tags.positive_only tag needs to be set to True." + ) + raise AssertionError(err_msg) from e + + @ignore_warnings(category=FutureWarning) def check_non_transformer_estimators_n_iter(name, estimator_orig): # Test that estimators that are not transformers with a parameter @@ -4059,15 +4515,57 @@ def {method}(self, X): estimator.partial_fit(X_bad, y) -def check_estimator_get_tags_default_keys(name, estimator_orig): - # check that if __sklearn_tags__ is implemented, it's an instance of Tags - estimator = clone(estimator_orig) - if not hasattr(estimator, "__sklearn_tags__"): - return - - assert isinstance( - estimator.__sklearn_tags__(), Tags - ), f"{name}.__sklearn_tags__() must be an instance of Tags" +def check_valid_tag_types(name, estimator): + """Check that estimator tags are valid.""" + assert hasattr(estimator, "__sklearn_tags__"), ( + f"Estimator {name} does not have `__sklearn_tags__` method. This method is" + " implemented in BaseEstimator and returns a sklearn.utils.Tags instance." + ) + err_msg = ( + "Tag values need to be of a certain type. " + "Please refer to the documentation of `sklearn.utils.Tags` for more details." + ) + tags = get_tags(estimator) + assert isinstance(tags.estimator_type, (str, type(None))), err_msg + assert isinstance(tags.target_tags, TargetTags), err_msg + assert isinstance(tags.classifier_tags, (ClassifierTags, type(None))), err_msg + assert isinstance(tags.regressor_tags, (RegressorTags, type(None))), err_msg + assert isinstance(tags.transformer_tags, (TransformerTags, type(None))), err_msg + assert isinstance(tags.input_tags, InputTags), err_msg + assert isinstance(tags.array_api_support, bool), err_msg + assert isinstance(tags.no_validation, bool), err_msg + assert isinstance(tags.non_deterministic, bool), err_msg + assert isinstance(tags.requires_fit, bool), err_msg + assert isinstance(tags._skip_test, bool), err_msg + + assert isinstance(tags.target_tags.required, bool), err_msg + assert isinstance(tags.target_tags.one_d_labels, bool), err_msg + assert isinstance(tags.target_tags.two_d_labels, bool), err_msg + assert isinstance(tags.target_tags.positive_only, bool), err_msg + assert isinstance(tags.target_tags.multi_output, bool), err_msg + assert isinstance(tags.target_tags.single_output, bool), err_msg + + assert isinstance(tags.input_tags.pairwise, bool), err_msg + assert isinstance(tags.input_tags.allow_nan, bool), err_msg + assert isinstance(tags.input_tags.sparse, bool), err_msg + assert isinstance(tags.input_tags.categorical, bool), err_msg + assert isinstance(tags.input_tags.string, bool), err_msg + assert isinstance(tags.input_tags.dict, bool), err_msg + assert isinstance(tags.input_tags.one_d_array, bool), err_msg + assert isinstance(tags.input_tags.two_d_array, bool), err_msg + assert isinstance(tags.input_tags.three_d_array, bool), err_msg + assert isinstance(tags.input_tags.positive_only, bool), err_msg + + if tags.classifier_tags is not None: + assert isinstance(tags.classifier_tags.poor_score, bool), err_msg + assert isinstance(tags.classifier_tags.multi_class, bool), err_msg + assert isinstance(tags.classifier_tags.multi_label, bool), err_msg + + if tags.regressor_tags is not None: + assert isinstance(tags.regressor_tags.poor_score, bool), err_msg + + if tags.transformer_tags is not None: + assert isinstance(tags.transformer_tags.preserves_dtype, list), err_msg def check_estimator_tags_renamed(name, estimator_orig): @@ -4076,13 +4574,20 @@ def check_estimator_tags_renamed(name, estimator_orig): scikit-learn versions. """ - if not hasattr(estimator_orig, "__sklearn_tags__"): - assert not hasattr(estimator_orig, "_more_tags"), help.format( - tags_func="_more_tags" - ) - assert not hasattr(estimator_orig, "_get_tags"), help.format( - tags_func="_get_tags" - ) + for klass in type(estimator_orig).mro(): + if ( + # Here we check vars(...) because we want to check if the method is + # explicitly defined in the class instead of inherited from a parent class. + ("_more_tags" in vars(klass) or "_get_tags" in vars(klass)) + and "__sklearn_tags__" not in vars(klass) + ): + raise TypeError( + f"Estimator {name} has defined either `_more_tags` or `_get_tags`," + " but not `__sklearn_tags__`. If you're customizing tags, and need to" + " support multiple scikit-learn versions, you can implement both" + " `__sklearn_tags__` and `_more_tags` or `_get_tags`. This change was" + " introduced in scikit-learn=1.6" + ) def check_dataframe_column_names_consistency(name, estimator_orig): diff --git a/sklearn/utils/extmath.py b/sklearn/utils/extmath.py index 2c8fa9f0cd105..b4af090344d74 100644 --- a/sklearn/utils/extmath.py +++ b/sklearn/utils/extmath.py @@ -11,7 +11,7 @@ from scipy import linalg, sparse from ..utils._param_validation import Interval, StrOptions, validate_params -from ._array_api import _is_numpy_namespace, device, get_namespace +from ._array_api import _average, _is_numpy_namespace, _nanmean, device, get_namespace from .sparsefuncs_fast import csr_row_norms from .validation import check_array, check_random_state @@ -1228,24 +1228,24 @@ def _nanaverage(a, weights=None): that :func:`np.nan` values are ignored from the average and weights can be passed. Note that when possible, we delegate to the prime methods. """ + xp, _ = get_namespace(a) + if a.shape[0] == 0: + return xp.nan - if len(a) == 0: - return np.nan - - mask = np.isnan(a) - if mask.all(): - return np.nan + mask = xp.isnan(a) + if xp.all(mask): + return xp.nan if weights is None: - return np.nanmean(a) + return _nanmean(a, xp=xp) - weights = np.asarray(weights) + weights = xp.asarray(weights) a, weights = a[~mask], weights[~mask] try: - return np.average(a, weights=weights) + return _average(a, weights=weights) except ZeroDivisionError: # this is when all weights are zero, then ignore them - return np.average(a) + return _average(a) def safe_sqr(X, *, copy=True): diff --git a/sklearn/utils/tests/test_array_api.py b/sklearn/utils/tests/test_array_api.py index 9c61bf0322536..d76ef4838e37e 100644 --- a/sklearn/utils/tests/test_array_api.py +++ b/sklearn/utils/tests/test_array_api.py @@ -19,6 +19,7 @@ _isin, _max_precision_float_dtype, _nanmax, + _nanmean, _nanmin, _NumPyAPIWrapper, _ravel, @@ -247,6 +248,7 @@ def test_device_none_if_no_input(): assert device(None, "name") is None +@skip_if_array_api_compat_not_configured def test_device_inspection(): class Device: def __init__(self, name): @@ -272,18 +274,26 @@ def __init__(self, device_name): with pytest.raises(TypeError): hash(Array("device").device) - # Test raise if on different devices + # If array API dispatch is disabled the device should be ignored. Erroring + # early for different devices would prevent the np.asarray conversion to + # happen. For example, `r2_score(np.ones(5), torch.ones(5))` should work + # fine with array API disabled. + assert device(Array("cpu"), Array("mygpu")) is None + + # Test that ValueError is raised if on different devices and array API dispatch is + # enabled. err_msg = "Input arrays use different devices: cpu, mygpu" - with pytest.raises(ValueError, match=err_msg): - device(Array("cpu"), Array("mygpu")) + with config_context(array_api_dispatch=True): + with pytest.raises(ValueError, match=err_msg): + device(Array("cpu"), Array("mygpu")) - # Test expected value is returned otherwise - array1 = Array("device") - array2 = Array("device") + # Test expected value is returned otherwise + array1 = Array("device") + array2 = Array("device") - assert array1.device == device(array1) - assert array1.device == device(array1, array2) - assert array1.device == device(array1, array1, array2) + assert array1.device == device(array1) + assert array1.device == device(array1, array2) + assert array1.device == device(array1, array1, array2) # TODO: add cupy to the list of libraries once the the following upstream issue @@ -320,6 +330,19 @@ def __init__(self, device_name): partial(_nanmax, axis=1), [3.0, numpy.nan, 6.0], ), + ([1, 2, numpy.nan], _nanmean, 1.5), + ([1, -2, -numpy.nan], _nanmean, -0.5), + ([-numpy.inf, -numpy.inf], _nanmean, -numpy.inf), + ( + [[1, 2, 3], [numpy.nan, numpy.nan, numpy.nan], [4, 5, 6.0]], + partial(_nanmean, axis=0), + [2.5, 3.5, 4.5], + ), + ( + [[1, 2, 3], [numpy.nan, numpy.nan, numpy.nan], [4, 5, 6.0]], + partial(_nanmean, axis=1), + [2.0, numpy.nan, 5.0], + ), ], ) def test_nan_reductions(library, X, reduction, expected): @@ -539,7 +562,7 @@ def test_get_namespace_and_device(): namespace, is_array_api, device = get_namespace_and_device(some_torch_tensor) assert namespace is get_namespace(some_numpy_array)[0] assert not is_array_api - assert device.type == "cpu" + assert device is None # Otherwise, expose the torch namespace and device via array API compat # wrapper. @@ -576,7 +599,7 @@ def test_count_nonzero( with config_context(array_api_dispatch=True): result = _count_nonzero( - array_xp, xp=xp, device=device_, axis=axis, sample_weight=sample_weight + array_xp, axis=axis, sample_weight=sample_weight, xp=xp, device=device_ ) assert_allclose(_convert_to_numpy(result, xp=xp), expected) @@ -607,8 +630,8 @@ def test_sparse_device(csr_container, dispatch): try: with config_context(array_api_dispatch=dispatch): assert device(a, b) is None - assert device(a, numpy.array([1])) == "cpu" + assert device(a, numpy.array([1])) is None assert get_namespace_and_device(a, b)[2] is None - assert get_namespace_and_device(a, numpy.array([1]))[2] == "cpu" + assert get_namespace_and_device(a, numpy.array([1]))[2] is None except ImportError: raise SkipTest("array_api_compat is not installed") diff --git a/sklearn/utils/tests/test_estimator_checks.py b/sklearn/utils/tests/test_estimator_checks.py index ff0c1d0e6d07f..b805bc1209f0c 100644 --- a/sklearn/utils/tests/test_estimator_checks.py +++ b/sklearn/utils/tests/test_estimator_checks.py @@ -7,6 +7,7 @@ import sys import unittest import warnings +from inspect import isgenerator from numbers import Integral, Real import joblib @@ -21,7 +22,11 @@ make_multilabel_classification, ) from sklearn.decomposition import PCA -from sklearn.exceptions import ConvergenceWarning, SkipTestWarning +from sklearn.exceptions import ( + ConvergenceWarning, + EstimatorCheckFailedWarning, + SkipTestWarning, +) from sklearn.linear_model import ( LinearRegression, LogisticRegression, @@ -34,6 +39,10 @@ from sklearn.svm import SVC, NuSVC from sklearn.utils import _array_api, all_estimators, deprecated from sklearn.utils._param_validation import Interval, StrOptions +from sklearn.utils._test_common.instance_generator import ( + _construct_instances, + _get_expected_failed_checks, +) from sklearn.utils._testing import ( MinimalClassifier, MinimalRegressor, @@ -43,6 +52,7 @@ raises, ) from sklearn.utils.estimator_checks import ( + _check_name, _NotAnArray, _yield_all_checks, check_array_api_input, @@ -62,6 +72,7 @@ check_estimator_repr, check_estimator_sparse_array, check_estimator_sparse_matrix, + check_estimator_sparse_tag, check_estimator_tags_renamed, check_estimators_nan_inf, check_estimators_overwrite_params, @@ -75,10 +86,12 @@ check_outlier_contamination, check_outlier_corruption, check_parameters_default_constructible, + check_positive_only_tag_during_fit, check_regressor_data_not_an_array, check_requires_y_none, check_sample_weights_pandas_series, check_set_params, + estimator_checks_generator, set_random_state, ) from sklearn.utils.fixes import CSR_CONTAINERS, SPARRAY_PRESENT @@ -496,20 +509,23 @@ def __sklearn_tags__(self): class RequiresPositiveXRegressor(LinearRegression): def fit(self, X, y): - X, y = validate_data(self, X, y, multi_output=True) + # reject sparse X to be able to call (X < 0).any() + X, y = validate_data(self, X, y, accept_sparse=False, multi_output=True) if (X < 0).any(): - raise ValueError("negative X values not supported!") + raise ValueError("Negative values in data passed to X.") return super().fit(X, y) def __sklearn_tags__(self): tags = super().__sklearn_tags__() tags.input_tags.positive_only = True + # reject sparse X to be able to call (X < 0).any() + tags.input_tags.sparse = False return tags class RequiresPositiveYRegressor(LinearRegression): def fit(self, X, y): - X, y = validate_data(self, X, y, multi_output=True) + X, y = validate_data(self, X, y, accept_sparse=True, multi_output=True) if (y <= 0).any(): raise ValueError("negative y values not supported!") return super().fit(X, y) @@ -760,6 +776,33 @@ def test_check_classifiers_one_label_sample_weights(): ) +def test_check_estimator_not_fail_fast(): + """Check the contents of the results returned with on_fail!="raise". + + This results should contain details about the observed failures, expected + or not. + """ + check_results = check_estimator(BaseEstimator(), on_fail=None) + assert isinstance(check_results, list) + assert len(check_results) > 0 + assert all( + isinstance(item, dict) + and set(item.keys()) + == { + "estimator", + "check_name", + "exception", + "status", + "expected_to_fail", + "expected_to_fail_reason", + } + for item in check_results + ) + # Some tests are expected to fail, some are expected to pass. + assert any(item["status"] == "failed" for item in check_results) + assert any(item["status"] == "passed" for item in check_results) + + def test_check_estimator(): # tests that the estimator actually fails on "bad" estimators. # not a complete test of all checks, which are very extensive. @@ -806,9 +849,57 @@ def test_check_outlier_corruption(): check_outlier_corruption(1, 2, decision) +def test_check_estimator_sparse_tag(): + """Test that check_estimator_sparse_tag raises error when sparse tag is + misaligned.""" + + class EstimatorWithSparseConfig(BaseEstimator): + def __init__(self, tag_sparse, accept_sparse, fit_error=None): + self.tag_sparse = tag_sparse + self.accept_sparse = accept_sparse + self.fit_error = fit_error + + def fit(self, X, y=None): + if self.fit_error: + raise self.fit_error + validate_data(self, X, y, accept_sparse=self.accept_sparse) + return self + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.sparse = self.tag_sparse + return tags + + test_cases = [ + {"tag_sparse": True, "accept_sparse": True, "error_type": None}, + {"tag_sparse": False, "accept_sparse": False, "error_type": None}, + {"tag_sparse": False, "accept_sparse": True, "error_type": AssertionError}, + {"tag_sparse": True, "accept_sparse": False, "error_type": AssertionError}, + ] + + for test_case in test_cases: + estimator = EstimatorWithSparseConfig( + test_case["tag_sparse"], + test_case["accept_sparse"], + ) + if test_case["error_type"] is None: + check_estimator_sparse_tag(estimator.__class__.__name__, estimator) + else: + with raises(test_case["error_type"]): + check_estimator_sparse_tag(estimator.__class__.__name__, estimator) + + # estimator `tag_sparse=accept_sparse=False` fails on sparse data + # but does not raise the appropriate error + for fit_error in [TypeError("unexpected error"), KeyError("other error")]: + estimator = EstimatorWithSparseConfig(False, False, fit_error) + with raises(AssertionError): + check_estimator_sparse_tag(estimator.__class__.__name__, estimator) + + def test_check_estimator_transformer_no_mixin(): # check that TransformerMixin is not required for transformer tests to run - with raises(AttributeError, ".*fit_transform.*"): + # but it fails since the tag is not set + with raises(RuntimeError, "the `transformer_tags` tag is not set"): check_estimator(BadTransformerWithoutMixin()) @@ -829,7 +920,9 @@ def test_check_estimator_clones(): est = Estimator() set_random_state(est) old_hash = joblib.hash(est) - check_estimator(est) + check_estimator( + est, expected_failed_checks=_get_expected_failed_checks(est) + ) assert old_hash == joblib.hash(est) # with fitting @@ -838,7 +931,9 @@ def test_check_estimator_clones(): set_random_state(est) est.fit(iris.data, iris.target) old_hash = joblib.hash(est) - check_estimator(est) + check_estimator( + est, expected_failed_checks=_get_expected_failed_checks(est) + ) assert old_hash == joblib.hash(est) @@ -910,7 +1005,7 @@ def test_check_estimator_pairwise(): # test precomputed metric est = KNeighborsRegressor(metric="precomputed") - check_estimator(est) + check_estimator(est, expected_failed_checks=_get_expected_failed_checks(est)) def test_check_classifier_data_not_an_array(): @@ -1217,12 +1312,85 @@ def test_all_estimators_all_public(): run_tests_without_pytest() -def test_xfail_ignored_in_check_estimator(): - # Make sure checks marked as xfail are just ignored and not run by - # check_estimator(), but still raise a warning. +def test_estimator_checks_generator_skipping_tests(): + # Make sure the checks generator skips tests that are expected to fail + est = next(_construct_instances(NuSVC)) + expected_to_fail = _get_expected_failed_checks(est) + checks = estimator_checks_generator( + est, legacy=True, expected_failed_checks=expected_to_fail, mark="skip" + ) + # making sure we use a class that has expected failures + assert len(expected_to_fail) > 0 + skipped_checks = [] + for estimator, check in checks: + try: + check(estimator) + except SkipTest: + skipped_checks.append(_check_name(check)) + # all checks expected to fail are skipped + # some others might also be skipped, if their dependencies are not installed. + assert set(expected_to_fail.keys()) <= set(skipped_checks) + + +def test_xfail_count_with_no_fast_fail(): + """Test that the right number of xfail warnings are raised when on_fail is "warn". + + It also checks the number of raised EstimatorCheckFailedWarning, and checks the + output of check_estimator. + """ + est = NuSVC() + expected_failed_checks = _get_expected_failed_checks(est) + # This is to make sure we test a class that has some expected failures + assert len(expected_failed_checks) > 0 with warnings.catch_warnings(record=True) as records: - check_estimator(NuSVC()) - assert SkipTestWarning in [rec.category for rec in records] + logs = check_estimator( + est, + expected_failed_checks=expected_failed_checks, + on_fail="warn", + ) + xfail_warns = [w for w in records if w.category != SkipTestWarning] + assert all([rec.category == EstimatorCheckFailedWarning for rec in xfail_warns]) + assert len(xfail_warns) == len(expected_failed_checks) + + xfailed = [log for log in logs if log["status"] == "xfail"] + assert len(xfailed) == len(expected_failed_checks) + + +def test_check_estimator_callback(): + """Test that the callback is called with the right arguments.""" + call_count = {"xfail": 0, "skipped": 0, "passed": 0, "failed": 0} + + def callback( + *, + estimator, + check_name, + exception, + status, + expected_to_fail, + expected_to_fail_reason, + ): + assert status in ("xfail", "skipped", "passed", "failed") + nonlocal call_count + call_count[status] += 1 + + est = NuSVC() + expected_failed_checks = _get_expected_failed_checks(est) + # This is to make sure we test a class that has some expected failures + assert len(expected_failed_checks) > 0 + with warnings.catch_warnings(record=True) as records: + logs = check_estimator( + est, + expected_failed_checks=expected_failed_checks, + on_fail=None, + callback=callback, + ) + all_checks_count = len(list(estimator_checks_generator(est, legacy=True))) + assert call_count["xfail"] == len(expected_failed_checks) + assert call_count["passed"] > 0 + assert call_count["failed"] == 0 + assert call_count["skipped"] == ( + all_checks_count - call_count["xfail"] - call_count["passed"] + ) # FIXME: this test should be uncommented when the checks will be granular @@ -1420,10 +1588,10 @@ def __sklearn_tags__(self): def _more_tags(self): return None # pragma: no cover - msg = "was removed in 1.6. Please use __sklearn_tags__ instead." - with raises(AssertionError, match=msg): + msg = "has defined either `_more_tags` or `_get_tags`" + with raises(TypeError, match=msg): check_estimator_tags_renamed("BadEstimator1", BadEstimator1()) - with raises(AssertionError, match=msg): + with raises(TypeError, match=msg): check_estimator_tags_renamed("BadEstimator2", BadEstimator2()) # This shouldn't fail since we allow both __sklearn_tags__ and _more_tags @@ -1460,6 +1628,20 @@ def test_estimator_with_set_output(): check_estimator(estimator) +def test_estimator_checks_generator(): + """Check that checks_generator returns a generator.""" + all_instance_gen_checks = estimator_checks_generator(LogisticRegression()) + assert isgenerator(all_instance_gen_checks) + + +def test_check_estimator_callback_with_fast_fail_error(): + """Check that check_estimator fails correctly with on_fail='raise' and callback.""" + with raises( + ValueError, match="callback cannot be provided together with on_fail='raise'" + ): + check_estimator(LogisticRegression(), on_fail="raise", callback=lambda: None) + + def test_check_mixin_order(): """Test that the check raises an error when the mixin order is incorrect.""" @@ -1470,3 +1652,18 @@ def fit(self, X, y=None): msg = "TransformerMixin comes before/left side of BaseEstimator" with raises(AssertionError, match=re.escape(msg)): check_mixin_order("BadEstimator", BadEstimator()) + + +def test_check_positive_only_tag_during_fit(): + class RequiresPositiveXBadTag(RequiresPositiveXRegressor): + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.positive_only = False + return tags + + with raises( + AssertionError, match="This happens when passing negative input values as X." + ): + check_positive_only_tag_during_fit( + "RequiresPositiveXBadTag", RequiresPositiveXBadTag() + ) diff --git a/sklearn/utils/tests/test_estimator_html_repr.py b/sklearn/utils/tests/test_estimator_html_repr.py index 580eb24584e2f..c1c35d29c4472 100644 --- a/sklearn/utils/tests/test_estimator_html_repr.py +++ b/sklearn/utils/tests/test_estimator_html_repr.py @@ -140,6 +140,16 @@ def test_get_visual_block_column_transformer(): assert est_html_info.name_details == (["num1", "num2"], [0, 3]) +def test_estimator_html_repr_an_empty_pipeline(): + """Check that the representation of an empty Pipeline does not fail. + + Non-regression test for: + https://github.com/scikit-learn/scikit-learn/issues/30197 + """ + empty_pipeline = Pipeline([]) + estimator_html_repr(empty_pipeline) + + def test_estimator_html_repr_pipeline(): num_trans = Pipeline( steps=[("pass", "passthrough"), ("imputer", SimpleImputer(strategy="median"))] diff --git a/sklearn/utils/tests/test_pprint.py b/sklearn/utils/tests/test_pprint.py index bef5836910787..b3df08732d798 100644 --- a/sklearn/utils/tests/test_pprint.py +++ b/sklearn/utils/tests/test_pprint.py @@ -304,7 +304,7 @@ def test_pipeline(print_changed_only_false): penalty='l2', random_state=None, solver='warn', tol=0.0001, verbose=0, warm_start=False))], - verbose=False)""" + transform_input=None, verbose=False)""" expected = expected[1:] # remove first \n assert pipeline.__repr__() == expected diff --git a/sklearn/utils/tests/test_tags.py b/sklearn/utils/tests/test_tags.py index 5768a0d2b6b27..72a811c8470ef 100644 --- a/sklearn/utils/tests/test_tags.py +++ b/sklearn/utils/tests/test_tags.py @@ -1,11 +1,29 @@ +from dataclasses import dataclass, fields + +import numpy as np import pytest from sklearn.base import ( BaseEstimator, + ClassifierMixin, RegressorMixin, TransformerMixin, ) -from sklearn.utils._tags import get_tags +from sklearn.pipeline import Pipeline +from sklearn.utils import ( + ClassifierTags, + InputTags, + RegressorTags, + Tags, + TargetTags, + TransformerTags, + get_tags, +) +from sklearn.utils._tags import _safe_tags, _to_new_tags, _to_old_tags, default_tags +from sklearn.utils.estimator_checks import ( + check_estimator_tags_renamed, + check_valid_tag_types, +) class NoTagsEstimator: @@ -25,7 +43,9 @@ class EmptyRegressor(RegressorMixin, BaseEstimator): pass -@pytest.mark.filterwarnings("ignore:.*no __sklearn_tags__ attribute.*:FutureWarning") +@pytest.mark.filterwarnings( + "ignore:.*no __sklearn_tags__ attribute.*:DeprecationWarning" +) @pytest.mark.parametrize( "estimator, value", [ @@ -38,3 +58,630 @@ class EmptyRegressor(RegressorMixin, BaseEstimator): ) def test_requires_y(estimator, value): assert get_tags(estimator).target_tags.required == value + + +def test_no___sklearn_tags__with_more_tags(): + """Test that calling `get_tags` on a class that defines `_more_tags` but not + `__sklearn_tags__` raises an error. + """ + + class MoreTagsEstimator(BaseEstimator): + def _more_tags(self): + return {"requires_y": True} # pragma: no cover + + with pytest.raises( + TypeError, match="has defined either `_more_tags` or `_get_tags`" + ): + check_estimator_tags_renamed("MoreTagsEstimator", MoreTagsEstimator()) + + +def test_tag_test_passes_with_inheritance(): + @dataclass + class MyTags(Tags): + my_tag: bool = True + + class MyEstimator(BaseEstimator): + def __sklearn_tags__(self): + tags_orig = super().__sklearn_tags__() + as_dict = { + field.name: getattr(tags_orig, field.name) + for field in fields(tags_orig) + } + tags = MyTags(**as_dict) + tags.my_tag = True + return tags + + check_valid_tag_types("MyEstimator", MyEstimator()) + + +######################################################################################## +# Test for the deprecation +# TODO(1.7): Remove this +######################################################################################## + + +class MixinAllowNanOldTags: + def _more_tags(self): + return {"allow_nan": True} + + +class MixinAllowNanNewTags: + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.allow_nan = True + return tags + + +class MixinAllowNanOldNewTags: + def _more_tags(self): + return {"allow_nan": True} # pragma: no cover + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.input_tags.allow_nan = True + return tags + + +class MixinArrayApiSupportOldTags: + def _more_tags(self): + return {"array_api_support": True} + + +class MixinArrayApiSupportNewTags: + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.array_api_support = True + return tags + + +class MixinArrayApiSupportOldNewTags: + def _more_tags(self): + return {"array_api_support": True} # pragma: no cover + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.array_api_support = True + return tags + + +class PredictorOldTags(BaseEstimator): + def _more_tags(self): + return {"requires_fit": True} + + +class PredictorNewTags(BaseEstimator): + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.requires_fit = True + return tags + + +class PredictorOldNewTags(BaseEstimator): + def _more_tags(self): + return {"requires_fit": True} # pragma: no cover + + def __sklearn_tags__(self): + tags = super().__sklearn_tags__() + tags.requires_fit = True + return tags + + +def test_get_tags_backward_compatibility(): + warn_msg = "Please define the `__sklearn_tags__` method" + + #################################################################################### + # only predictor inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + for predictor_cls in predictor_classes: + if predictor_cls.__name__.endswith("OldTags"): + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = get_tags(predictor_cls()) + else: + tags = get_tags(predictor_cls()) + assert tags.requires_fit + + #################################################################################### + # one mixin and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for allow_nan_cls in allow_nan_classes: + for predictor_cls in predictor_classes: + + class ChildClass(allow_nan_cls, predictor_cls): + pass + + if any( + base_cls.__name__.endswith("OldTags") + for base_cls in (predictor_cls, allow_nan_cls) + ): + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = get_tags(ChildClass()) + else: + tags = get_tags(ChildClass()) + + assert tags.input_tags.allow_nan + assert tags.requires_fit + + #################################################################################### + # two mixins and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + array_api_classes = [ + MixinArrayApiSupportNewTags, + MixinArrayApiSupportOldNewTags, + MixinArrayApiSupportOldTags, + ] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for predictor_cls in predictor_classes: + for array_api_cls in array_api_classes: + for allow_nan_cls in allow_nan_classes: + + class ChildClass(allow_nan_cls, array_api_cls, predictor_cls): + pass + + if any( + base_cls.__name__.endswith("OldTags") + for base_cls in (predictor_cls, array_api_cls, allow_nan_cls) + ): + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = get_tags(ChildClass()) + else: + tags = get_tags(ChildClass()) + + assert tags.input_tags.allow_nan + assert tags.array_api_support + assert tags.requires_fit + + +@pytest.mark.filterwarnings( + "ignore:.*Please define the `__sklearn_tags__` method.*:DeprecationWarning" +) +def test_safe_tags_backward_compatibility(): + warn_msg = "The `_safe_tags` function is deprecated in 1.6" + + #################################################################################### + # only predictor inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + for predictor_cls in predictor_classes: + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = _safe_tags(predictor_cls()) + assert tags["requires_fit"] + + #################################################################################### + # one mixin and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for allow_nan_cls in allow_nan_classes: + for predictor_cls in predictor_classes: + + class ChildClass(allow_nan_cls, predictor_cls): + pass + + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = _safe_tags(ChildClass()) + + assert tags["allow_nan"] + assert tags["requires_fit"] + + #################################################################################### + # two mixins and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + array_api_classes = [ + MixinArrayApiSupportNewTags, + MixinArrayApiSupportOldNewTags, + MixinArrayApiSupportOldTags, + ] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for predictor_cls in predictor_classes: + for array_api_cls in array_api_classes: + for allow_nan_cls in allow_nan_classes: + + class ChildClass(allow_nan_cls, array_api_cls, predictor_cls): + pass + + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = _safe_tags(ChildClass()) + + assert tags["allow_nan"] + assert tags["array_api_support"] + assert tags["requires_fit"] + + +@pytest.mark.filterwarnings( + "ignore:.*Please define the `__sklearn_tags__` method.*:DeprecationWarning" +) +def test__get_tags_backward_compatibility(): + warn_msg = "The `_get_tags` method is deprecated in 1.6" + + #################################################################################### + # only predictor inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + for predictor_cls in predictor_classes: + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = predictor_cls()._get_tags() + assert tags["requires_fit"] + + #################################################################################### + # one mixin and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for allow_nan_cls in allow_nan_classes: + for predictor_cls in predictor_classes: + + class ChildClass(allow_nan_cls, predictor_cls): + pass + + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = ChildClass()._get_tags() + + assert tags["allow_nan"] + assert tags["requires_fit"] + + #################################################################################### + # two mixins and one predictor all inheriting from BaseEstimator + predictor_classes = [PredictorNewTags, PredictorOldNewTags, PredictorOldTags] + array_api_classes = [ + MixinArrayApiSupportNewTags, + MixinArrayApiSupportOldNewTags, + MixinArrayApiSupportOldTags, + ] + allow_nan_classes = [ + MixinAllowNanNewTags, + MixinAllowNanOldNewTags, + MixinAllowNanOldTags, + ] + + for predictor_cls in predictor_classes: + for array_api_cls in array_api_classes: + for allow_nan_cls in allow_nan_classes: + + class ChildClass(allow_nan_cls, array_api_cls, predictor_cls): + pass + + with pytest.warns(DeprecationWarning, match=warn_msg): + tags = ChildClass()._get_tags() + + assert tags["allow_nan"] + assert tags["array_api_support"] + assert tags["requires_fit"] + + +def test_roundtrip_tags(): + estimator = PredictorNewTags() + tags = default_tags(estimator) + assert _to_new_tags(_to_old_tags(tags), estimator=estimator) == tags + + +def test_base_estimator_more_tags(): + """Test that the `_more_tags` and `_get_tags` methods are equivalent for + `BaseEstimator`. + """ + estimator = BaseEstimator() + with pytest.warns( + DeprecationWarning, match="The `_more_tags` method is deprecated" + ): + more_tags = BaseEstimator._more_tags(estimator) + + with pytest.warns(DeprecationWarning, match="The `_get_tags` method is deprecated"): + get_tags = BaseEstimator._get_tags(estimator) + + assert more_tags == get_tags + + +def test_safe_tags(): + estimator = PredictorNewTags() + with pytest.warns( + DeprecationWarning, match="The `_safe_tags` function is deprecated" + ): + tags = _safe_tags(estimator) + + with pytest.warns( + DeprecationWarning, match="The `_safe_tags` function is deprecated" + ): + tags_requires_fit = _safe_tags(estimator, key="requires_fit") + + assert tags_requires_fit == tags["requires_fit"] + + err_msg = "The key unknown_key is not defined" + with pytest.raises(ValueError, match=err_msg): + with pytest.warns( + DeprecationWarning, match="The `_safe_tags` function is deprecated" + ): + _safe_tags(estimator, key="unknown_key") + + +def test_old_tags(): + """Set to non-default values and check that we get the expected old tags.""" + + class MyClass: + _estimator_type = "regressor" + + def __sklearn_tags__(self): + input_tags = InputTags( + one_d_array=True, + two_d_array=False, + three_d_array=True, + sparse=True, + categorical=True, + string=True, + dict=True, + positive_only=True, + allow_nan=True, + pairwise=True, + ) + target_tags = TargetTags( + required=False, + one_d_labels=True, + two_d_labels=True, + positive_only=True, + multi_output=True, + single_output=False, + ) + transformer_tags = None + classifier_tags = None + regressor_tags = RegressorTags( + poor_score=True, + ) + return Tags( + estimator_type=self._estimator_type, + input_tags=input_tags, + target_tags=target_tags, + transformer_tags=transformer_tags, + classifier_tags=classifier_tags, + regressor_tags=regressor_tags, + ) + + estimator = MyClass() + new_tags = get_tags(estimator) + old_tags = _to_old_tags(new_tags) + expected_tags = { + "allow_nan": True, + "array_api_support": False, + "binary_only": False, + "multilabel": False, + "multioutput": True, + "multioutput_only": True, + "no_validation": False, + "non_deterministic": False, + "pairwise": True, + "preserves_dtype": ["float64"], + "poor_score": True, + "requires_fit": True, + "requires_positive_X": True, + "requires_y": False, + "requires_positive_y": True, + "_skip_test": False, + "stateless": True, + "X_types": [ + "1darray", + "3darray", + "sparse", + "categorical", + "string", + "dict", + "1dlabels", + "2dlabels", + ], + } + assert old_tags == expected_tags + assert _to_new_tags(_to_old_tags(new_tags), estimator=estimator) == new_tags + + class MyClass: + _estimator_type = "classifier" + + def __sklearn_tags__(self): + input_tags = InputTags( + one_d_array=True, + two_d_array=False, + three_d_array=True, + sparse=True, + categorical=True, + string=True, + dict=True, + positive_only=True, + allow_nan=True, + pairwise=True, + ) + target_tags = TargetTags( + required=False, + one_d_labels=True, + two_d_labels=False, + positive_only=True, + multi_output=True, + single_output=False, + ) + transformer_tags = None + classifier_tags = ClassifierTags( + poor_score=True, + multi_class=False, + multi_label=True, + ) + regressor_tags = None + return Tags( + estimator_type=self._estimator_type, + input_tags=input_tags, + target_tags=target_tags, + transformer_tags=transformer_tags, + classifier_tags=classifier_tags, + regressor_tags=regressor_tags, + ) + + estimator = MyClass() + new_tags = get_tags(estimator) + old_tags = _to_old_tags(new_tags) + expected_tags = { + "allow_nan": True, + "array_api_support": False, + "binary_only": True, + "multilabel": True, + "multioutput": True, + "multioutput_only": True, + "no_validation": False, + "non_deterministic": False, + "pairwise": True, + "preserves_dtype": ["float64"], + "poor_score": True, + "requires_fit": True, + "requires_positive_X": True, + "requires_y": False, + "requires_positive_y": True, + "_skip_test": False, + "stateless": True, + "X_types": [ + "1darray", + "3darray", + "sparse", + "categorical", + "string", + "dict", + "1dlabels", + ], + } + assert old_tags == expected_tags + assert _to_new_tags(_to_old_tags(new_tags), estimator=estimator) == new_tags + + class MyClass: + + def fit(self, X, y=None): + return self # pragma: no cover + + def transform(self, X): + return X # pragma: no cover + + def __sklearn_tags__(self): + input_tags = InputTags( + one_d_array=True, + two_d_array=False, + three_d_array=True, + sparse=True, + categorical=True, + string=True, + dict=True, + positive_only=True, + allow_nan=True, + pairwise=True, + ) + target_tags = TargetTags( + required=False, + one_d_labels=True, + two_d_labels=False, + positive_only=True, + multi_output=True, + single_output=False, + ) + transformer_tags = TransformerTags( + preserves_dtype=["float64"], + ) + classifier_tags = None + regressor_tags = None + return Tags( + estimator_type=None, + input_tags=input_tags, + target_tags=target_tags, + transformer_tags=transformer_tags, + classifier_tags=classifier_tags, + regressor_tags=regressor_tags, + ) + + estimator = MyClass() + new_tags = get_tags(estimator) + old_tags = _to_old_tags(new_tags) + expected_tags = { + "allow_nan": True, + "array_api_support": False, + "binary_only": False, + "multilabel": False, + "multioutput": True, + "multioutput_only": True, + "no_validation": False, + "non_deterministic": False, + "pairwise": True, + "preserves_dtype": ["float64"], + "poor_score": False, + "requires_fit": True, + "requires_positive_X": True, + "requires_y": False, + "requires_positive_y": True, + "_skip_test": False, + "stateless": True, + "X_types": [ + "1darray", + "3darray", + "sparse", + "categorical", + "string", + "dict", + "1dlabels", + ], + } + assert old_tags == expected_tags + assert _to_new_tags(_to_old_tags(new_tags), estimator=estimator) == new_tags + + +# TODO(1.7): Remove this test +def test_tags_no_sklearn_tags_concrete_implementation(): + """Non-regression test for: + https://github.com/scikit-learn/scikit-learn/issues/30479 + + There is no class implementing `__sklearn_tags__` without calling + `super().__sklearn_tags__()`. Thus, we raise a warning and request to inherit from + `BaseEstimator` that implements `__sklearn_tags__`. + """ + + class MyEstimator(ClassifierMixin): + def __init__(self, *, param=1): + self.param = param + + def fit(self, X, y=None): + self.is_fitted_ = True + return self + + def predict(self, X): + return np.full(shape=X.shape[0], fill_value=self.param) + + X = np.array([[1, 2], [2, 3], [3, 4]]) + y = np.array([1, 0, 1]) + + my_pipeline = Pipeline([("estimator", MyEstimator(param=1))]) + with pytest.warns(DeprecationWarning, match="The following error was raised"): + my_pipeline.fit(X, y).predict(X) + + # check that we still raise an error if it is not a AttributeError or related to + # __sklearn_tags__ + class MyEstimator2(MyEstimator, BaseEstimator): + def __init__(self, *, param=1, error_type=AttributeError): + self.param = param + self.error_type = error_type + + def __sklearn_tags__(self): + super().__sklearn_tags__() + raise self.error_type("test") + + for error_type in (AttributeError, TypeError, ValueError): + estimator = MyEstimator2(param=1, error_type=error_type) + with pytest.raises(error_type): + get_tags(estimator) diff --git a/sklearn/utils/tests/test_testing.py b/sklearn/utils/tests/test_testing.py index bc13019dab550..ecc74ecaae7c4 100644 --- a/sklearn/utils/tests/test_testing.py +++ b/sklearn/utils/tests/test_testing.py @@ -782,6 +782,44 @@ def test_assert_docstring_consistency_error_msg(): assert_docstring_consistency([f_four, f_five, f_six], include_params=True) +@skip_if_no_numpydoc +def test_assert_docstring_consistency_descr_regex_pattern(): + """Check `assert_docstring_consistency` `descr_regex_pattern` works.""" + # Check regex that matches full parameter descriptions + regex_full = ( + r"The (set|group) " # match 'set' or 'group' + + r"of labels to (include|add) " # match 'include' or 'add' + + r"when `average \!\= 'binary'`, and (their|the) " # match 'their' or 'the' + + r"order if `average is None`\." + + r"[\s\w]*\.* " # optionally match additonal sentence + + r"Labels present (on|in) " # match 'on' or 'in' + + r"(them|the) " # match 'them' or 'the' + + r"datas? can be excluded\." # match 'data' or 'datas' + ) + + assert_docstring_consistency( + [f_four, f_five, f_six], + include_params=True, + descr_regex_pattern=" ".join(regex_full.split()), + ) + # Check we can just match a few alternate words + regex_words = r"(labels|average|binary)" # match any of these 3 words + assert_docstring_consistency( + [f_four, f_five, f_six], + include_params=True, + descr_regex_pattern=" ".join(regex_words.split()), + ) + # Check error raised when regex doesn't match + regex_error = r"The set of labels to include when.+" + msg = r"The description of Parameter 'labels' in \['f_six'\] does not match" + with pytest.raises(AssertionError, match=msg): + assert_docstring_consistency( + [f_four, f_five, f_six], + include_params=True, + descr_regex_pattern=" ".join(regex_error.split()), + ) + + class RegistrationCounter: def __init__(self): self.nb_calls = 0 diff --git a/sklearn/utils/tests/test_validation.py b/sklearn/utils/tests/test_validation.py index 5ae5a003d0d0a..8d6069631db6a 100644 --- a/sklearn/utils/tests/test_validation.py +++ b/sklearn/utils/tests/test_validation.py @@ -743,7 +743,12 @@ def test_check_array_min_samples_and_features_messages(): check_array([], ensure_2d=False) # Invalid edge case when checking the default minimum sample of a scalar - msg = r"Singleton array array\(42\) cannot be considered a valid" " collection." + msg = re.escape( + ( + "Input should have at least 1 dimension i.e. satisfy " + "`len(x.shape) > 0`, got scalar `array(42)` instead." + ) + ) with pytest.raises(TypeError, match=msg): check_array(42, ensure_2d=False) @@ -1833,19 +1838,19 @@ def test_num_features_errors_1d_containers(X, constructor_name): if constructor_name == "array": expected_type_name = "numpy.ndarray" elif constructor_name == "series": - expected_type_name = "pandas.core.series.Series" + expected_type_name = "pandas.*Series" else: expected_type_name = constructor_name message = ( f"Unable to find the number of features from X of type {expected_type_name}" ) if hasattr(X, "shape"): - message += " with shape (3,)" + message += re.escape(" with shape (3,)") elif isinstance(X[0], str): message += " where the samples are of type str" elif isinstance(X[0], dict): message += " where the samples are of type dict" - with pytest.raises(TypeError, match=re.escape(message)): + with pytest.raises(TypeError, match=message): _num_features(X) diff --git a/sklearn/utils/validation.py b/sklearn/utils/validation.py index 649df1de8f223..7b227be44b77d 100644 --- a/sklearn/utils/validation.py +++ b/sklearn/utils/validation.py @@ -397,7 +397,8 @@ def _num_samples(x): if hasattr(x, "shape") and x.shape is not None: if len(x.shape) == 0: raise TypeError( - "Singleton array %r cannot be considered a valid collection." % x + "Input should have at least 1 dimension i.e. satisfy " + f"`len(x.shape) > 0`, got scalar `{x!r}` instead." ) # Check that shape is returning an integer or default to len # Dask dataframes may not return numeric shape[0] value @@ -1413,7 +1414,7 @@ def _check_y(y, multi_output=False, y_numeric=False, estimator=None): return y -def column_or_1d(y, *, dtype=None, warn=False): +def column_or_1d(y, *, dtype=None, warn=False, device=None): """Ravel column or 1d numpy array, else raises an error. Parameters @@ -1429,6 +1430,12 @@ def column_or_1d(y, *, dtype=None, warn=False): warn : bool, default=False To control display of warnings. + device : device, default=None + `device` object. + See the :ref:`Array API User Guide ` for more details. + + .. versionadded:: 1.6 + Returns ------- y : ndarray @@ -1457,7 +1464,9 @@ def column_or_1d(y, *, dtype=None, warn=False): shape = y.shape if len(shape) == 1: - return _asarray_with_order(xp.reshape(y, (-1,)), order="C", xp=xp) + return _asarray_with_order( + xp.reshape(y, (-1,)), order="C", xp=xp, device=device + ) if len(shape) == 2 and shape[1] == 1: if warn: warnings.warn( @@ -1469,7 +1478,9 @@ def column_or_1d(y, *, dtype=None, warn=False): DataConversionWarning, stacklevel=2, ) - return _asarray_with_order(xp.reshape(y, (-1,)), order="C", xp=xp) + return _asarray_with_order( + xp.reshape(y, (-1,)), order="C", xp=xp, device=device + ) raise ValueError( "y should be a 1d array, got an array of shape {} instead.".format(shape) @@ -1533,7 +1544,14 @@ def has_fit_parameter(estimator, parameter): >>> has_fit_parameter(SVC(), "sample_weight") True """ - return parameter in signature(estimator.fit).parameters + return ( + # This is used during test collection in common tests. The + # hasattr(estimator, "fit") makes it so that we don't fail for an estimator + # that does not have a `fit` method during collection of checks. The right + # checks will fail later. + hasattr(estimator, "fit") + and parameter in signature(estimator.fit).parameters + ) def check_symmetric(array, *, tol=1e-10, raise_warning=True, raise_exception=False): pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy