From d4d3c6d68c3e96f932d57d1c92d7fe767095a138 Mon Sep 17 00:00:00 2001 From: Tim de Jager Date: Wed, 4 Dec 2024 08:42:22 +0100 Subject: [PATCH] feat: add proper unit testing for PyPI installation (#2617) ## Description This adds proper unit testing, for PyPI installations and adds a test harness to test these things. This is a much more efficient and smaller way of testing the functionality, specifically the need to install/re-install then doing full integration tests. ## Checklist - [x] Tests for direct url archives - [x] Test for vcs installs. - [x] See if we need to remove integration tests, because some of it is tested here. --------- Co-authored-by: Bas Zalmstra --- examples/pypi-source-deps/pixi.lock | 1451 +++++++---------- examples/pypi-source-deps/pixi.toml | 2 +- ...t_conda_env_yaml_with_source_editable.snap | 2 +- src/install_pypi/conversions.rs | 1 - src/install_pypi/mod.rs | 34 +- src/install_pypi/{plan.rs => plan/mod.rs} | 164 +- src/install_pypi/plan/test/harness.rs | 521 ++++++ src/install_pypi/plan/test/mod.rs | 471 ++++++ 8 files changed, 1735 insertions(+), 911 deletions(-) rename src/install_pypi/{plan.rs => plan/mod.rs} (77%) create mode 100644 src/install_pypi/plan/test/harness.rs create mode 100644 src/install_pypi/plan/test/mod.rs diff --git a/examples/pypi-source-deps/pixi.lock b/examples/pypi-source-deps/pixi.lock index 89e7a76f3..ab3f559d5 100644 --- a/examples/pypi-source-deps/pixi.lock +++ b/examples/pypi-source-deps/pixi.lock @@ -1,4 +1,4 @@ -version: 5 +version: 6 environments: default: channels: @@ -10,174 +10,170 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.7.4-hbcca054_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.1.0-h77fa898_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h69a702a_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.0-hde9e2c9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-h4bc722e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-hb9d3cd8_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.5-h2ad013b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.13-5_cp313.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl - - pypi: git+https://github.com/pallets/flask@f93dd6e826a9bf00bf9e08d9bb3a03abcb1e974c - - pypi: https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl + - pypi: git+https://github.com/pallets/flask@f2674c5bb4f7a79f836069859a346b81771eeee5 + - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - - pypi: git+https://github.com/pytest-dev/pytest.git@c947145fbb4aeec810a259b19f70fcb52fd53ad4 - - pypi: git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 - - pypi: https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl + - pypi: git+https://github.com/pytest-dev/pytest.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3 + - pypi: git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 + - pypi: https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl - pypi: ./minimal-project osx-64: - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.7.4-h8857fd0_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.2-h73e2aa4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.8.30-h8857fd0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.4-h240833e_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.46.0-h1b8f9f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-h87427d6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hfdf4475_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.47.0-h2f8c449_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-hf036a51_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.1-hd23fc13_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.5-h37a9e06_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.0-hd471939_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.0-h3a8ca6c_101_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.13-5_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl - pypi: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl - - pypi: git+https://github.com/pallets/flask@f93dd6e826a9bf00bf9e08d9bb3a03abcb1e974c - - pypi: https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl + - pypi: git+https://github.com/pallets/flask@f2674c5bb4f7a79f836069859a346b81771eeee5 + - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - - pypi: git+https://github.com/pytest-dev/pytest.git@c947145fbb4aeec810a259b19f70fcb52fd53ad4 - - pypi: git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 - - pypi: https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl + - pypi: git+https://github.com/pytest-dev/pytest.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3 + - pypi: git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 + - pypi: https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl - pypi: ./minimal-project osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.7.4-hf0a4a13_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.4-h286801f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.46.0-hfb93653_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-hfb2fe0b_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h99b78c6_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.47.0-hbaaea75_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.1-h8359307_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.5-h30c5eda_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.0-h39f12f2_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl - pypi: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl - - pypi: git+https://github.com/pallets/flask@f93dd6e826a9bf00bf9e08d9bb3a03abcb1e974c - - pypi: https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl + - pypi: git+https://github.com/pallets/flask@f2674c5bb4f7a79f836069859a346b81771eeee5 + - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl + - pypi: https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - - pypi: git+https://github.com/pytest-dev/pytest.git@c947145fbb4aeec810a259b19f70fcb52fd53ad4 - - pypi: git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 - - pypi: https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl + - pypi: git+https://github.com/pytest-dev/pytest.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3 + - pypi: git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 + - pypi: https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl - pypi: ./minimal-project win-64: - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.7.4-h56e8100_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.2-h63175ca_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.8.30-h56e8100_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.4-he0c23c2_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.46.0-h2466b09_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_1.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.3.1-h2466b09_3.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.12.5-h889d299_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.47.0-h2466b09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python_abi-3.13-5_cp313.conda - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h8a93ad2_20.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.40.33810-hcc2c482_20.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.40.33810-h3bf8584_20.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.42.34433-he29a5d6_23.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.42.34433-hdffcdeb_23.conda - conda: https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 - - pypi: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl - pypi: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl - - pypi: git+https://github.com/pallets/flask@f93dd6e826a9bf00bf9e08d9bb3a03abcb1e974c - - pypi: https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl + - pypi: git+https://github.com/pallets/flask@f2674c5bb4f7a79f836069859a346b81771eeee5 + - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - - pypi: git+https://github.com/pytest-dev/pytest.git@c947145fbb4aeec810a259b19f70fcb52fd53ad4 - - pypi: git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 - - pypi: https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl + - pypi: git+https://github.com/pytest-dev/pytest.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3 + - pypi: git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 + - pypi: https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl - pypi: ./minimal-project packages: -- kind: conda - name: _libgcc_mutex - version: '0.1' - build: conda_forge - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 md5: d7c89558ba9fa0495403155b64376d81 license: None purls: [] size: 2562 timestamp: 1578324546067 -- kind: conda - name: _openmp_mutex - version: '4.5' - build: 2_gnu +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 build_number: 16 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 md5: 73aaf86a425cc6e73fcf236a5a46396d depends: @@ -190,37 +186,12 @@ packages: purls: [] size: 23621 timestamp: 1650670423406 -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl name: blinker - version: 1.8.2 - url: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - sha256: 1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01 - requires_python: '>=3.8' -- kind: conda - name: bzip2 - version: 1.0.8 - build: h2466b09_7 - build_number: 7 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda - sha256: 35a5dad92e88fdd7fc405e864ec239486f4f31eec229e31686e61a140a8e573b - md5: 276e7ffe9ffe39688abc665ef0f45596 - depends: - - ucrt >=10.0.20348.0 - - vc >=14.2,<15 - - vc14_runtime >=14.29.30139 - license: bzip2-1.0.6 - license_family: BSD - purls: [] - size: 54927 - timestamp: 1720974860185 -- kind: conda - name: bzip2 - version: 1.0.8 - build: h4bc722e_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + version: 1.9.0 + sha256: ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d md5: 62ee74e96c5ebb0af99386de58cf9553 depends: @@ -231,13 +202,17 @@ packages: purls: [] size: 252783 timestamp: 1720974456583 -- kind: conda - name: bzip2 - version: 1.0.8 - build: h99b78c6_7 - build_number: 7 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda +- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda + sha256: cad153608b81fb24fc8c509357daa9ae4e49dfc535b2cb49b91e23dbd68fc3c5 + md5: 7ed4301d437b59045be7e051a0308211 + depends: + - __osx >=10.13 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 134188 + timestamp: 1720974491916 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda sha256: adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91 md5: fc6948412dbbbe9a4c9ddbbcfe0a79ab depends: @@ -247,240 +222,198 @@ packages: purls: [] size: 122909 timestamp: 1720974522888 -- kind: conda - name: bzip2 - version: 1.0.8 - build: hfdf4475_7 - build_number: 7 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda - sha256: cad153608b81fb24fc8c509357daa9ae4e49dfc535b2cb49b91e23dbd68fc3c5 - md5: 7ed4301d437b59045be7e051a0308211 +- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda + sha256: 35a5dad92e88fdd7fc405e864ec239486f4f31eec229e31686e61a140a8e573b + md5: 276e7ffe9ffe39688abc665ef0f45596 depends: - - __osx >=10.13 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 license: bzip2-1.0.6 license_family: BSD purls: [] - size: 134188 - timestamp: 1720974491916 -- kind: conda - name: ca-certificates - version: 2024.7.4 - build: h56e8100_0 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.7.4-h56e8100_0.conda - sha256: 7f37bb33c7954de1b4d19ad622859feb4f6c58f751c38b895524cad4e44af72e - md5: 9caa97c9504072cd060cf0a3142cc0ed + size: 54927 + timestamp: 1720974860185 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda + sha256: afee721baa6d988e27fef1832f68d6f32ac8cc99cdf6015732224c2841a09cea + md5: c27d1c142233b5bc9ca570c6e2e0c244 license: ISC purls: [] - size: 154943 - timestamp: 1720077592592 -- kind: conda - name: ca-certificates - version: 2024.7.4 - build: h8857fd0_0 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.7.4-h8857fd0_0.conda - sha256: d16f46c489cb3192305c7d25b795333c5fc17bb0986de20598ed519f8c9cc9e4 - md5: 7df874a4b05b2d2b82826190170eaa0f + size: 159003 + timestamp: 1725018903918 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.8.30-h8857fd0_0.conda + sha256: 593f302d0f44c2c771e1614ee6d56fffdc7d616e6f187669c8b0e34ffce3e1ae + md5: b7e5424e7f06547a903d28e4651dbb21 license: ISC purls: [] - size: 154473 - timestamp: 1720077510541 -- kind: conda - name: ca-certificates - version: 2024.7.4 - build: hbcca054_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.7.4-hbcca054_0.conda - sha256: c1548a3235376f464f9931850b64b02492f379b2f2bb98bc786055329b080446 - md5: 23ab7665c5f63cfb9f1f6195256daac6 + size: 158665 + timestamp: 1725019059295 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda + sha256: 2db1733f4b644575dbbdd7994a8f338e6ef937f5ebdb74acd557e9dda0211709 + md5: 40dec13fd8348dbe303e57be74bd3d35 license: ISC purls: [] - size: 154853 - timestamp: 1720077432978 -- kind: conda - name: ca-certificates - version: 2024.7.4 - build: hf0a4a13_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.7.4-hf0a4a13_0.conda - sha256: 33a61116dae7f369b6ce92a7f2a1ff361ae737c675a493b11feb5570b89e0e3b - md5: 21f9a33e5fe996189e470c19c5354dbe + size: 158482 + timestamp: 1725019034582 +- conda: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.8.30-h56e8100_0.conda + sha256: 0fcac3a7ffcc556649e034a1802aedf795e64227eaa7194d207b01eaf26454c4 + md5: 4c4fd67c18619be5aa65dc5b6c72e490 license: ISC purls: [] - size: 154517 - timestamp: 1720077468981 -- kind: pypi + size: 158773 + timestamp: 1725019107649 +- pypi: https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl name: certifi - version: 2024.7.4 - url: https://files.pythonhosted.org/packages/1c/d5/c84e1a17bf61d4df64ca866a1c9a913874b4e9bdc131ec689a0ad013fb36/certifi-2024.7.4-py3-none-any.whl - sha256: c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 + version: 2024.8.30 + sha256: 922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 requires_python: '>=3.6' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: charset-normalizer - version: 3.3.2 - url: https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl - sha256: ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b + version: 3.4.0 + sha256: 4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc requires_python: '>=3.7.0' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl name: charset-normalizer - version: 3.3.2 - url: https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl - sha256: 55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 + version: 3.4.0 + sha256: e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed requires_python: '>=3.7.0' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl name: charset-normalizer - version: 3.3.2 - url: https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl - sha256: 96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 + version: 3.4.0 + sha256: 92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 requires_python: '>=3.7.0' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl name: charset-normalizer - version: 3.3.2 - url: https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b + version: 3.4.0 + sha256: 707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b requires_python: '>=3.7.0' -- kind: pypi +- pypi: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl name: click version: 8.1.7 - url: direct+https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl requires_dist: - colorama ; platform_system == 'Windows' - importlib-metadata ; python_full_version < '3.8' requires_python: '>=3.7' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl name: colorama version: 0.4.6 - url: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl sha256: 4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7' -- kind: pypi + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' +- pypi: git+https://github.com/pallets/flask@f2674c5bb4f7a79f836069859a346b81771eeee5 name: flask - version: 3.1.0.dev0 - url: git+https://github.com/pallets/flask@f93dd6e826a9bf00bf9e08d9bb3a03abcb1e974c + version: 3.1.1.dev0 requires_dist: - - werkzeug>=3.0.0 + - werkzeug>=3.1 - jinja2>=3.1.2 - - itsdangerous>=2.1.2 + - itsdangerous>=2.2 - click>=8.1.3 - - blinker>=1.6.2 - - importlib-metadata>=3.6.0 ; python_full_version < '3.10' + - blinker>=1.9 + - importlib-metadata>=3.6 ; python_full_version < '3.10' - asgiref>=3.2 ; extra == 'async' - python-dotenv ; extra == 'dotenv' - requires_python: '>=3.8' -- kind: pypi + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl name: idna - version: '3.8' - url: https://files.pythonhosted.org/packages/22/7e/d71db821f177828df9dea8c42ac46473366f191be53080e552e628aad991/idna-3.8-py3-none-any.whl - sha256: 050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac + version: '3.10' + sha256: 946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 + requires_dist: + - ruff>=0.6.2 ; extra == 'all' + - mypy>=1.11.2 ; extra == 'all' + - pytest>=8.3.2 ; extra == 'all' + - flake8>=7.1.1 ; extra == 'all' requires_python: '>=3.6' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl name: iniconfig version: 2.0.0 - url: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl sha256: b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 requires_python: '>=3.7' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl name: itsdangerous version: 2.2.0 - url: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl sha256: c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef requires_python: '>=3.8' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl name: jinja2 version: 3.1.4 - url: https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl sha256: bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d requires_dist: - markupsafe>=2.0 - babel>=2.7 ; extra == 'i18n' requires_python: '>=3.7' -- kind: conda - name: ld_impl_linux-64 - version: '2.40' - build: hf3520f5_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda - sha256: 764b6950aceaaad0c67ef925417594dd14cd2e22fff864aeef455ac259263d15 - md5: b80f2f396ca2c28b8c14c437a4ed1e74 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_2.conda + sha256: 7c91cea91b13f4314d125d1bedb9d03a29ebbd5080ccdea70260363424646dbe + md5: 048b02e3962f066da18efe3a21b77672 + depends: + - __glibc >=2.17,<3.0.a0 constrains: - - binutils_impl_linux-64 2.40 + - binutils_impl_linux-64 2.43 license: GPL-3.0-only license_family: GPL purls: [] - size: 707602 - timestamp: 1718625640445 -- kind: conda - name: libexpat - version: 2.6.2 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda - sha256: 331bb7c7c05025343ebd79f86ae612b9e1e74d2687b8f3179faec234f986ce19 - md5: e7ba12deb7020dd080c6c70e7b6f6a3d + size: 669211 + timestamp: 1729655358674 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda + sha256: 56541b98447b58e52d824bd59d6382d609e11de1f8adf20b23143e353d2b8d26 + md5: db833e03127376d461e1e13e76f09b6c depends: - - libgcc-ng >=12 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 constrains: - - expat 2.6.2.* + - expat 2.6.4.* license: MIT license_family: MIT purls: [] - size: 73730 - timestamp: 1710362120304 -- kind: conda - name: libexpat - version: 2.6.2 - build: h63175ca_0 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.2-h63175ca_0.conda - sha256: 79f612f75108f3e16bbdc127d4885bb74729cf66a8702fca0373dad89d40c4b7 - md5: bc592d03f62779511d392c175dcece64 + size: 73304 + timestamp: 1730967041968 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.4-h240833e_0.conda + sha256: d10f43d0c5df6c8cf55259bce0fe14d2377eed625956cddce06f58827d288c59 + md5: 20307f4049a735a78a29073be1be2626 + depends: + - __osx >=10.13 constrains: - - expat 2.6.2.* + - expat 2.6.4.* license: MIT license_family: MIT purls: [] - size: 139224 - timestamp: 1710362609641 -- kind: conda - name: libexpat - version: 2.6.2 - build: h73e2aa4_0 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.2-h73e2aa4_0.conda - sha256: a188a77b275d61159a32ab547f7d17892226e7dac4518d2c6ac3ac8fc8dfde92 - md5: 3d1d51c8f716d97c864d12f7af329526 + size: 70758 + timestamp: 1730967204736 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.4-h286801f_0.conda + sha256: e42ab5ace927ee7c84e3f0f7d813671e1cf3529f5f06ee5899606630498c2745 + md5: 38d2656dd914feb0cab8c629370768bf + depends: + - __osx >=11.0 constrains: - - expat 2.6.2.* + - expat 2.6.4.* license: MIT license_family: MIT purls: [] - size: 69246 - timestamp: 1710362566073 -- kind: conda - name: libexpat - version: 2.6.2 - build: hebf3989_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda - sha256: ba7173ac30064ea901a4c9fb5a51846dcc25512ceb565759be7d18cbf3e5415e - md5: e3cde7cfa87f82f7cb13d482d5e0ad09 + size: 64693 + timestamp: 1730967175868 +- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.6.4-he0c23c2_0.conda + sha256: 0c0447bf20d1013d5603499de93a16b6faa92d7ead870d96305c0f065b6a5a12 + md5: eb383771c680aa792feb529eaf9df82f + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 constrains: - - expat 2.6.2.* + - expat 2.6.4.* license: MIT license_family: MIT purls: [] - size: 63655 - timestamp: 1710362424980 -- kind: conda - name: libffi - version: 3.4.2 - build: h0d85af4_5 - build_number: 5 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 + size: 139068 + timestamp: 1730967442102 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e + md5: d645c6d2ac96843a2bfaccd2d62b3ac3 + depends: + - libgcc-ng >=9.4.0 + license: MIT + license_family: MIT + purls: [] + size: 58292 + timestamp: 1636488182923 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 sha256: 7a2d27a936ceee6942ea4d397f9c7d136f12549d86f7617e8b6bad51e01a941f md5: ccb34fb14960ad8b125962d3d79b31a9 license: MIT @@ -488,13 +421,7 @@ packages: purls: [] size: 51348 timestamp: 1636488394370 -- kind: conda - name: libffi - version: 3.4.2 - build: h3422bc3_5 - build_number: 5 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca md5: 086914b672be056eb70fd4285b6783b6 license: MIT @@ -502,29 +429,7 @@ packages: purls: [] size: 39020 timestamp: 1636488587153 -- kind: conda - name: libffi - version: 3.4.2 - build: h7f98852_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 - sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e - md5: d645c6d2ac96843a2bfaccd2d62b3ac3 - depends: - - libgcc-ng >=9.4.0 - license: MIT - license_family: MIT - purls: [] - size: 58292 - timestamp: 1636488182923 -- kind: conda - name: libffi - version: 3.4.2 - build: h8ffe710_5 - build_number: 5 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2 sha256: 1951ab740f80660e9bc07d2ed3aefb874d78c107264fd810f24a1a6211d4b1a5 md5: 2c96d1b6915b408893f9472569dee135 depends: @@ -535,140 +440,126 @@ packages: purls: [] size: 42063 timestamp: 1636489106777 -- kind: conda - name: libgcc - version: 14.1.0 - build: h77fa898_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.1.0-h77fa898_1.conda - sha256: 10fa74b69266a2be7b96db881e18fa62cfa03082b65231e8d652e897c4b335a3 - md5: 002ef4463dd1e2b44a94a4ace468f5d2 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h77fa898_1.conda + sha256: 53eb8a79365e58849e7b1a068d31f4f9e718dc938d6f2c03e960345739a03569 + md5: 3cb76c3f10d3bc7f1105b2fc9db984df depends: - _libgcc_mutex 0.1 conda_forge - _openmp_mutex >=4.5 constrains: - - libgomp 14.1.0 h77fa898_1 - - libgcc-ng ==14.1.0=*_1 + - libgomp 14.2.0 h77fa898_1 + - libgcc-ng ==14.2.0=*_1 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 846380 - timestamp: 1724801836552 -- kind: conda - name: libgcc-ng - version: 14.1.0 - build: h69a702a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h69a702a_1.conda - sha256: b91f7021e14c3d5c840fbf0dc75370d6e1f7c7ff4482220940eaafb9c64613b7 - md5: 1efc0ad219877a73ef977af7dbb51f17 + size: 848745 + timestamp: 1729027721139 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_1.conda + sha256: 3a76969c80e9af8b6e7a55090088bc41da4cffcde9e2c71b17f44d37b7cb87f7 + md5: e39480b9ca41323497b05492a63bc35b depends: - - libgcc 14.1.0 h77fa898_1 + - libgcc 14.2.0 h77fa898_1 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 52170 - timestamp: 1724801842101 -- kind: conda - name: libgomp - version: 14.1.0 - build: h77fa898_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_1.conda - sha256: c96724c8ae4ee61af7674c5d9e5a3fbcf6cd887a40ad5a52c99aa36f1d4f9680 - md5: 23c255b008c4f2ae008f81edcabaca89 + size: 54142 + timestamp: 1729027726517 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h77fa898_1.conda + sha256: 1911c29975ec99b6b906904040c855772ccb265a1c79d5d75c8ceec4ed89cd63 + md5: cc3573974587f12dda90d96e3e55a702 depends: - _libgcc_mutex 0.1 conda_forge license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 460218 - timestamp: 1724801743478 -- kind: conda - name: libnsl - version: 2.0.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 - md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 + size: 460992 + timestamp: 1729027639220 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-h4bc722e_0.conda + sha256: d02d1d3304ecaf5c728e515eb7416517a0b118200cd5eacbe829c432d1664070 + md5: aeb98fdeb2e8f25d43ef71fbacbeec80 depends: + - __glibc >=2.17,<3.0.a0 - libgcc-ng >=12 - license: LGPL-2.1-only - license_family: GPL + license: BSD-2-Clause + license_family: BSD purls: [] - size: 33408 - timestamp: 1697359010159 -- kind: conda - name: libsqlite - version: 3.46.0 - build: h1b8f9f3_0 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.46.0-h1b8f9f3_0.conda - sha256: 63af1a9e3284c7e4952364bafe7267e41e2d9d8bcc0e85a4ea4b0ec02d3693f6 - md5: 5dadfbc1a567fe6e475df4ce3148be09 + size: 89991 + timestamp: 1723817448345 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hfdf4475_0.conda + sha256: 791be3d30d8e37ec49bcc23eb8f1e1415d911a7c023fa93685f2ea485179e258 + md5: ed625b2e59dff82859c23dd24774156b depends: - __osx >=10.13 - - libzlib >=1.2.13,<2.0a0 - license: Unlicense + license: BSD-2-Clause + license_family: BSD purls: [] - size: 908643 - timestamp: 1718050720117 -- kind: conda - name: libsqlite - version: 3.46.0 - build: h2466b09_0 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.46.0-h2466b09_0.conda - sha256: 662bd7e0d63c5b8c31cca19b91649e798319b93568a2ba8d1375efb91eeb251b - md5: 951b0a3a463932e17414cd9f047fa03d + size: 76561 + timestamp: 1723817691512 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h99b78c6_0.conda + sha256: f7917de9117d3a5fe12a39e185c7ce424f8d5010a6f97b4333e8a1dcb2889d16 + md5: 7476305c35dd9acef48da8f754eedb40 + depends: + - __osx >=11.0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 69263 + timestamp: 1723817629767 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-h2466b09_0.conda + sha256: fc529fc82c7caf51202cc5cec5bb1c2e8d90edbac6d0a4602c966366efe3c7bf + md5: 74860100b2029e2523cf480804c76b9b depends: - ucrt >=10.0.20348.0 - vc >=14.2,<15 - vc14_runtime >=14.29.30139 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 88657 + timestamp: 1723861474602 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.47.0-hadc24fc_1.conda + sha256: 8a9aadf996a2399f65b679c6e7f29139d5059f699c63e6d7b50e20db10c00508 + md5: b6f02b52a174e612e89548f4663ce56a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 license: Unlicense purls: [] - size: 876677 - timestamp: 1718051113874 -- kind: conda - name: libsqlite - version: 3.46.0 - build: hde9e2c9_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.0-hde9e2c9_0.conda - sha256: daee3f68786231dad457d0dfde3f7f1f9a7f2018adabdbb864226775101341a8 - md5: 18aa975d2094c34aef978060ae7da7d8 + size: 875349 + timestamp: 1730208050020 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.47.0-h2f8c449_1.conda + sha256: a0f7381c867898a45018b1e5cf1aca68659d292d58252e8f489a4270b010fed8 + md5: af445c495253a871c3d809e1199bb12b depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<2.0a0 + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 license: Unlicense purls: [] - size: 865346 - timestamp: 1718050628718 -- kind: conda - name: libsqlite - version: 3.46.0 - build: hfb93653_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.46.0-hfb93653_0.conda - sha256: 73048f9cb8647d3d3bfe6021c0b7d663e12cffbe9b4f31bd081e713b0a9ad8f9 - md5: 12300188028c9bc02da965128b91b517 + size: 915300 + timestamp: 1730208101739 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.47.0-hbaaea75_1.conda + sha256: 5a96caa566c11e5a5ebdcdb86a0759a7fb27d3c5f42e6a0fd0d6023c1e935d9e + md5: 07a14fbe439eef078cc479deca321161 depends: - __osx >=11.0 - - libzlib >=1.2.13,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + license: Unlicense + purls: [] + size: 837683 + timestamp: 1730208293578 +- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.47.0-h2466b09_1.conda + sha256: 3342d6fe787f5830f7e8466d9c65c914bfd8d67220fb5673041b338cbba47afe + md5: 5b1f36012cc3d09c4eb9f24ad0e2c379 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 license: Unlicense purls: [] - size: 830198 - timestamp: 1718050644825 -- kind: conda - name: libuuid - version: 2.38.1 - build: h0b41bf4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + size: 892175 + timestamp: 1730208431651 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 md5: 40b61aab5c7ba9ff276c41cfffe6b80b depends: @@ -678,99 +569,60 @@ packages: purls: [] size: 33601 timestamp: 1680112270483 -- kind: conda - name: libxcrypt - version: 4.4.36 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c - md5: 5aa797f8787fe7a17d1b0821485b5adc +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 + md5: edb0dca6bc32e4f4789199455a1dbeb8 depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - purls: [] - size: 100393 - timestamp: 1702724383534 -- kind: conda - name: libzlib - version: 1.3.1 - build: h2466b09_1 - build_number: 1 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_1.conda - sha256: b13846a54a15243e15f96fec06b526d8155adc6a1ac2b6ed47a88f6a71a94b68 - md5: d4483ca8afc57ddf1f6dded53b36c17f - depends: - - ucrt >=10.0.20348.0 - - vc >=14.2,<15 - - vc14_runtime >=14.29.30139 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 constrains: - - zlib 1.3.1 *_1 + - zlib 1.3.1 *_2 license: Zlib license_family: Other purls: [] - size: 56186 - timestamp: 1716874730539 -- kind: conda - name: libzlib - version: 1.3.1 - build: h4ab18f5_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda - sha256: adf6096f98b537a11ae3729eaa642b0811478f0ea0402ca67b5108fe2cb0010d - md5: 57d7dc60e9325e3de37ff8dffd18e814 + size: 60963 + timestamp: 1727963148474 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda + sha256: 8412f96504fc5993a63edf1e211d042a1fd5b1d51dedec755d2058948fcced09 + md5: 003a54a4e32b02f7355b50a837e699da depends: - - libgcc-ng >=12 + - __osx >=10.13 constrains: - - zlib 1.3.1 *_1 + - zlib 1.3.1 *_2 license: Zlib license_family: Other purls: [] - size: 61574 - timestamp: 1716874187109 -- kind: conda - name: libzlib - version: 1.3.1 - build: h87427d6_1 - build_number: 1 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-h87427d6_1.conda - sha256: 80a62db652b1da0ccc100812a1d86e94f75028968991bfb17f9536f3aa72d91d - md5: b7575b5aa92108dcc9aaab0f05f2dbce + size: 57133 + timestamp: 1727963183990 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b + md5: 369964e85dc26bfe78f41399b366c435 depends: - - __osx >=10.13 + - __osx >=11.0 constrains: - - zlib 1.3.1 *_1 + - zlib 1.3.1 *_2 license: Zlib license_family: Other purls: [] - size: 57372 - timestamp: 1716874211519 -- kind: conda - name: libzlib - version: 1.3.1 - build: hfb2fe0b_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-hfb2fe0b_1.conda - sha256: c34365dd37b0eab27b9693af32a1f7f284955517c2cc91f1b88a7ef4738ff03e - md5: 636077128927cf79fd933276dc3aed47 + size: 46438 + timestamp: 1727963202283 +- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + sha256: ba945c6493449bed0e6e29883c4943817f7c79cbff52b83360f7b341277c6402 + md5: 41fbfac52c601159df6c01f875de31b9 depends: - - __osx >=11.0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 constrains: - - zlib 1.3.1 *_1 + - zlib 1.3.1 *_2 license: Zlib license_family: Other purls: [] - size: 46921 - timestamp: 1716874262512 -- kind: pypi + size: 55476 + timestamp: 1727963768015 +- pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl name: markdown-it-py version: 3.0.0 - url: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl sha256: 355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 requires_dist: - mdurl~=0.1 @@ -799,64 +651,37 @@ packages: - pytest-cov ; extra == 'testing' - pytest-regressions ; extra == 'testing' requires_python: '>=3.8' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: markupsafe - version: 2.1.5 - url: https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 - requires_python: '>=3.7' -- kind: pypi + version: 3.0.2 + sha256: 15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl name: markupsafe - version: 2.1.5 - url: https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl - sha256: 823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb - requires_python: '>=3.7' -- kind: pypi + version: 3.0.2 + sha256: e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl name: markupsafe - version: 2.1.5 - url: https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl - sha256: 3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 - requires_python: '>=3.7' -- kind: pypi + version: 3.0.2 + sha256: f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl name: markupsafe - version: 2.1.5 - url: https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl - sha256: 8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 - requires_python: '>=3.7' -- kind: pypi + version: 3.0.2 + sha256: ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl name: mdurl version: 0.1.2 - url: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 requires_python: '>=3.7' -- kind: pypi +- pypi: ./minimal-project name: minimal-project version: '0.1' - path: ./minimal-project sha256: 590cda021c427ceaff15b4aa13245e6fd493b6ffb759c0a017f5d1b485b75c57 editable: true -- kind: conda - name: ncurses - version: '6.5' - build: h7bae524_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda - sha256: 27d0b9ff78ad46e1f3a6c96c479ab44beda5f96def88e2fe626e0a49429d8afc - md5: cb2b0ea909b97b3d70cd3921d1445e1a - depends: - - __osx >=11.0 - license: X11 AND BSD-3-Clause - purls: [] - size: 802321 - timestamp: 1724658775723 -- kind: conda - name: ncurses - version: '6.5' - build: he02047a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda sha256: 6a1d5d8634c1a07913f1c525db6455918cbc589d745fac46d9d6e30340c8731a md5: 70caf8bb6cf39a0b6b7efc885f51c0fe depends: @@ -866,13 +691,7 @@ packages: purls: [] size: 889086 timestamp: 1724658547447 -- kind: conda - name: ncurses - version: '6.5' - build: hf036a51_1 - build_number: 1 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-hf036a51_1.conda +- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-hf036a51_1.conda sha256: b0b3180039ef19502525a2abd5833c00f9624af830fd391f851934d57bffb9af md5: e102bbf8a6ceeaf429deab8032fc8977 depends: @@ -881,87 +700,70 @@ packages: purls: [] size: 822066 timestamp: 1724658603042 -- kind: conda - name: openssl - version: 3.3.1 - build: h2466b09_3 - build_number: 3 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/openssl-3.3.1-h2466b09_3.conda - sha256: 76a10564ca450f56495cff06bf60bdf0fe42e6ef7a20469276894d4ac7c0140a - md5: c6ebd3a1a2b393e040ca71c9f9ef8d97 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda + sha256: 27d0b9ff78ad46e1f3a6c96c479ab44beda5f96def88e2fe626e0a49429d8afc + md5: cb2b0ea909b97b3d70cd3921d1445e1a depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + purls: [] + size: 802321 + timestamp: 1724658775723 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.0-hb9d3cd8_0.conda + sha256: 814b9dff1847b132c676ee6cc1a8cb2d427320779b93e1b6d76552275c128705 + md5: 23cc74f77eb99315c0360ec3533147a9 + depends: + - __glibc >=2.17,<3.0.a0 - ca-certificates - - ucrt >=10.0.20348.0 - - vc >=14.2,<15 - - vc14_runtime >=14.29.30139 + - libgcc >=13 license: Apache-2.0 license_family: Apache purls: [] - size: 8362062 - timestamp: 1724404916759 -- kind: conda - name: openssl - version: 3.3.1 - build: h8359307_3 - build_number: 3 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.1-h8359307_3.conda - sha256: 9dd1ee7a8c21ff4fcbb98e9d0be0e83e5daf8a555c73589ad9e3046966b72e5e - md5: 644904d696d83c0ac78d594e0cf09f66 + size: 2947466 + timestamp: 1731377666602 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.0-hd471939_0.conda + sha256: ba7e068ed469d6625e32ae60e6ad893e655b6695280dadf7e065ed0b6f3b885c + md5: ec99d2ce0b3033a75cbad01bbc7c5b71 depends: - - __osx >=11.0 + - __osx >=10.13 - ca-certificates license: Apache-2.0 license_family: Apache purls: [] - size: 2888820 - timestamp: 1724402552318 -- kind: conda - name: openssl - version: 3.3.1 - build: hb9d3cd8_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.1-hb9d3cd8_3.conda - sha256: 9e27441b273a7cf9071f6e88ba9ad565d926d8083b154c64a74b99fba167b137 - md5: 6c566a46baae794daf34775d41eb180a + size: 2590683 + timestamp: 1731378034404 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.0-h39f12f2_0.conda + sha256: bd1d58ced46e75efa3b842c61642fd12272c69e9fe4d7261078bc082153a1d53 + md5: df307bbc703324722df0293c9ca2e418 depends: - - __glibc >=2.17,<3.0.a0 + - __osx >=11.0 - ca-certificates - - libgcc-ng >=13 license: Apache-2.0 license_family: Apache purls: [] - size: 2892042 - timestamp: 1724402701933 -- kind: conda - name: openssl - version: 3.3.1 - build: hd23fc13_3 - build_number: 3 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.1-hd23fc13_3.conda - sha256: 63921822fbb66337e0fd50b2a07412583fbe7783bc92c663bdf93c9a09026fdc - md5: ad8c8c9556a701817bd1aca75a302e96 + size: 2935176 + timestamp: 1731377561525 +- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.0-h2466b09_0.conda + sha256: e03045a0837e01ff5c75e9273a572553e7522290799807f918c917a9826a6484 + md5: d0d805d9b5524a14efb51b3bff965e83 depends: - - __osx >=10.13 - ca-certificates + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 license: Apache-2.0 license_family: Apache purls: [] - size: 2549881 - timestamp: 1724403015051 -- kind: pypi + size: 8491156 + timestamp: 1731379715927 +- pypi: https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl name: packaging - version: '24.1' - url: https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl - sha256: 5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 + version: '24.2' + sha256: 09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 requires_python: '>=3.8' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl name: pluggy version: 1.5.0 - url: https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl sha256: 44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 requires_dist: - pre-commit ; extra == 'dev' @@ -969,25 +771,23 @@ packages: - pytest ; extra == 'testing' - pytest-benchmark ; extra == 'testing' requires_python: '>=3.8' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl name: pygments version: 2.18.0 - url: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl sha256: b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a requires_dist: - colorama>=0.4.6 ; extra == 'windows-terminal' requires_python: '>=3.8' -- kind: pypi +- pypi: git+https://github.com/pytest-dev/pytest.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3 name: pytest - version: 8.4.0.dev54+gc947145fb - url: git+https://github.com/pytest-dev/pytest.git@c947145fbb4aeec810a259b19f70fcb52fd53ad4 + version: 8.4.0.dev250+g9d4f36d87 requires_dist: + - colorama ; sys_platform == 'win32' + - exceptiongroup>=1.0.0rc8 ; python_full_version < '3.11' - iniconfig - packaging - - pluggy<2,>=1.5 - - exceptiongroup>=1.0.0rc8 ; python_full_version < '3.11' + - pluggy>=1.5,<2 - tomli>=1 ; python_full_version < '3.11' - - colorama ; sys_platform == 'win32' - argcomplete ; extra == 'dev' - attrs>=19.2 ; extra == 'dev' - hypothesis>=3.56 ; extra == 'dev' @@ -996,127 +796,147 @@ packages: - requests ; extra == 'dev' - setuptools ; extra == 'dev' - xmlschema ; extra == 'dev' - requires_python: '>=3.8' -- kind: conda - name: python - version: 3.12.5 - build: h2ad013b_0_cpython - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.5-h2ad013b_0_cpython.conda - sha256: e2aad83838988725d4ffba4e9717b9328054fd18a668cff3377e0c50f109e8bd - md5: 9c56c4df45f6571b13111d8df2448692 + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.0-h9ebbce0_101_cp313.conda + build_number: 101 + sha256: 66a7997b24b2dca636df11402abec7bd2199ddf6971eb47a3ee6b1d27d4faee9 + md5: f4fea9d5bb3f2e61a39950a7ab70ee4e depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.6.2,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - - libgcc-ng >=12 - - libnsl >=2.0.1,<2.1.0a0 - - libsqlite >=3.46.0,<4.0a0 + - libgcc >=13 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.47.0,<4.0a0 - libuuid >=2.38.1,<3.0a0 - - libxcrypt >=4.4.36 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.3.1,<4.0a0 + - openssl >=3.4.0,<4.0a0 + - python_abi 3.13.* *_cp313 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 license: Python-2.0 purls: [] - size: 31663253 - timestamp: 1723143721353 -- kind: conda - name: python - version: 3.12.5 - build: h30c5eda_0_cpython - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.5-h30c5eda_0_cpython.conda - sha256: 1319e918fb54c9491832a9731cad00235a76f61c6f9b23fc0f70cdfb74c950ea - md5: 5e315581e2948dfe3bcac306540e9803 + size: 33054218 + timestamp: 1732736838043 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.0-h3a8ca6c_101_cp313.conda + build_number: 101 + sha256: c8b23bbdcd0e4f24fed2028cba20bd81325a4220439c1b8e6b06694f16642a2c + md5: 0acea4c3eee2454fd642d1a4eafa2943 depends: - - __osx >=11.0 + - __osx >=10.13 - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.2,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - - libsqlite >=3.46.0,<4.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.47.0,<4.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.3.1,<4.0a0 + - openssl >=3.4.0,<4.0a0 + - python_abi 3.13.* *_cp313 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 license: Python-2.0 purls: [] - size: 12926356 - timestamp: 1723142203193 -- kind: conda - name: python - version: 3.12.5 - build: h37a9e06_0_cpython - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.5-h37a9e06_0_cpython.conda - sha256: c0f39e625b2fd65f70a9cc086fe4b25cc72228453dbbcd92cd5d140d080e38c5 - md5: 517cb4e16466f8d96ba2a72897d14c48 + size: 13941305 + timestamp: 1732736712289 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.0-hbbac1ca_101_cp313.conda + build_number: 101 + sha256: 742544a4cf9a10cf2c16d35d96fb696c27d58b9df0cc29fbef5629283aeca941 + md5: e972e146a1e0cfb1f26da42cb6f6648c depends: - - __osx >=10.13 + - __osx >=11.0 - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.2,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - - libsqlite >=3.46.0,<4.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.47.0,<4.0a0 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.3.1,<4.0a0 + - openssl >=3.4.0,<4.0a0 + - python_abi 3.13.* *_cp313 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 license: Python-2.0 purls: [] - size: 12173272 - timestamp: 1723142761765 -- kind: conda - name: python - version: 3.12.5 - build: h889d299_0_cpython - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/python-3.12.5-h889d299_0_cpython.conda - sha256: 4cef304eb8877fd3094c14b57097ccc1b817b4afbf2223dd45d2b61e44064740 - md5: db056d8b140ab2edd56a2f9bdb203dcd + size: 12806496 + timestamp: 1732735488999 +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.0-hf5aa216_101_cp313.conda + build_number: 101 + sha256: b8eba57bd86c7890b27e67b477b52b5bd547946c354f29b9dbbc70ad83f2863b + md5: 158d6077a635cf0c0c23bec3955a4833 depends: - bzip2 >=1.0.8,<2.0a0 - - libexpat >=2.6.2,<3.0a0 + - libexpat >=2.6.4,<3.0a0 - libffi >=3.4,<4.0a0 - - libsqlite >=3.46.0,<4.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.47.0,<4.0a0 - libzlib >=1.3.1,<2.0a0 - - openssl >=3.3.1,<4.0a0 + - openssl >=3.4.0,<4.0a0 + - python_abi 3.13.* *_cp313 - tk >=8.6.13,<8.7.0a0 - tzdata - ucrt >=10.0.20348.0 - vc >=14.2,<15 - vc14_runtime >=14.29.30139 - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.12.* *_cp312 license: Python-2.0 purls: [] - size: 15897752 - timestamp: 1723141830317 -- kind: conda - name: readline - version: '8.2' - build: h8228510_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + size: 16697406 + timestamp: 1732734725404 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.13-5_cp313.conda + build_number: 5 + sha256: 438225b241c5f9bddae6f0178a97f5870a89ecf927dfca54753e689907331442 + md5: 381bbd2a92c863f640a55b6ff3c35161 + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6217 + timestamp: 1723823393322 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.13-5_cp313.conda + build_number: 5 + sha256: 075ad768648e88b78d2a94099563b43d3082e7c35979f457164f26d1079b7b5c + md5: 927a2186f1f997ac018d67c4eece90a6 + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6291 + timestamp: 1723823083064 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.13-5_cp313.conda + build_number: 5 + sha256: 4437198eae80310f40b23ae2f8a9e0a7e5c2b9ae411a8621eb03d87273666199 + md5: b8e82d0a5c1664638f87f63cc5d241fb + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6322 + timestamp: 1723823058879 +- conda: https://conda.anaconda.org/conda-forge/win-64/python_abi-3.13-5_cp313.conda + build_number: 5 + sha256: 0c12cc1b84962444002c699ed21e815fb9f686f950d734332a1b74d07db97756 + md5: 44b4fe6f22b57103afb2299935c8b68e + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6716 + timestamp: 1723823166911 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 md5: 47d31b792659ce70f470b5c82fdfb7a4 depends: @@ -1127,68 +947,59 @@ packages: purls: [] size: 281456 timestamp: 1679532220005 -- kind: conda - name: readline - version: '8.2' - build: h92ec313_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda - sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 - md5: 8cbb776a2f641b943d413b3e19df71f4 +- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda + sha256: 41e7d30a097d9b060037f0c6a2b1d4c4ae7e942c06c943d23f9d481548478568 + md5: f17f77f2acf4d344734bda76829ce14e depends: - ncurses >=6.3,<7.0a0 license: GPL-3.0-only license_family: GPL purls: [] - size: 250351 - timestamp: 1679532511311 -- kind: conda - name: readline - version: '8.2' - build: h9e318b2_1 - build_number: 1 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda - sha256: 41e7d30a097d9b060037f0c6a2b1d4c4ae7e942c06c943d23f9d481548478568 - md5: f17f77f2acf4d344734bda76829ce14e + size: 255870 + timestamp: 1679532707590 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 + md5: 8cbb776a2f641b943d413b3e19df71f4 depends: - ncurses >=6.3,<7.0a0 license: GPL-3.0-only license_family: GPL purls: [] - size: 255870 - timestamp: 1679532707590 -- kind: pypi + size: 250351 + timestamp: 1679532511311 +- pypi: git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 name: requests version: 2.31.0 - url: git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 requires_dist: - - charset-normalizer<4,>=2 - - idna<4,>=2.5 - - urllib3<3,>=1.21.1 + - charset-normalizer>=2,<4 + - idna>=2.5,<4 + - urllib3>=1.21.1,<3 - certifi>=2017.4.17 - - pysocks!=1.5.7,>=1.5.6 ; extra == 'socks' - - chardet<6,>=3.0.2 ; extra == 'use-chardet-on-py3' + - pysocks>=1.5.6,!=1.5.7 ; extra == 'socks' + - chardet>=3.0.2,<6 ; extra == 'use-chardet-on-py3' requires_python: '>=3.7' -- kind: pypi +- pypi: https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl name: rich - version: 13.8.0 - url: https://files.pythonhosted.org/packages/c7/d9/c2a126eeae791e90ea099d05cb0515feea3688474b978343f3cdcfe04523/rich-13.8.0-py3-none-any.whl - sha256: 2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc + version: 13.9.4 + sha256: 6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90 requires_dist: - ipywidgets>=7.5.1,<9 ; extra == 'jupyter' - markdown-it-py>=2.2.0 - pygments>=2.13.0,<3.0.0 - - typing-extensions>=4.0.0,<5.0 ; python_full_version < '3.9' - requires_python: '>=3.7.0' -- kind: conda - name: tk - version: 8.6.13 - build: h1abcd95_1 - build_number: 1 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda + - typing-extensions>=4.0.0,<5.0 ; python_full_version < '3.11' + requires_python: '>=3.8.0' +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e + md5: d453b98d9c83e71da0741bb0ff4d76bc + depends: + - libgcc-ng >=12 + - libzlib >=1.2.13,<2.0.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3318875 + timestamp: 1699202167581 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda sha256: 30412b2e9de4ff82d8c2a7e5d06a15f4f4fef1809a72138b6ccb53a33b26faf5 md5: bf830ba5afc507c6232d4ef0fb1a882d depends: @@ -1198,13 +1009,7 @@ packages: purls: [] size: 3270220 timestamp: 1699202389792 -- kind: conda - name: tk - version: 8.6.13 - build: h5083fa2_1 - build_number: 1 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 md5: b50a57ba89c32b62428b71a875291c9b depends: @@ -1214,13 +1019,7 @@ packages: purls: [] size: 3145523 timestamp: 1699202432999 -- kind: conda - name: tk - version: 8.6.13 - build: h5226925_1 - build_number: 1 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda +- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda sha256: 2c4e914f521ccb2718946645108c9bd3fc3216ba69aea20c2c3cedbd8db32bb1 md5: fc048363eb8f03cd1737600a5d08aafe depends: @@ -1232,131 +1031,76 @@ packages: purls: [] size: 3503410 timestamp: 1699202577803 -- kind: conda - name: tk - version: 8.6.13 - build: noxft_h4845f30_101 - build_number: 101 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e - md5: d453b98d9c83e71da0741bb0ff4d76bc - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<2.0.0a0 - license: TCL - license_family: BSD - purls: [] - size: 3318875 - timestamp: 1699202167581 -- kind: conda - name: tzdata - version: 2024a - build: h8827d51_1 - build_number: 1 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda - sha256: 7d21c95f61319dba9209ca17d1935e6128af4235a67ee4e57a00908a1450081e - md5: 8bfdead4e0fff0383ae4c9c50d0531bd +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024b-hc8b5060_0.conda + sha256: 4fde5c3008bf5d2db82f2b50204464314cc3c91c1d953652f7bd01d9e52aefdf + md5: 8ac3367aafb1cc0a068483c580af8015 license: LicenseRef-Public-Domain purls: [] - size: 124164 - timestamp: 1724736371498 -- kind: conda - name: ucrt - version: 10.0.22621.0 - build: h57928b3_0 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_0.tar.bz2 - sha256: f29cdaf8712008f6b419b8b1a403923b00ab2504bfe0fb2ba8eb60e72d4f14c6 - md5: 72608f6cd3e5898229c3ea16deb1ac43 + size: 122354 + timestamp: 1728047496079 +- conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda + sha256: db8dead3dd30fb1a032737554ce91e2819b43496a0db09927edf01c32b577450 + md5: 6797b005cd0f439c4c5c9ac565783700 constrains: - vs2015_runtime >=14.29.30037 - license: LicenseRef-Proprietary - license_family: PROPRIETARY + license: LicenseRef-MicrosoftWindowsSDK10 purls: [] - size: 1283972 - timestamp: 1666630199266 -- kind: pypi + size: 559710 + timestamp: 1728377334097 +- pypi: https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl name: urllib3 - version: 2.2.2 - url: https://files.pythonhosted.org/packages/ca/1c/89ffc63a9605b583d5df2be791a27bc1a42b7c32bab68d3c8f2f73a98cd4/urllib3-2.2.2-py3-none-any.whl - sha256: a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 + version: 2.2.3 + sha256: ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac requires_dist: - brotli>=1.0.9 ; platform_python_implementation == 'CPython' and extra == 'brotli' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'brotli' - - h2<5,>=4 ; extra == 'h2' - - pysocks!=1.5.7,<2.0,>=1.5.6 ; extra == 'socks' + - h2>=4,<5 ; extra == 'h2' + - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' - zstandard>=0.18.0 ; extra == 'zstd' requires_python: '>=3.8' -- kind: conda - name: vc - version: '14.3' - build: h8a93ad2_20 - build_number: 20 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h8a93ad2_20.conda - sha256: 23ac5feb15a9adf3ab2b8c4dcd63650f8b7ae860c5ceb073e49cf71d203eddef - md5: 8558f367e1d7700554f7cdb823c46faf +- conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-ha32ba9b_23.conda + sha256: 986ddaf8feec2904eac9535a7ddb7acda1a1dfb9482088fdb8129f1595181663 + md5: 7c10ec3158d1eb4ddff7007c9101adb0 depends: - - vc14_runtime >=14.40.33810 + - vc14_runtime >=14.38.33135 track_features: - vc14 license: BSD-3-Clause license_family: BSD purls: [] - size: 17391 - timestamp: 1717709040616 -- kind: conda - name: vc14_runtime - version: 14.40.33810 - build: hcc2c482_20 - build_number: 20 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.40.33810-hcc2c482_20.conda - sha256: bba8daa6f78b26b48fb7e1377eb52160e25495710bf53146c5f405bd50565982 - md5: ad33c7cd933d69b9dee0f48317cdf137 + size: 17479 + timestamp: 1731710827215 +- conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.42.34433-he29a5d6_23.conda + sha256: c483b090c4251a260aba6ff3e83a307bcfb5fb24ad7ced872ab5d02971bd3a49 + md5: 32b37d0cfa80da34548501cdc913a832 depends: - ucrt >=10.0.20348.0 constrains: - - vs2015_runtime 14.40.33810.* *_20 - license: LicenseRef-ProprietaryMicrosoft + - vs2015_runtime 14.42.34433.* *_23 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime license_family: Proprietary purls: [] - size: 751028 - timestamp: 1724712684919 -- kind: conda - name: vs2015_runtime - version: 14.40.33810 - build: h3bf8584_20 - build_number: 20 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.40.33810-h3bf8584_20.conda - sha256: 0c2803f7a788c51f28235a7228dc2ab3f107b4b16ab0845a3e595c8c51e50a7a - md5: c21f1b4a3a30bbc3ef35a50957578e0e + size: 754247 + timestamp: 1731710681163 +- conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.42.34433-hdffcdeb_23.conda + sha256: 568ce8151eaae256f1cef752fc78651ad7a86ff05153cc7a4740b52ae6536118 + md5: 5c176975ca2b8366abad3c97b3cd1e83 depends: - - vc14_runtime >=14.40.33810 + - vc14_runtime >=14.42.34433 license: BSD-3-Clause license_family: BSD purls: [] - size: 17395 - timestamp: 1717709043353 -- kind: pypi + size: 17572 + timestamp: 1731710685291 +- pypi: https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl name: werkzeug - version: 3.0.4 - url: https://files.pythonhosted.org/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl - sha256: 02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c + version: 3.1.3 + sha256: 54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e requires_dist: - markupsafe>=2.1.1 - watchdog>=2.3 ; extra == 'watchdog' - requires_python: '>=3.8' -- kind: conda - name: xz - version: 5.2.6 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 md5: 2161070d867d1b1204ea749c8eec4ef0 depends: @@ -1365,36 +1109,21 @@ packages: purls: [] size: 418368 timestamp: 1660346797927 -- kind: conda - name: xz - version: 5.2.6 - build: h57fd34a_0 - subdir: osx-arm64 - url: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 - sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec - md5: 39c6b54e94014701dd157f4f576ed211 - license: LGPL-2.1 and GPL-2.0 - purls: [] - size: 235693 - timestamp: 1660346961024 -- kind: conda - name: xz - version: 5.2.6 - build: h775f41a_0 - subdir: osx-64 - url: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 sha256: eb09823f34cc2dd663c0ec4ab13f246f45dcd52e5b8c47b9864361de5204a1c8 md5: a72f9d4ea13d55d745ff1ed594747f10 license: LGPL-2.1 and GPL-2.0 purls: [] size: 238119 timestamp: 1660346964847 -- kind: conda - name: xz - version: 5.2.6 - build: h8d14728_0 - subdir: win-64 - url: https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec + md5: 39c6b54e94014701dd157f4f576ed211 + license: LGPL-2.1 and GPL-2.0 + purls: [] + size: 235693 + timestamp: 1660346961024 +- conda: https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2 sha256: 54d9778f75a02723784dc63aff4126ff6e6749ba21d11a6d03c1f4775f269fe0 md5: 515d77642eaa3639413c6b1bc3f94219 depends: diff --git a/examples/pypi-source-deps/pixi.toml b/examples/pypi-source-deps/pixi.toml index c3d949727..71f46e0d6 100644 --- a/examples/pypi-source-deps/pixi.toml +++ b/examples/pypi-source-deps/pixi.toml @@ -23,7 +23,7 @@ rich = "~=13.7" # With https flask = { git = "https://github.com/pallets/flask" } -requests = { git = "https://github.com/psf/requests.git", rev = "0106aced5faa299e6ede89d1230bd6784f2c3660" } +requests = { git = "https://github.com/psf/requests.git", rev = "147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4" } # TODO: will support later -> or use branch = '' or tag = '' to specify a branch or tag # You can also directly add a source dependency from file diff --git a/src/cli/project/export/snapshots/pixi__cli__project__export__conda_environment__tests__test_export_conda_env_yaml_with_source_editable.snap b/src/cli/project/export/snapshots/pixi__cli__project__export__conda_environment__tests__test_export_conda_env_yaml_with_source_editable.snap index 49f0171f5..ed31217c2 100644 --- a/src/cli/project/export/snapshots/pixi__cli__project__export__conda_environment__tests__test_export_conda_env_yaml_with_source_editable.snap +++ b/src/cli/project/export/snapshots/pixi__cli__project__export__conda_environment__tests__test_export_conda_env_yaml_with_source_editable.snap @@ -12,7 +12,7 @@ dependencies: - pip: - rich~=13.7 - flask @ git+https://github.com/pallets/flask - - requests @ git+https://github.com/psf/requests.git@0106aced5faa299e6ede89d1230bd6784f2c3660 + - requests @ git+https://github.com/psf/requests.git@147c8511ddbfa5e8f71bbf5c18ede0c4ceb3bba4 - -e ./minimal-project - click @ https://github.com/pallets/click/releases/download/8.1.7/click-8.1.7-py3-none-any.whl - pytest @ git+https://github.com/pytest-dev/pytest.git diff --git a/src/install_pypi/conversions.rs b/src/install_pypi/conversions.rs index 6084f4295..2e7750088 100644 --- a/src/install_pypi/conversions.rs +++ b/src/install_pypi/conversions.rs @@ -120,7 +120,6 @@ pub fn convert_to_dist( filename_decoded.as_ref(), pkg.requires_python.clone(), )?; - // Recreate the filename from the extracted last component // If this errors this is not a valid wheel filename // and we should consider it a sdist diff --git a/src/install_pypi/mod.rs b/src/install_pypi/mod.rs index 21c7ac08f..284e7c59d 100644 --- a/src/install_pypi/mod.rs +++ b/src/install_pypi/mod.rs @@ -295,7 +295,7 @@ pub async fn update_python_distributions( } // Download, build, and unzip any missing distributions. - let wheels = if remote.is_empty() { + let remote_dists = if remote.is_empty() { Vec::new() } else { let start = std::time::Instant::now(); @@ -328,7 +328,7 @@ pub async fn update_python_distributions( ) .with_reporter(UvReporter::new(options)); - let wheels = preparer + let remote_dists = preparer .prepare( remote.iter().map(|(d, _)| d.clone()).collect(), &uv_context.in_flight, @@ -337,17 +337,17 @@ pub async fn update_python_distributions( .into_diagnostic() .context("Failed to prepare distributions")?; - let s = if wheels.len() == 1 { "" } else { "s" }; + let s = if remote_dists.len() == 1 { "" } else { "s" }; tracing::info!( "{}", format!( "Prepared {} in {}", - format!("{} package{}", wheels.len(), s), + format!("{} package{}", remote_dists.len(), s), elapsed(start.elapsed()) ) ); - wheels + remote_dists }; // Remove any unnecessary packages. @@ -408,8 +408,12 @@ pub async fn update_python_distributions( } // Install the resolved distributions. - let local_iter = local.iter().map(|(d, _)| d.clone()); - let wheels = wheels.into_iter().chain(local_iter).collect::>(); + // At this point we have all the wheels we need to install available to link locally + let local_dists = local.iter().map(|(d, _)| d.clone()); + let all_dists = remote_dists + .into_iter() + .chain(local_dists) + .collect::>(); // Figure what wheels needed to be re-installed because of an installer mismatch // we want to handle these somewhat differently and warn the user about them @@ -427,7 +431,7 @@ pub async fn update_python_distributions( // Verify if pypi wheels will override existing conda packages // and warn if they are if let Ok(Some(clobber_packages)) = - pypi_conda_clobber.clobber_on_installation(wheels.clone(), &venv) + pypi_conda_clobber.clobber_on_installation(all_dists.clone(), &venv) { let packages_names = clobber_packages.iter().join(", "); @@ -452,27 +456,27 @@ pub async fn update_python_distributions( } let options = UvReporterOptions::new() - .with_length(wheels.len() as u64) - .with_capacity(wheels.len() + 30) - .with_starting_tasks(wheels.iter().map(|d| format!("{}", d.name()))) + .with_length(all_dists.len() as u64) + .with_capacity(all_dists.len() + 30) + .with_starting_tasks(all_dists.iter().map(|d| format!("{}", d.name()))) .with_top_level_message("Installing distributions"); - if !wheels.is_empty() { + if !all_dists.is_empty() { let start = std::time::Instant::now(); uv_installer::Installer::new(&venv) .with_link_mode(LinkMode::default()) .with_installer_name(Some(consts::PIXI_UV_INSTALLER.to_string())) .with_reporter(UvReporter::new(options)) - .install(wheels.clone()) + .install(all_dists.clone()) .await .unwrap(); - let s = if wheels.len() == 1 { "" } else { "s" }; + let s = if all_dists.len() == 1 { "" } else { "s" }; tracing::info!( "{}", format!( "Installed {} in {}", - format!("{} package{}", wheels.len(), s), + format!("{} package{}", all_dists.len(), s), elapsed(start.elapsed()) ) ); diff --git a/src/install_pypi/plan.rs b/src/install_pypi/plan/mod.rs similarity index 77% rename from src/install_pypi/plan.rs rename to src/install_pypi/plan/mod.rs index d36f53d68..f9bd3e06e 100644 --- a/src/install_pypi/plan.rs +++ b/src/install_pypi/plan/mod.rs @@ -19,6 +19,9 @@ use super::{ utils::{check_url_freshness, strip_direct_scheme}, }; +#[cfg(test)] +mod test; + #[derive(Debug)] pub enum InstallReason { /// Reinstall a package from the local cache, will link from the cache @@ -116,8 +119,13 @@ pub(crate) enum NeedReinstall { SourceDirectoryNewerThanCache, /// Url file parse error UnableToParseFileUrl { url: String }, + /// Unable to convert locked directory to a url + UnableToConvertLockedPath { path: String }, /// The editable status of the installed wheel changed with regards to the locked version - EditableStatusChanged { is_now_editable: bool }, + EditableStatusChanged { + locked_editable: bool, + installed_editable: bool, + }, /// Somehow unable to parse the installed dist url UnableToParseInstalledDistUrl { url: String }, /// Archive is newer than the cache @@ -132,14 +140,19 @@ pub(crate) enum NeedReinstall { /// Unable to parse the installed git url UnableToParseGitUrl { url: String }, /// Unable to get the installed dist metadata, something is definitely broken - UnableToGetInstalledDistMetadata, + UnableToGetInstalledDistMetadata { cause: String }, /// The requires-python is different than the installed version RequiredPythonChanged { - installed_python_version: uv_pep440::VersionSpecifiers, + installed_python_require: uv_pep440::VersionSpecifiers, locked_python_version: uv_pep440::Version, }, /// Re-installing because of an installer mismatch, but we are managing the package InstallerMismatch { previous_installer: String }, + /// The installed url does not match the locked url + UrlMismatch { + installed_url: String, + locked_url: Option, + }, } impl std::fmt::Display for NeedReinstall { @@ -160,11 +173,14 @@ impl std::fmt::Display for NeedReinstall { NeedReinstall::UnableToParseFileUrl { url } => { write!(f, "Unable to parse file url: {}", url) } - NeedReinstall::EditableStatusChanged { is_now_editable } => { + NeedReinstall::EditableStatusChanged { + locked_editable, + installed_editable, + } => { write!( f, - "Editable status changed, editable status is: {}", - is_now_editable + "Editable status changed, editable status is: {} installed editable is: {}", + locked_editable, installed_editable ) } NeedReinstall::UnableToParseInstalledDistUrl { url } => { @@ -185,11 +201,11 @@ impl std::fmt::Display for NeedReinstall { NeedReinstall::UnableToParseGitUrl { url } => { write!(f, "Unable to parse git url: {}", url) } - NeedReinstall::UnableToGetInstalledDistMetadata => { - write!(f, "Unable to get installed dist metadata") + NeedReinstall::UnableToGetInstalledDistMetadata { cause } => { + write!(f, "Unable to get installed dist metadata: {}", cause) } NeedReinstall::RequiredPythonChanged { - installed_python_version, + installed_python_require: installed_python_version, locked_python_version, } => { write!( @@ -205,6 +221,18 @@ impl std::fmt::Display for NeedReinstall { previous_installer ) } + NeedReinstall::UrlMismatch { + installed_url, + locked_url, + } => write!( + f, + "Installed url {} does not match locked url {}", + installed_url, + locked_url.clone().unwrap_or_else(|| "None".to_string()) + ), + NeedReinstall::UnableToConvertLockedPath { path } => { + write!(f, "Unable to convert locked path to url: {}", path) + } } } } @@ -221,6 +249,7 @@ fn need_reinstall( installed: &InstalledDist, locked: &PypiPackageData, python_version: &uv_pep440::Version, + lock_file_dir: &Path, ) -> miette::Result { // Check if the installed version is the same as the required version match installed { @@ -259,14 +288,50 @@ fn need_reinstall( let result = Url::parse(&url); match result { Ok(url) => { + // Convert the locked location, which can be a path or a url, to a url + let locked_url = match &locked.location { + // Fine if it is already a url + UrlOrPath::Url(url) => url.clone(), + // Do some path mangling if it is actually a path to get it into a url + UrlOrPath::Path(path) => { + let path = PathBuf::from(path.as_str()); + // Because the path we are comparing to is absolute we need to convert + let path = if path.is_absolute() { + path + } else { + // Relative paths will be relative to the lock file directory + lock_file_dir.join(path) + }; + // Okay, now convert to a file path, if we cant do that we need to re-install + match Url::from_file_path(path.clone()) { + Ok(url) => url, + Err(_) => { + return Ok(ValidateCurrentInstall::Reinstall( + NeedReinstall::UnableToConvertLockedPath { + path: path.display().to_string(), + }, + )); + } + } + } + }; + // Check if the urls are different - if Some(&url) == locked.location.as_url() { - // Check cache freshness + if url == locked_url { + // Okay so these are the same, but we need to check if the cache is newer + // than the source directory if !check_url_freshness(&url, installed)? { return Ok(ValidateCurrentInstall::Reinstall( NeedReinstall::SourceDirectoryNewerThanCache, )); } + } else { + return Ok(ValidateCurrentInstall::Reinstall( + NeedReinstall::UrlMismatch { + installed_url: url.to_string(), + locked_url: locked.location.as_url().map(|u| u.to_string()), + }, + )); } } Err(_) => { @@ -279,7 +344,8 @@ fn need_reinstall( if dir_info.editable.unwrap_or_default() != locked.editable { return Ok(ValidateCurrentInstall::Reinstall( NeedReinstall::EditableStatusChanged { - is_now_editable: dir_info.editable.unwrap_or_default(), + locked_editable: locked.editable, + installed_editable: dir_info.editable.unwrap_or_default(), }, )); } @@ -321,6 +387,13 @@ fn need_reinstall( NeedReinstall::ArchiveDistNewerThanCache, )); } + } else { + return Ok(ValidateCurrentInstall::Reinstall( + NeedReinstall::UrlMismatch { + installed_url: installed_url.to_string(), + locked_url: locked.location.as_url().map(|u| u.to_string()), + }, + )); } } uv_pypi_types::DirectUrl::VcsUrl { @@ -328,8 +401,14 @@ fn need_reinstall( vcs_info, subdirectory: _, } => { - let url = Url::parse(&url).into_diagnostic()?; - let git_url = match &locked.location { + // Check if the installed git url is the same as the locked git url + // if this fails, it should be an error, because then installed url is not a git url + let installed_git_url = + ParsedGitUrl::try_from(Url::parse(url.as_str()).into_diagnostic()?) + .into_diagnostic()?; + // Try to parse the locked git url, this can be any url, so this may fail + // in practice it always seems to succeed, even with a non-git url + let locked_git_url = match &locked.location { UrlOrPath::Url(url) => ParsedGitUrl::try_from(url.clone()), UrlOrPath::Path(_path) => { // Previously @@ -338,18 +417,27 @@ fn need_reinstall( )); } }; - match git_url { - Ok(git) => { - // Check the repository base url - if git.url.repository() != &url - // Check the sha from the direct_url.json and the required sha - // Use the uv git url to get the sha - || vcs_info.commit_id != git.url.precise().map(|p| p.to_string()) + match locked_git_url { + Ok(locked_git_url) => { + // Check the repository base url with the locked url + if locked_git_url.url.repository() != installed_git_url.url.repository() { + // This happens when this is not a git url + return Ok(ValidateCurrentInstall::Reinstall( + NeedReinstall::UrlMismatch { + installed_url: installed_git_url.url.to_string(), + locked_url: Some(locked_git_url.url.to_string()), + }, + )); + } + if vcs_info.commit_id + != locked_git_url.url.precise().map(|p| p.to_string()) + { + // The commit id is different, we need to reinstall return Ok(ValidateCurrentInstall::Reinstall( NeedReinstall::GitCommitsMismatch { installed_commit: vcs_info.commit_id.unwrap_or_default(), - locked_commit: git + locked_commit: locked_git_url .url .precise() .map(|p| p.to_string()) @@ -361,7 +449,11 @@ fn need_reinstall( Err(_) => { return Ok(ValidateCurrentInstall::Reinstall( NeedReinstall::UnableToParseGitUrl { - url: url.to_string(), + url: locked + .location + .as_url() + .map(|u| u.to_string()) + .unwrap_or_default(), }, )); } @@ -391,13 +483,16 @@ fn need_reinstall( }; // Do some extra checks if the version is the same - let metadata = if let Ok(metadata) = installed.metadata() { - metadata - } else { - // Can't be sure lets reinstall - return Ok(ValidateCurrentInstall::Reinstall( - NeedReinstall::UnableToGetInstalledDistMetadata, - )); + let metadata = match installed.metadata() { + Ok(metadata) => metadata, + Err(err) => { + // Can't be sure lets reinstall + return Ok(ValidateCurrentInstall::Reinstall( + NeedReinstall::UnableToGetInstalledDistMetadata { + cause: err.to_string(), + }, + )); + } }; if let Some(requires_python) = metadata.requires_python { @@ -405,7 +500,7 @@ fn need_reinstall( if !requires_python.contains(python_version) { return Ok(ValidateCurrentInstall::Reinstall( NeedReinstall::RequiredPythonChanged { - installed_python_version: requires_python, + installed_python_require: requires_python, locked_python_version: python_version.clone(), }, )); @@ -577,7 +672,12 @@ impl InstallPlanner { )); } else { // Check if we need to reinstall - match need_reinstall(dist, required_pkg, &self.python_version)? { + match need_reinstall( + dist, + required_pkg, + &self.python_version, + &self.lock_file_dir, + )? { ValidateCurrentInstall::Keep => { // No need to reinstall continue; diff --git a/src/install_pypi/plan/test/harness.rs b/src/install_pypi/plan/test/harness.rs new file mode 100644 index 000000000..e44180a61 --- /dev/null +++ b/src/install_pypi/plan/test/harness.rs @@ -0,0 +1,521 @@ +use crate::install_pypi::plan::{CachedDistProvider, InstallPlanner, InstalledDistProvider}; +use pixi_consts::consts; +use pixi_manifest::pypi::pypi_requirement::ParsedGitUrl; +use rattler_lock::{PypiPackageData, UrlOrPath}; +use std::collections::HashMap; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use tempfile::TempDir; +use typed_path::Utf8TypedPathBuf; +use url::Url; +use uv_distribution_filename::WheelFilename; +use uv_distribution_types::{InstalledDirectUrlDist, InstalledDist, InstalledRegistryDist}; +use uv_pypi_types::DirectUrl::VcsUrl; +use uv_pypi_types::{ArchiveInfo, DirectUrl, VcsInfo, VcsKind}; + +#[derive(Default)] +/// Builder to create installed dists +struct InstalledDistBuilder; + +impl InstalledDistBuilder { + pub fn registry>(name: S, version: S, path: PathBuf) -> InstalledDist { + let name = + uv_pep508::PackageName::new(name.as_ref().to_owned()).expect("unable to normalize"); + let version = + uv_pep440::Version::from_str(version.as_ref()).expect("cannot parse pep440 version"); + + let registry = InstalledRegistryDist { + name, + version, + path, + cache_info: None, + }; + InstalledDist::Registry(registry) + } + + pub fn directory>( + name: S, + version: S, + install_path: PathBuf, + source_path: PathBuf, + editable: bool, + ) -> (InstalledDist, DirectUrl) { + let name = + uv_pep508::PackageName::new(name.as_ref().to_owned()).expect("unable to normalize"); + let version = + uv_pep440::Version::from_str(version.as_ref()).expect("cannot parse pep440 version"); + let directory_url = Url::from_file_path(&source_path).unwrap(); + + let direct_url = DirectUrl::LocalDirectory { + url: directory_url.to_string(), + dir_info: uv_pypi_types::DirInfo { + editable: Some(editable), + }, + }; + + let installed_direct_url = InstalledDirectUrlDist { + name, + version, + direct_url: Box::new(direct_url.clone()), + url: directory_url, + editable, + path: install_path, + cache_info: None, + }; + (InstalledDist::Url(installed_direct_url), direct_url) + } + + pub fn archive>( + name: S, + version: S, + install_path: PathBuf, + url: Url, + ) -> (InstalledDist, DirectUrl) { + let name = + uv_pep508::PackageName::new(name.as_ref().to_owned()).expect("unable to normalize"); + let version = + uv_pep440::Version::from_str(version.as_ref()).expect("cannot parse pep440 version"); + + let direct_url = DirectUrl::ArchiveUrl { + url: url.to_string(), + archive_info: ArchiveInfo { + hashes: None, + hash: None, + }, + subdirectory: None, + }; + + let installed_direct_url = InstalledDirectUrlDist { + name, + version, + direct_url: Box::new(direct_url.clone()), + url, + editable: false, + path: install_path, + cache_info: None, + }; + (InstalledDist::Url(installed_direct_url), direct_url) + } + + pub fn git>( + name: S, + version: S, + install_path: PathBuf, + url: Url, + ) -> (InstalledDist, DirectUrl) { + let name = + uv_pep508::PackageName::new(name.as_ref().to_owned()).expect("unable to normalize"); + let version = + uv_pep440::Version::from_str(version.as_ref()).expect("cannot parse pep440 version"); + + // Parse git url and extract git commit, use this as the commit_id + let parsed_git_url = ParsedGitUrl::try_from(url.clone()).expect("should parse git url"); + + let direct_url = VcsUrl { + url: url.to_string(), + subdirectory: None, + vcs_info: VcsInfo { + vcs: VcsKind::Git, + commit_id: parsed_git_url.rev.map(|r| r.to_string()), + requested_revision: None, + }, + }; + + let installed_direct_url = InstalledDirectUrlDist { + name, + version, + direct_url: Box::new(direct_url.clone()), + url, + path: install_path, + editable: false, + cache_info: None, + }; + (InstalledDist::Url(installed_direct_url), direct_url) + } +} + +#[derive(Default)] +/// Some configuration options for the installed dist +pub struct InstalledDistOptions { + installer: Option, + requires_python: Option, + metadata_mtime: Option, +} + +impl InstalledDistOptions { + pub fn with_installer>(mut self, installer: S) -> Self { + self.installer = Some(installer.as_ref().to_owned()); + self + } + + pub fn with_requires_python>(mut self, requires_python: S) -> Self { + self.requires_python = + uv_pep440::VersionSpecifiers::from_str(requires_python.as_ref()).ok(); + self + } + + pub fn with_metadata_mtime(mut self, metadata_mtime: std::time::SystemTime) -> Self { + self.metadata_mtime = Some(metadata_mtime); + self + } + + pub fn installer(&self) -> &str { + self.installer + .as_deref() + .unwrap_or(consts::PIXI_UV_INSTALLER) + } + + pub fn requires_python(&self) -> Option<&uv_pep440::VersionSpecifiers> { + self.requires_python.as_ref() + } + + pub fn metadata_mtime(&self) -> Option { + self.metadata_mtime + } +} + +pub struct MockedSitePackages { + installed_dist: Vec, + /// This is the fake site packages directory, we need a file-backing for some of the + /// re-installation checks + fake_site_packages: TempDir, +} + +impl MockedSitePackages { + pub fn new() -> Self { + Self { + installed_dist: vec![], + fake_site_packages: tempfile::tempdir().expect("should create temp dir"), + } + } + + /// Create INSTALLER and METADATA files for the installed dist + /// these are checked for the installer and requires python + fn create_file_backing( + &self, + name: &str, + version: &str, + opts: InstalledDistOptions, + ) -> PathBuf { + // Create the dist-info directory + let dist_info = format!("{}-{}.dist-info", name, version); + let dist_info = self.fake_site_packages.path().join(dist_info); + fs_err::create_dir_all(&dist_info).expect("should create dist-info"); + + // Write the INSTALLER file + let installer = opts.installer(); + fs_err::write(dist_info.join("INSTALLER"), installer).expect("could not write INSTALLER"); + + // Write the METADATA file + let raw_metadata = "Name: {name}\nVersion: {version}\nSummary: A test package"; + let mut minimal_metadata = raw_metadata + .replace("{name}", name) + .replace("{version}", version); + if let Some(requires_python) = opts.requires_python() { + let requires_python = format!("\nRequires-Python: {}", requires_python); + minimal_metadata.push_str(&requires_python); + } + let mut file = std::fs::OpenOptions::new() + .write(true) + .read(true) + .create(true) + .truncate(true) + .open(dist_info.join("METADATA")) + .unwrap(); + file.write_all(minimal_metadata.as_bytes()) + .expect("should write metadata"); + + if let Some(metadata_mtime) = opts.metadata_mtime() { + file.set_modified(metadata_mtime) + .expect("should set modified time"); + file.sync_all().expect("should sync file"); + } + + dist_info + } + + /// Create a direct url for the installed dist + fn create_direct_url(&self, dist_info: &Path, direct_url: DirectUrl) { + let json = serde_json::to_string(&direct_url).expect("should serialize"); + let direct_url = dist_info.join("direct_url.json"); + fs_err::write(&direct_url, json).expect("should write direct url"); + } + + /// Add a registry installed dist to the site packages + pub fn add_registry>( + mut self, + name: S, + version: S, + opts: InstalledDistOptions, + ) -> Self { + let dist_info = self.create_file_backing(name.as_ref(), version.as_ref(), opts); + self.installed_dist + .push(InstalledDistBuilder::registry(name, version, dist_info)); + self + } + + /// Add a local directory that serves as an installed dist to the site-packages + pub fn add_directory>( + mut self, + name: S, + version: S, + source_path: PathBuf, + editable: bool, + opts: InstalledDistOptions, + ) -> Self { + let dist_info = self.create_file_backing(name.as_ref(), version.as_ref(), opts); + let (installed_dist, direct_url) = InstalledDistBuilder::directory( + name, + version, + dist_info.clone(), + source_path, + editable, + ); + self.create_direct_url(&dist_info, direct_url); + self.installed_dist.push(installed_dist); + self + } + + /// Add an archive installed dist to the site packages + pub fn add_archive>( + mut self, + name: S, + version: S, + url: Url, + opts: InstalledDistOptions, + ) -> Self { + let dist_info = self.create_file_backing(name.as_ref(), version.as_ref(), opts); + let (installed_dist, direct_url) = + InstalledDistBuilder::archive(name, version, dist_info.clone(), url); + self.create_direct_url(&dist_info, direct_url); + self.installed_dist.push(installed_dist); + self + } + + /// Add a git installed dist to the site packages + pub fn add_git>( + mut self, + name: S, + version: S, + url: Url, + opts: InstalledDistOptions, + ) -> Self { + let dist_info = self.create_file_backing(name.as_ref(), version.as_ref(), opts); + let (installed_dist, direct_url) = + InstalledDistBuilder::git(name, version, dist_info.clone(), url); + self.create_direct_url(&dist_info, direct_url); + self.installed_dist.push(installed_dist); + self + } +} + +impl<'a> InstalledDistProvider<'a> for MockedSitePackages { + fn iter(&'a self) -> impl Iterator { + self.installed_dist.iter() + } +} + +#[derive(Default)] +/// Builder to create pypi package data, this is essentially the locked data +struct PyPIPackageDataBuilder; + +impl PyPIPackageDataBuilder { + fn registry>(name: S, version: S) -> PypiPackageData { + PypiPackageData { + name: pep508_rs::PackageName::new(name.as_ref().to_owned()).unwrap(), + version: pep440_rs::Version::from_str(version.as_ref()).unwrap(), + // We dont check these fields, for determining the installation from a registry + // + requires_dist: vec![], + requires_python: None, + location: UrlOrPath::Url( + Url::parse(&format!( + "https://pypi.org/{name}-{version}-py3-none-any.whl", + name = name.as_ref(), + version = version.as_ref() + )) + .unwrap(), + ), + hash: None, + editable: false, + } + } + + fn directory>( + name: S, + version: S, + path: PathBuf, + editable: bool, + ) -> PypiPackageData { + PypiPackageData { + name: pep508_rs::PackageName::new(name.as_ref().to_owned()).unwrap(), + version: pep440_rs::Version::from_str(version.as_ref()).unwrap(), + requires_dist: vec![], + requires_python: None, + location: UrlOrPath::Path(Utf8TypedPathBuf::from(path.to_string_lossy().to_string())), + hash: None, + editable, + } + } + + fn direct_url>(name: S, version: S, url: Url) -> PypiPackageData { + // Create new url with direct+ in the scheme + let url = Url::parse(&format!("direct+{}", url)).unwrap(); + PypiPackageData { + name: pep508_rs::PackageName::new(name.as_ref().to_owned()).unwrap(), + version: pep440_rs::Version::from_str(version.as_ref()).unwrap(), + requires_dist: vec![], + requires_python: None, + location: UrlOrPath::Url(url), + hash: None, + editable: false, + } + } + + fn git>(name: S, version: S, url: Url) -> PypiPackageData { + PypiPackageData { + name: pep508_rs::PackageName::new(name.as_ref().to_owned()).unwrap(), + version: pep440_rs::Version::from_str(version.as_ref()).unwrap(), + requires_dist: vec![], + requires_python: None, + location: UrlOrPath::Url(url), + hash: None, + editable: false, + } + } +} + +/// Implementor of the [`CachedDistProvider`] that does not cache anything +pub struct NoCache; + +impl<'a> CachedDistProvider<'a> for NoCache { + fn get_cached_dist( + &mut self, + _name: &'a uv_normalize::PackageName, + _version: uv_pep440::Version, + ) -> Option { + None + } +} + +/// Implementor of the [`CachedDistProvider`] that assumes to have cached everything +pub struct AllCached; +impl<'a> CachedDistProvider<'a> for AllCached { + fn get_cached_dist( + &mut self, + name: &'a uv_normalize::PackageName, + version: uv_pep440::Version, + ) -> Option { + let wheel_filename = + WheelFilename::from_str(format!("{}-{}-py3-none-any.whl", name, version).as_str()) + .unwrap(); + let dist = uv_distribution_types::CachedRegistryDist { + filename: wheel_filename, + path: Default::default(), + hashes: vec![], + cache_info: Default::default(), + }; + Some(dist) + } +} + +/// Struct to create the required packages map +#[derive(Default)] +pub struct RequiredPackages { + required: HashMap, +} + +impl RequiredPackages { + pub fn new() -> Self { + Self::default() + } + + /// Add a registry package to the required packages + pub fn add_registry>(mut self, name: S, version: S) -> Self { + let package_name = + uv_normalize::PackageName::new(name.as_ref().to_owned()).expect("should be correct"); + let data = PyPIPackageDataBuilder::registry(name, version); + self.required.insert(package_name, data); + self + } + + /// Add a directory package to the required packages + pub fn add_directory>( + mut self, + name: S, + version: S, + path: PathBuf, + editable: bool, + ) -> Self { + let package_name = + uv_normalize::PackageName::new(name.as_ref().to_owned()).expect("should be correct"); + let data = PyPIPackageDataBuilder::directory(name, version, path, editable); + self.required.insert(package_name, data); + self + } + + pub fn add_archive>(mut self, name: S, version: S, url: Url) -> Self { + let package_name = + uv_normalize::PackageName::new(name.as_ref().to_owned()).expect("should be correct"); + let data = PyPIPackageDataBuilder::direct_url(name, version, url); + self.required.insert(package_name, data); + self + } + + pub fn add_git>(mut self, name: S, version: S, url: Url) -> Self { + let package_name = + uv_normalize::PackageName::new(name.as_ref().to_owned()).expect("should be correct"); + let data = PyPIPackageDataBuilder::git(name, version, url); + self.required.insert(package_name, data); + self + } + + /// Convert the required packages where it the data is borrowed + /// this is needed to pass it into the [`InstallPlanner`] + pub fn to_borrowed(&self) -> HashMap { + self.required.iter().map(|(k, v)| (k.clone(), v)).collect() + } +} + +/// Python version to use throughout the tests +pub const TEST_PYTHON_VERSION: &str = "3.12"; + +/// Some python version +fn python_version() -> uv_pep440::Version { + uv_pep440::Version::from_str(TEST_PYTHON_VERSION).unwrap() +} + +/// Simple function to create an install planner +pub fn install_planner() -> InstallPlanner { + InstallPlanner::new( + uv_cache::Cache::temp().unwrap(), + &python_version(), + PathBuf::new(), + ) +} + +/// Create a fake pyproject.toml file in a temp dir +/// return the temp dir +pub fn fake_pyproject_toml( + modification_time: Option, +) -> (TempDir, std::fs::File) { + let temp_dir = tempfile::tempdir().unwrap(); + let pyproject_toml = temp_dir.path().join("pyproject.toml"); + let mut pyproject_toml = std::fs::File::create(pyproject_toml).unwrap(); + pyproject_toml + .write_all( + r#" + [build-system] + requires = ["setuptools>=42"] + build-backend = "setuptools.build_meta" + "# + .as_bytes(), + ) + .unwrap(); + // Set the modification time if it is provided + if let Some(modification_time) = modification_time { + pyproject_toml.set_modified(modification_time).unwrap(); + } + (temp_dir, pyproject_toml) +} diff --git a/src/install_pypi/plan/test/mod.rs b/src/install_pypi/plan/test/mod.rs new file mode 100644 index 000000000..a6b48d43e --- /dev/null +++ b/src/install_pypi/plan/test/mod.rs @@ -0,0 +1,471 @@ +use self::harness::{InstalledDistOptions, MockedSitePackages, NoCache, RequiredPackages}; +use crate::install_pypi::plan::test::harness::{AllCached, TEST_PYTHON_VERSION}; +use crate::install_pypi::NeedReinstall; +use assert_matches::assert_matches; +use url::Url; + +mod harness; + +/// When no site-packages exist, and we have requested an uncached package +/// we expect an installation from the remote +#[test] +fn test_no_installed_require_one() { + // No installed packages + let site_packages = MockedSitePackages::new(); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + // We should install a single package + // from the remote because we do not cache + assert_eq!(install_plan.remote.len(), 1); +} + +/// Test that we can install a package from the cache when it is available +#[test] +fn test_no_installed_require_one_cached() { + // No installed packages + let site_packages = MockedSitePackages::new(); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, AllCached, &required.to_borrowed()) + .expect("should install"); + + // We should install a single package + // from the remote because we do not cache + assert!(install_plan.remote.is_empty()); + assert_eq!(install_plan.local.len(), 1); +} + +/// When we have a site-packages with the requested package, and the version matches we expect +/// no re-installation to occur +#[test] +fn test_install_required_equivalent() { + // No installed packages + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default(), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + // Should not install package + assert!( + install_plan.reinstalls.is_empty(), + "found reinstalls: {:?}", + install_plan.reinstalls + ); + assert!(install_plan.local.is_empty()); + assert!(install_plan.remote.is_empty()); +} + +/// When we have a site-packages with the requested package, and the version does not match we expect +/// a re-installation to occur, with a version mismatch indication +#[test] +fn test_install_required_mismatch() { + // No installed packages + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default(), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.7.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + // We should install a single package + // from the remote because we do not cache + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::VersionMismatch { ref installed_version, ref locked_version } + if installed_version.to_string() == "0.6.0" && locked_version.to_string() == "0.7.0" + ); + assert!(install_plan.local.is_empty()); + // Not cached we get it from the remote + assert_eq!(install_plan.remote.len(), 1); +} + +/// When we have a site-packages with the requested package, and the version does not match we expect +/// a re-installation to occur, with a version mismatch indication +#[test] +fn test_install_required_mismatch_cached() { + // No installed packages + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default(), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.7.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, AllCached, &required.to_borrowed()) + .expect("should install"); + + // We should install a single package + // from the remote because we do not cache + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::VersionMismatch { ref installed_version, ref locked_version } + if installed_version.to_string() == "0.6.0" && locked_version.to_string() == "0.7.0" + ); + assert!(install_plan.remote.is_empty()); + // Not cached we get it from the remote + assert_eq!(install_plan.local.len(), 1); +} + +/// When requiring a package that has a different INSTALLER but we *do require* it +/// we should reinstall it +#[test] +fn test_install_required_installer_mismatch() { + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default().with_installer("i-am-not-pixi"), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::InstallerMismatch { ref previous_installer } if previous_installer == "i-am-not-pixi" + ); + assert!(install_plan.local.is_empty()); + // Not cached we get it from the remote + assert_eq!(install_plan.remote.len(), 1); +} + +/// When having a package with a different INSTALLER, and we do not require it, we should leave it alone +/// and not reinstall it +#[test] +fn test_installed_one_other_installer() { + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default().with_installer("i-am-not-pixi"), + ); + // Nothing is required + let required = RequiredPackages::new(); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + // We should not do anything + assert!(install_plan.local.is_empty()); + assert!(install_plan.remote.is_empty()); +} + +/// When requiring a package that has a different required python then we have installed we want to reinstall +/// the package +#[test] +fn test_install_required_python_mismatch() { + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default().with_requires_python("<3.12"), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::RequiredPythonChanged { + ref installed_python_require, + ref locked_python_version + } if installed_python_require.to_string() == "<3.12" + && locked_python_version.to_string() == TEST_PYTHON_VERSION + ); + assert!(install_plan.local.is_empty()); + // Not cached we get it from the remote + assert_eq!(install_plan.remote.len(), 1); +} + +/// When no longer requiring a package that is installed we should uninstall it, +/// i.e. mark as extraneous +#[test] +fn test_installed_one_none_required() { + let site_packages = MockedSitePackages::new().add_registry( + "aiofiles", + "0.6.0", + InstalledDistOptions::default(), + ); + let required = RequiredPackages::new(); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + assert_eq!(install_plan.extraneous.len(), 1); +} + +/// When requiring a package from the registry that is currently installed as a directory +/// it should be re-installed +#[test] +fn test_installed_local_required_registry() { + let (temp_dir, _) = harness::fake_pyproject_toml(None); + let site_packages = MockedSitePackages::new().add_directory( + "aiofiles", + "0.6.0", + temp_dir.path().to_path_buf(), + false, + InstalledDistOptions::default(), + ); + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::UrlMismatch{ ref installed_url, ref locked_url } if *installed_url != locked_url.clone().unwrap() + ); +} + +/// When requiring a local package and that same local package is installed, we should not reinstall it +/// except if the pyproject.toml file, or some other source files we won't check here is newer than the cache +#[test] +fn test_installed_local_required_local() { + let ten_minutes_ago = std::time::SystemTime::now() - std::time::Duration::from_secs(60 * 10); + let (fake, _) = harness::fake_pyproject_toml(Some(ten_minutes_ago)); + let site_packages = MockedSitePackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + false, + InstalledDistOptions::default(), + ); + // Requires following package + let required = RequiredPackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + false, + ); + + // pyproject.toml file is older than the cache, all else is the same + // so we do not expect a re-installation + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_eq!( + install_plan.reinstalls.len(), + 0, + "found reinstall: {:?}", + install_plan.reinstalls + ); + assert!(install_plan.remote.is_empty()); + assert!(install_plan.local.is_empty()); +} +/// When requiring a local package and that same local package is installed, we should not reinstall it +/// except if the pyproject.toml file, or some other source files we won't check here is newer than the cache +#[test] +fn test_local_source_newer_than_local_metadata() { + let (fake, pyproject) = harness::fake_pyproject_toml(None); + let site_packages = MockedSitePackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + false, + // Set the metadata mtime to 1 day ago + InstalledDistOptions::default().with_metadata_mtime( + std::time::SystemTime::now() - std::time::Duration::from_secs(60 * 60 * 24), + ), + ); + // Requires following package + let required = RequiredPackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + false, + ); + // Set the pyproject.toml file to be newer than the installed metadata + // We need to do this otherwise the test seems to fail even though the file should be newer + pyproject + .set_modified(std::time::SystemTime::now() + std::time::Duration::from_secs(60 * 60 * 24)) + .unwrap(); + pyproject.sync_all().unwrap(); + + // pyproject.toml file is older than the cache, all else is the same + // so we do not expect a re-installation + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::SourceDirectoryNewerThanCache + ); +} + +/// When we have an editable package installed and we require a non-editable package +/// we should reinstall the non-editable package +#[test] +fn test_installed_editable_required_non_editable() { + let (fake, _) = harness::fake_pyproject_toml(None); + let site_packages = MockedSitePackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + true, + InstalledDistOptions::default(), + ); + + // Requires following package + let required = RequiredPackages::new().add_directory( + "aiofiles", + "0.6.0", + fake.path().to_path_buf(), + false, + ); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::EditableStatusChanged { + locked_editable: false, + installed_editable: true + } + ); +} + +/// When having a direct archive installed and we require the same version from the registry +/// we should reinstall +#[test] +fn test_installed_archive_require_registry() { + let remote_url = + Url::parse("https://some-other-registry.org/aiofiles-0.6.0-py3-none-any.whl").unwrap(); + let site_packages = MockedSitePackages::new().add_archive( + "aiofiles", + "0.6.0", + remote_url.clone(), + InstalledDistOptions::default(), + ); + + // Requires following package + let required = RequiredPackages::new().add_registry("aiofiles", "0.6.0"); + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::UrlMismatch { .. } + ); + + // If we have the correct archive installed it should not reinstall + let required = RequiredPackages::new().add_archive("aiofiles", "0.6.0", remote_url.clone()); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + assert!(install_plan.local.is_empty()); + assert!(install_plan.remote.is_empty()); +} + +/// When having a git installed, and we require the same version from the registry +/// we should reinstall, otherwise we should not +/// note that we are using full git commits here, because it seems from my (Tim) +/// testing that these are the ones used in the lock file +#[test] +fn test_installed_git_require_registry() { + let git_url = + Url::parse("git+https://github.com/pypa/pip.git@9d4f36d87dae9a968fb527e2cb87e8a507b0beb3") + .expect("could not parse git url"); + + let site_packages = MockedSitePackages::new().add_git( + "pip", + "1.0.0", + git_url.clone(), + InstalledDistOptions::default(), + ); + let required = RequiredPackages::new().add_registry("pip", "1.0.0"); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::UrlMismatch { .. } + ); + + // Okay now we require the same git package, it should not reinstall + let required = RequiredPackages::new().add_git("pip", "1.0.0", git_url.clone()); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + assert!( + install_plan.reinstalls.is_empty(), + "found reinstalls: {:?}", + install_plan.reinstalls + ); +} + +/// When the git commit differs we should reinstall +#[test] +fn test_installed_git_require_git_commit_mismatch() { + let installed = "9d4f36d87dae9a968fb527e2cb87e8a507b0beb3"; + let git_url = Url::parse(format!("git+https://github.com/pypa/pip.git@{installed}").as_str()) + .expect("could not parse git url"); + + let site_packages = MockedSitePackages::new().add_git( + "pip", + "1.0.0", + git_url.clone(), + InstalledDistOptions::default(), + ); + let locked = "cf20850e5e42ba9a71748fdf04193c7857cf5f61"; + let git_url_2 = Url::parse(format!("git+https://github.com/pypa/pip.git@{locked}").as_str()) + .expect("could not parse git url"); + let required = RequiredPackages::new().add_git("pip", "1.0.0", git_url_2); + + let plan = harness::install_planner(); + let install_plan = plan + .plan(&site_packages, NoCache, &required.to_borrowed()) + .expect("should install"); + + assert_matches!( + install_plan.reinstalls[0].1, + NeedReinstall::GitCommitsMismatch { ref installed_commit, ref locked_commit } + if installed == installed_commit && locked == locked_commit + ); +}